//------------------------------------------------------------------------------ // Copyright (c) 2001-2002, Haiku // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // // File Name: CurView.cpp // Author: DarkWyrm // Description: cursor handler for the app // //------------------------------------------------------------------------------ #include #include #include #include #include #include #include #include "CursorWhichItem.h" #include "CurView.h" #include #include "defs.h" #include "ServerConfig.h" #include #include #include #include //#define DEBUG_CURSORSET #define SAVE_CURSORSET 'svcu' #define DELETE_CURSORSET 'dlcu' #define LOAD_CURSORSET 'ldcu' #define CURSOR_UPDATED 'csru' CurView::CurView(const BRect &frame, const char *name, int32 resize, int32 flags) :BView(frame,name,resize,flags), settings(B_SIMPLE_DATA) { SetViewUIColor(B_PANEL_BACKGROUND_COLOR); cursorset=new CursorSet("Default"); /* // Code disabled -- cursor set management belongs in another app BMenuBar *mb=new BMenuBar(BRect(0,0,Bounds().Width(),16),"menubar"); settings_menu=new BMenu("Settings"); settings_menu->AddItem(new BMenuItem("Save Cursor Set",new BMessage(SAVE_CURSORSET),'S')); settings_menu->AddSeparatorItem(); settings_menu->AddItem(new BMenuItem("Delete Cursor Set",new BMessage(DELETE_CURSORSET))); mb->AddItem(settings_menu); cursorset_menu=LoadCursorSets(); if(cursorset_menu) mb->AddItem(cursorset_menu); else { // We should *never* be here, but just in case.... cursorset_menu=new BMenu("Cursor Sets"); mb->AddItem(cursorset_menu); } AddChild(mb); */ BRect wellrect(0,0,20,20); wellrect.OffsetTo(10,25); wellrect.right=wellrect.left+50; /* // Code disabled -- cursor set management belongs in another app cursorset_label=new BStringView(wellrect,"cursorset_label","Cursor Set: "); AddChild(cursorset_label); cursorset_label->ResizeToPreferred(); cursorset_name=""; */ // Set up list of cursor attributes BRect cvrect; BRect rect; cvrect.Set(0,0,75,75); bmpview=new BitmapView(BPoint(10,10),new BMessage(CURSOR_UPDATED),this); bmpview->MoveTo( (Bounds().Width()-bmpview->Bounds().Width())/2,30); AddChild(bmpview); rect.left=(Bounds().Width()-200)/2; rect.right=rect.left+190; rect.top=bmpview->Frame().bottom+30; rect.bottom=rect.top+100; attrlist=new BListView(rect,"AttributeList"); scrollview=new BScrollView("ScrollView",attrlist, B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true); AddChild(scrollview); scrollview->SetViewUIColor(B_PANEL_BACKGROUND_COLOR); attrlist->SetSelectionMessage(new BMessage(ATTRIBUTE_CHOSEN)); attrlist->AddItem(new CursorWhichItem(B_CURSOR_DEFAULT)); attrlist->AddItem(new CursorWhichItem(B_CURSOR_TEXT)); attrlist->AddItem(new CursorWhichItem(B_CURSOR_MOVE)); attrlist->AddItem(new CursorWhichItem(B_CURSOR_DRAG)); attrlist->AddItem(new CursorWhichItem(B_CURSOR_RESIZE)); attrlist->AddItem(new CursorWhichItem(B_CURSOR_RESIZE_NWSE)); attrlist->AddItem(new CursorWhichItem(B_CURSOR_RESIZE_NESW)); attrlist->AddItem(new CursorWhichItem(B_CURSOR_RESIZE_NS)); attrlist->AddItem(new CursorWhichItem(B_CURSOR_RESIZE_EW)); cvrect.Set(0,0,60,30); cvrect.OffsetTo( (Bounds().Width()-200)/2,scrollview->Frame().bottom+20); defaults=new BButton(cvrect,"DefaultsButton","Defaults", new BMessage(DEFAULT_SETTINGS),B_FOLLOW_LEFT |B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); AddChild(defaults); cvrect.OffsetBy(70,0); revert=new BButton(cvrect,"RevertButton","Revert", new BMessage(REVERT_SETTINGS),B_FOLLOW_LEFT |B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); AddChild(revert); revert->SetEnabled(false); cvrect.OffsetBy(70,0); apply=new BButton(cvrect,"ApplyButton","Apply", new BMessage(APPLY_SETTINGS),B_FOLLOW_LEFT |B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); AddChild(apply); apply->SetEnabled(false); BEntry entry(COLOR_SET_DIR); entry_ref ref; entry.GetRef(&ref); attribute=B_PANEL_BACKGROUND_COLOR; attrstring="Background"; LoadSettings(); } CurView::~CurView(void) { delete cursorset; } void CurView::AllAttached(void) { attrlist->Select(0); attrlist->SetTarget(this); apply->SetTarget(this); defaults->SetTarget(this); revert->SetTarget(this); bmpview->SetTarget(this); BMessenger msgr(this); } void CurView::MessageReceived(BMessage *msg) { if(msg->WasDropped()) { } switch(msg->what) { case CURSOR_UPDATED: { CursorWhichItem *cwi=(CursorWhichItem*)attrlist->ItemAt(attrlist->CurrentSelection()); if(cwi) cwi->SetBitmap(bmpview->GetBitmap()); break; } case ATTRIBUTE_CHOSEN: { CursorWhichItem *cwi=(CursorWhichItem*)attrlist->ItemAt(attrlist->CurrentSelection()); if(cwi) { bmpview->SetBitmap(cwi->GetBitmap()); bmpview->Invalidate(); } break; } default: BView::MessageReceived(msg); break; } } /* // Code disabled -- cursor set management belongs in another app BMenu *CurView::LoadCursorSets(void) { #ifdef DEBUG_CURSORSET printf("Loading cursor sets from disk\n"); #endif // This function populates the member menu *cursorset_menu with the cursor // set files located in the cursor set directory. To ensure that there are // no entries pointing to invalid cursor sets, they are validated before // a menu item is added. BDirectory dir; BEntry entry; BPath path; BString name; BMenu *menu=new BMenu("Cursor Sets"); status_t dirstat=dir.SetTo(COLOR_SET_DIR); if(dirstat!=B_OK) { // We couldn't set the directory, so more than likely it just // doesn't exist. Create it and return an empty menu. switch(dirstat) { case B_NAME_TOO_LONG: { BAlert *a=new BAlert("Haiku","Couldn't open the folder for cursor sets. " "You will be able to change system cursors, but be unable to save them to a cursor set. " "Please contact Haiku about Appearance Preferences::CurView::" "LoadCursorSets::B_NAME_TOO_LONG for a bugfix", "OK", NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); a->SetFlags(a->Flags() | B_CLOSE_ON_ESCAPE); a->Go(); break; } case B_ENTRY_NOT_FOUND: { create_directory(COLOR_SET_DIR,0777); break; } case B_BAD_VALUE: { printf("CurView::LoadCursorSets(): Invalid cursorset folder path.\n"); break; } case B_NO_MEMORY: { printf("CurView::LoadCursorSets(): No memory left. We're probably going to crash now. \n"); break; } case B_BUSY: { printf("CurView::LoadCursorSets(): Busy node " CURSOR_SET_DIR "\n"); break; } case B_FILE_ERROR: { BAlert *a=new BAlert("Haiku","Couldn't open the folder for cursor sets " "because of a file error. Perhaps there is a file (instead of a folder) at " COLOR_SET_DIR "? You will be able to change system cursors, but be unable to save them to a cursor set. ", "OK", NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); a->SetFlags(a->Flags() | B_CLOSE_ON_ESCAPE); a->Go(); break; } case B_NO_MORE_FDS: { BAlert *a=new BAlert("Haiku","Couldn't open the folder for cursor sets " "because there are too many open files. Please close some files and restart " " this application.", "OK", NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); a->SetFlags(a->Flags() | B_CLOSE_ON_ESCAPE); a->Go(); if(Window()) Window()->PostMessage(B_QUIT_REQUESTED); break; } } return menu; } int32 count=dir.CountEntries(); BMessage *msg; CursorSet cs(NULL); for(int32 i=0;iAddString("name",name); menu->AddItem(new BMenuItem(name.String(),msg)); } return menu; } void CurView::SetCursorSetName(const char *name) { if(!name) return; BString namestr("Cursor Set: "); cursorset_name=name; namestr+=name; cursorset_label->SetText(namestr.String()); cursorset_label->ResizeToPreferred(); cursorset_label->Invalidate(); } */ void CurView::SaveSettings(void) { // Save the current GUI cursor settings to the GUI cursors file in the // path specified in defs.h BString path(SERVER_SETTINGS_DIR); path+=CURSOR_SETTINGS_NAME; #ifdef DEBUG_CURSORSET printf("SaveSettings: %s\n",path.String()); #endif cursorset->Save(path.String(),B_CREATE_FILE|B_ERASE_FILE); // prev_set_name=cursorset_name; revert->SetEnabled(false); } void CurView::LoadSettings(void) { // Load the current GUI cursor settings from disk. This is done instead of // getting them from the server at this point for testing purposes. Comment // out the #define LOAD_SETTINGS_FROM_DISK line to use the server query code #ifdef DEBUG_CURSORSET printf("Loading settings from disk\n"); #endif settings.MakeEmpty(); BDirectory dir,newdir; if(dir.SetTo(SERVER_SETTINGS_DIR)==B_ENTRY_NOT_FOUND) { #ifdef DEBUG_CURSORSET printf("Cursor set folder not found. Creating %s\n",SERVER_SETTINGS_DIR); #endif create_directory(SERVER_SETTINGS_DIR,0777); } BString path(SERVER_SETTINGS_DIR); path+=CURSOR_SETTINGS_NAME; status_t stat=cursorset->Load(path.String()); if(stat!=B_OK) { #ifdef DEBUG_CURSORSET printf("Couldn't open file %s for read\n",path.String()); #endif SetDefaults(); SaveSettings(); } return; } void CurView::SetDefaults(void) { // The server will perform the necessary work to set defaults, so just ask it to do the // work for us. It is a synchronous procedure, so we will notify the server and load the cursor // set 'Default'. BString string(CURSOR_SET_DIR); string+="Default"; cursorset->Load(string.String()); port_id port=find_port(SERVER_PORT_NAME); if(port==B_NAME_NOT_FOUND) return; BPrivate::PortLink link(port); int32 code; link.StartMessage(AS_SET_SYSCURSOR_DEFAULTS); link.Flush(); link.GetNextMessage(code); } BitmapView::BitmapView(const BPoint &pt,BMessage *message, const BHandler *handler, const BLooper *looper=NULL) : BBox(BRect(0,0,75,75).OffsetToCopy(pt),"bitmapview",B_FOLLOW_NONE,B_WILL_DRAW, B_PLAIN_BORDER), BInvoker(message,handler,looper) { SetFont(be_plain_font); bitmap=NULL; SetViewUIColor(B_PANEL_BACKGROUND_COLOR); SetDrawingMode(B_OP_ALPHA); drawrect=Bounds().InsetByCopy(5,5); } BitmapView::~BitmapView(void) { } void BitmapView::SetBitmap(BBitmap *bmp) { bitmap=bmp; } void BitmapView::Draw(BRect r) { BBox::Draw(r); if(bitmap) DrawBitmap(bitmap, drawrect); } void BitmapView::MessageReceived(BMessage *msg) { if(msg->WasDropped()) { entry_ref ref; if(msg->FindRef("refs",&ref)!=B_OK) return; BBitmap *tmp=BTranslationUtils::GetBitmap(&ref); if(tmp) { delete bitmap; bitmap=tmp; int32 offset; BRect r(Bounds()); r.right-=10; r.bottom-=10; drawrect=bitmap->Bounds(); if(r.Contains(bitmap->Bounds())) { // calculate a centered rect for direct display offset=((r.IntegerWidth()-bitmap->Bounds().IntegerWidth()) >> 1)+5; drawrect.OffsetBy(offset,offset); } else { // calculate a scaled-down rectangle for display drawrect.left=drawrect.top=0; if(bitmap->Bounds().Height() > bitmap->Bounds().Width()) { drawrect.right=(r.Height()*bitmap->Bounds().Width())/bitmap->Bounds().Height(); drawrect.bottom=r.Height(); offset=((r.IntegerWidth()-drawrect.IntegerWidth()) >> 1)+5; drawrect.OffsetBy(offset,5); } else { drawrect.bottom=(r.Width()*bitmap->Bounds().Height())/bitmap->Bounds().Width(); drawrect.right=r.Width(); offset=((r.IntegerHeight()-drawrect.IntegerHeight()) >> 1)+5; drawrect.OffsetBy(5,offset); } } Invoke(); Invalidate(); return; } } else BBox::MessageReceived(msg); }