1 /* 2 * Copyright 2002-2005, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Jerome Duval (jerome.duval@free.fr) 7 * Axel Dörfler, axeld@pinc-software.de 8 */ 9 10 11 #include "BackgroundsView.h" 12 #include "ImageFilePanel.h" 13 14 #include <OS.h> 15 #include <MenuField.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <StorageKit.h> 19 #include <Background.h> 20 #include <Window.h> 21 #include <Messenger.h> 22 #include <Bitmap.h> 23 #include <Point.h> 24 #include <TranslationKit.h> 25 #include <PopUpMenu.h> 26 27 28 static const uint32 kMsgApplySettings = 'aply'; 29 static const uint32 kMsgRevertSettings = 'rvrt'; 30 31 static const uint32 kMsgUpdateColor = 'upcl'; 32 static const uint32 kMsgAllWorkspaces = 'alwk'; 33 static const uint32 kMsgCurrentWorkspace = 'crwk'; 34 static const uint32 kMsgDefaultFolder = 'dffl'; 35 static const uint32 kMsgOtherFolder = 'otfl'; 36 static const uint32 kMsgNoImage = 'noim'; 37 static const uint32 kMsgOtherImage = 'otim'; 38 static const uint32 kMsgImageSelected = 'imsl'; 39 static const uint32 kMsgFolderSelected = 'flsl'; 40 41 static const uint32 kMsgCenterPlacement = 'cnpl'; 42 static const uint32 kMsgManualPlacement = 'mnpl'; 43 static const uint32 kMsgScalePlacement = 'scpl'; 44 static const uint32 kMsgTilePlacement = 'tlpl'; 45 static const uint32 kMsgIconLabelBackground = 'ilcb'; 46 47 static const uint32 kMsgImagePlacement = 'xypl'; 48 static const uint32 kMsgUpdatePreviewPlacement = 'pvpl'; 49 50 51 const uint8 kHandCursorData[68] = { 52 16, 1, 2, 2, 53 54 0,0, // 0000000000000000 55 7,128, // 0000011110000000 56 61,112, // 0011110101110000 57 37,40, // 0010010100101000 58 36,168, // 0010010010101000 59 18,148, // 0001001010010100 60 18,84, // 0001001001010100 61 9,42, // 0000100100101010 62 8,1, // 0000100000000001 63 60,1, // 0011110000000001 64 76,1, // 0100110000000001 65 66,1, // 0100001000000001 66 48,1, // 0011000000000001 67 12,1, // 0000110000000001 68 2,0, // 0000001000000000 69 1,0, // 0000000100000000 70 71 0,0, // 0000000000000000 72 7,128, // 0000011110000000 73 63,240, // 0011111111110000 74 63,248, // 0011111111111000 75 63,248, // 0011111111111000 76 31,252, // 0001111111111100 77 31,252, // 0001111111111100 78 15,254, // 0000111111111110 79 15,255, // 0000111111111111 80 63,255, // 0011111111111111 81 127,255, // 0111111111111111 82 127,255, // 0111111111111111 83 63,255, // 0011111111111111 84 15,255, // 0000111111111111 85 3,254, // 0000001111111110 86 1,248 // 0000000111111000 87 }; 88 89 90 BackgroundsView::BackgroundsView(BRect frame, const char *name, int32 resize, 91 int32 flags) 92 : BBox(frame, name, resize, 93 flags | B_WILL_DRAW | B_FRAME_EVENTS, B_NO_BORDER), 94 fCurrent(NULL), 95 fCurrentInfo(NULL), 96 fLastImageIndex(-1), 97 fPathList(1, true), 98 fImageList(1, true) 99 { 100 // we need the "Current Workspace" first to get its height 101 102 BMenuItem *menuItem; 103 fWorkspaceMenu = new BPopUpMenu("pick one"); 104 fWorkspaceMenu->AddItem(menuItem = new BMenuItem("All Workspaces", 105 new BMessage(kMsgAllWorkspaces))); 106 fWorkspaceMenu->AddItem(menuItem = new BMenuItem("Current Workspace", 107 new BMessage(kMsgCurrentWorkspace))); 108 menuItem->SetMarked(true); 109 fLastWorkspaceIndex = fWorkspaceMenu->IndexOf(fWorkspaceMenu->FindMarked()); 110 fWorkspaceMenu->AddSeparatorItem(); 111 fWorkspaceMenu->AddItem(menuItem = new BMenuItem("Default folder", 112 new BMessage(kMsgDefaultFolder))); 113 fWorkspaceMenu->AddItem(menuItem = new BMenuItem("Other folder" B_UTF8_ELLIPSIS, 114 new BMessage(kMsgOtherFolder))); 115 116 BMenuField *workspaceMenuField = new BMenuField(BRect(0, 0, 130, 18), 117 "workspaceMenuField", NULL, fWorkspaceMenu, true); 118 workspaceMenuField->ResizeToPreferred(); 119 120 /* the preview box */ 121 122 BFont font(be_plain_font); 123 font_height fontHeight; 124 font.GetHeight(&fontHeight); 125 126 fPreview = new PreviewBox(BRect(10, 8.0 + workspaceMenuField->Bounds().Height() / 2.0f 127 - ceilf(fontHeight.ascent + fontHeight.descent) / 2.0f, 160, 180), "preview"); 128 fPreview->SetFont(&font); 129 fPreview->SetLabel("Preview"); 130 AddChild(fPreview); 131 132 BRect rect(10, fPreview->Bounds().bottom - 30, 70, fPreview->Bounds().bottom - 10); 133 fXPlacementText = new BTextControl(rect, "xPlacementText", "X:", NULL, 134 new BMessage(kMsgImagePlacement), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); 135 fXPlacementText->SetDivider(fXPlacementText->StringWidth(fXPlacementText->Label()) + 4.0f); 136 fXPlacementText->TextView()->SetMaxBytes(5); 137 float width, height; 138 fXPlacementText->GetPreferredSize(&width, &height); 139 float delta = fXPlacementText->Bounds().Height() - height; 140 fXPlacementText->MoveBy(0, delta); 141 fXPlacementText->ResizeTo(fXPlacementText->Bounds().Width(), height); 142 fPreview->AddChild(fXPlacementText); 143 144 rect.OffsetBy(70, delta); 145 fYPlacementText = new BTextControl(rect, "yPlacementText", "Y:", NULL, 146 new BMessage(kMsgImagePlacement), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); 147 fYPlacementText->SetDivider(fYPlacementText->StringWidth(fYPlacementText->Label()) + 4.0f); 148 fYPlacementText->TextView()->SetMaxBytes(5); 149 fXPlacementText->ResizeTo(fYPlacementText->Bounds().Width(), height); 150 fPreview->AddChild(fYPlacementText); 151 152 for (int32 i = 0; i < 256; i++) { 153 if ((i < '0' || i > '9') && i != '-') { 154 fXPlacementText->TextView()->DisallowChar(i); 155 fYPlacementText->TextView()->DisallowChar(i); 156 } 157 } 158 159 fPreView = new PreView(BRect(15, 25, 135, 115), "preView", 160 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_SUBPIXEL_PRECISE); 161 fPreview->AddChild(fPreView); 162 163 /* the right box */ 164 165 BBox *rightbox = new BBox(BRect(fPreview->Frame().right + 10, 166 7, Frame().right - 10, fPreview->Frame().bottom), 167 "rightbox"); 168 rightbox->SetLabel(workspaceMenuField); 169 AddChild(rightbox); 170 171 fPicker = new BColorControl(BPoint(10, 110), B_CELLS_32x8, 5.0, "Picker", 172 new BMessage(kMsgUpdateColor)); 173 rightbox->AddChild(fPicker); 174 175 delta = fPicker->Frame().bottom + 10.0f - rightbox->Bounds().Height(); 176 rightbox->ResizeBy(0, delta); 177 fPreview->ResizeBy(0, delta); 178 179 // we're not yet attached to a view, so we need to move them manually 180 fXPlacementText->MoveBy(0, delta); 181 fYPlacementText->MoveBy(0, delta); 182 183 float offset = be_plain_font->StringWidth("Placement:") + 5; 184 rect.Set(offset + 10, 76, 280, 96); 185 186 fIconLabelBackground = new BCheckBox(rect, "iconLabelBackground", 187 "Icon label background", new BMessage(kMsgIconLabelBackground)); 188 fIconLabelBackground->SetValue(B_CONTROL_ON); 189 rightbox->AddChild(fIconLabelBackground); 190 191 fImageMenu = new BPopUpMenu("pick one"); 192 fImageMenu->AddItem(new BGImageMenuItem("None", -1, new BMessage(kMsgNoImage))); 193 fImageMenu->AddSeparatorItem(); 194 fImageMenu->AddItem(new BMenuItem("Other" B_UTF8_ELLIPSIS, new BMessage(kMsgOtherImage))); 195 196 fPlacementMenu = new BPopUpMenu("pick one"); 197 fPlacementMenu->AddItem(new BMenuItem("Manual", 198 new BMessage(kMsgManualPlacement))); 199 fPlacementMenu->AddItem(new BMenuItem("Center", 200 new BMessage(kMsgCenterPlacement))); 201 fPlacementMenu->AddItem(new BMenuItem("Scale to fit", 202 new BMessage(kMsgScalePlacement))); 203 fPlacementMenu->AddItem(new BMenuItem("Tile", 204 new BMessage(kMsgTilePlacement))); 205 206 rect.OffsetBy(-offset, -25); 207 BMenuField *placementMenuField = new BMenuField(rect, "placementMenuField", 208 "Placement:", fPlacementMenu); 209 placementMenuField->SetDivider(offset); 210 placementMenuField->SetAlignment(B_ALIGN_RIGHT); 211 rightbox->AddChild(placementMenuField); 212 213 rect.OffsetBy(0, -25); 214 rect.right += 40; 215 BMenuField *imageMenuField = new BMenuField(rect, "imageMenuField", 216 "Image:", fImageMenu); 217 imageMenuField->SetDivider(offset); 218 imageMenuField->SetAlignment(B_ALIGN_RIGHT); 219 rightbox->AddChild(imageMenuField); 220 221 fRevert = new BButton(BRect(fPreview->Frame().left, fPreview->Frame().bottom + 10, 222 fPreview->Frame().left + 80, Frame().bottom - 10), "RevertButton", 223 "Revert", new BMessage(kMsgRevertSettings), B_FOLLOW_LEFT | B_FOLLOW_TOP, 224 B_WILL_DRAW | B_NAVIGABLE); 225 AddChild(fRevert); 226 227 fApply = new BButton(BRect(rightbox->Frame().right - 70, fPreview->Frame().bottom 228 + 10, rightbox->Frame().right, 110), "ApplyButton", "Apply", 229 new BMessage(kMsgApplySettings), B_FOLLOW_LEFT | B_FOLLOW_TOP, 230 B_WILL_DRAW | B_NAVIGABLE); 231 AddChild(fApply); 232 233 ResizeBy(0, delta); 234 } 235 236 237 BackgroundsView::~BackgroundsView() 238 { 239 delete fPanel; 240 delete fFolderPanel; 241 } 242 243 244 void 245 BackgroundsView::AllAttached() 246 { 247 fPlacementMenu->SetTargetForItems(this); 248 fImageMenu->SetTargetForItems(this); 249 fWorkspaceMenu->SetTargetForItems(this); 250 fXPlacementText->SetTarget(this); 251 fYPlacementText->SetTarget(this); 252 fIconLabelBackground->SetTarget(this); 253 fPicker->SetTarget(this); 254 fApply->SetTarget(this); 255 fRevert->SetTarget(this); 256 257 fPanel = new ImageFilePanel(B_OPEN_PANEL, new BMessenger(this), NULL, 258 B_FILE_NODE, false, NULL, new CustomRefFilter(true)); 259 fPanel->SetButtonLabel(B_DEFAULT_BUTTON, "Select"); 260 261 fFolderPanel = new BFilePanel(B_OPEN_PANEL, new BMessenger(this), NULL, 262 B_DIRECTORY_NODE, false, NULL, new CustomRefFilter(false)); 263 fFolderPanel->SetButtonLabel(B_DEFAULT_BUTTON, "Select"); 264 265 Window()->ResizeTo(Frame().Width(), Frame().Height()); 266 267 LoadSettings(); 268 LoadDesktopFolder(); 269 } 270 271 272 void 273 BackgroundsView::MessageReceived(BMessage *msg) 274 { 275 switch (msg->what) { 276 case B_SIMPLE_DATA: 277 case B_REFS_RECEIVED: 278 RefsReceived(msg); 279 break; 280 281 case kMsgUpdatePreviewPlacement: 282 { 283 BString xstring, ystring; 284 xstring << (int)fPreView->fPoint.x; 285 ystring << (int)fPreView->fPoint.y; 286 fXPlacementText->SetText(xstring.String()); 287 fYPlacementText->SetText(ystring.String()); 288 UpdatePreview(); 289 UpdateButtons(); 290 break; 291 } 292 293 case kMsgManualPlacement: 294 UpdatePreview(); 295 UpdateButtons(); 296 break; 297 298 case kMsgTilePlacement: 299 case kMsgScalePlacement: 300 case kMsgCenterPlacement: 301 UpdatePreview(); 302 UpdateButtons(); 303 break; 304 305 case kMsgIconLabelBackground: 306 UpdateButtons(); 307 break; 308 309 case kMsgUpdateColor: 310 case kMsgImagePlacement: 311 UpdatePreview(); 312 UpdateButtons(); 313 break; 314 315 case kMsgCurrentWorkspace: 316 case kMsgAllWorkspaces: 317 fImageMenu->FindItem(kMsgNoImage)->SetLabel("None"); 318 fLastWorkspaceIndex = fWorkspaceMenu->IndexOf( 319 fWorkspaceMenu->FindMarked()); 320 if (!fCurrent->IsDesktop()) { 321 fPreview->SetDesktop(true); 322 LoadDesktopFolder(); 323 } else 324 UpdateButtons(); 325 break; 326 327 case kMsgDefaultFolder: 328 fImageMenu->FindItem(kMsgNoImage)->SetLabel("None"); 329 fLastWorkspaceIndex = fWorkspaceMenu->IndexOf( 330 fWorkspaceMenu->FindMarked()); 331 fPreview->SetDesktop(false); 332 LoadDefaultFolder(); 333 break; 334 335 case kMsgOtherFolder: 336 fFolderPanel->Show(); 337 break; 338 339 case kMsgOtherImage: 340 fPanel->Show(); 341 break; 342 343 case B_CANCEL: 344 { 345 PRINT(("cancel received\n")); 346 void* pointer; 347 msg->FindPointer("source", &pointer); 348 if (pointer == fPanel) { 349 if (fLastImageIndex >= 0) 350 FindImageItem(fLastImageIndex)->SetMarked(true); 351 else 352 fImageMenu->ItemAt(0)->SetMarked(true); 353 } else if (pointer == fFolderPanel) { 354 if (fLastWorkspaceIndex >= 0) 355 fWorkspaceMenu->ItemAt(fLastWorkspaceIndex)->SetMarked(true); 356 } 357 break; 358 } 359 360 case kMsgImageSelected: 361 case kMsgNoImage: 362 fLastImageIndex = ((BGImageMenuItem*)fImageMenu->FindMarked())->ImageIndex(); 363 UpdatePreview(); 364 UpdateButtons(); 365 break; 366 367 case kMsgFolderSelected: 368 fImageMenu->FindItem(kMsgNoImage)->SetLabel("Default"); 369 fLastWorkspaceIndex = fWorkspaceMenu->IndexOf( 370 fWorkspaceMenu->FindMarked()); 371 fPreview->SetDesktop(false); 372 LoadRecentFolder(*fPathList.ItemAt(fWorkspaceMenu->IndexOf( 373 fWorkspaceMenu->FindMarked()) - 6)); 374 break; 375 376 case kMsgApplySettings: 377 { 378 Save(); 379 380 //NotifyServer(); 381 thread_id notify_thread; 382 notify_thread = spawn_thread(BackgroundsView::NotifyThread, "notifyServer", 383 B_NORMAL_PRIORITY, this); 384 resume_thread(notify_thread); 385 UpdateButtons(); 386 break; 387 } 388 case kMsgRevertSettings: 389 UpdateWithCurrent(); 390 break; 391 392 default: 393 BView::MessageReceived(msg); 394 break; 395 } 396 } 397 398 399 void 400 BackgroundsView::LoadDesktopFolder() 401 { 402 BPath path; 403 if (find_directory(B_DESKTOP_DIRECTORY, &path) == B_OK) { 404 status_t err; 405 err = get_ref_for_path(path.Path(), &fCurrentRef); 406 if (err != B_OK) 407 printf("error in LoadDesktopSettings\n"); 408 LoadFolder(true); 409 } 410 } 411 412 413 void 414 BackgroundsView::LoadDefaultFolder() 415 { 416 BPath path; 417 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) { 418 BString pathString = path.Path(); 419 pathString << "/Tracker/DefaultFolderTemplate"; 420 status_t err; 421 err = get_ref_for_path(pathString.String(), &fCurrentRef); 422 if (err != B_OK) 423 printf("error in LoadDefaultFolderSettings\n"); 424 LoadFolder(false); 425 } 426 } 427 428 429 void 430 BackgroundsView::LoadRecentFolder(BPath path) 431 { 432 status_t err; 433 err = get_ref_for_path(path.Path(), &fCurrentRef); 434 if (err != B_OK) 435 printf("error in LoadRecentFolder\n"); 436 LoadFolder(false); 437 } 438 439 440 void 441 BackgroundsView::LoadFolder(bool isDesktop) 442 { 443 if (fCurrent) { 444 delete fCurrent; 445 fCurrent = NULL; 446 } 447 448 BNode node(&fCurrentRef); 449 if (node.InitCheck() == B_OK) 450 fCurrent = BackgroundImage::GetBackgroundImage(&node, isDesktop, this); 451 452 UpdateWithCurrent(); 453 } 454 455 456 void 457 BackgroundsView::UpdateWithCurrent(void) 458 { 459 if (fCurrent == NULL) 460 return; 461 462 fPlacementMenu->FindItem(kMsgScalePlacement)->SetEnabled(fCurrent->IsDesktop()); 463 fPlacementMenu->FindItem(kMsgCenterPlacement)->SetEnabled(fCurrent->IsDesktop()); 464 465 if (fWorkspaceMenu->IndexOf(fWorkspaceMenu->FindMarked()) > 5) 466 fImageMenu->FindItem(kMsgNoImage)->SetLabel("Default"); 467 else 468 fImageMenu->FindItem(kMsgNoImage)->SetLabel("None"); 469 470 for (int32 i = fImageMenu->CountItems() - 5; i >= 0; i--) { 471 fImageMenu->RemoveItem(2); 472 } 473 474 for (int32 i = fImageList.CountItems() - 1; i >= 0; i--) { 475 BMessage *message = new BMessage(kMsgImageSelected); 476 AddItem(new BGImageMenuItem(GetImage(i)->GetName(), i, message)); 477 } 478 479 fImageMenu->SetTargetForItems(this); 480 481 fCurrentInfo = fCurrent->ImageInfoForWorkspace(current_workspace()); 482 483 if (!fCurrentInfo) { 484 fImageMenu->FindItem(kMsgNoImage)->SetMarked(true); 485 fPlacementMenu->FindItem(kMsgManualPlacement)->SetMarked(true); 486 } else { 487 fIconLabelBackground->SetValue(fCurrentInfo->fEraseTextWidgetBackground 488 ? B_CONTROL_ON : B_CONTROL_OFF); 489 490 BString xtext, ytext; 491 int32 cmd = 0; 492 switch (fCurrentInfo->fMode) { 493 case BackgroundImage::kCentered: 494 cmd = kMsgCenterPlacement; 495 break; 496 case BackgroundImage::kScaledToFit: 497 cmd = kMsgScalePlacement; 498 break; 499 case BackgroundImage::kAtOffset: 500 cmd = kMsgManualPlacement; 501 xtext << (int)fCurrentInfo->fOffset.x; 502 ytext << (int)fCurrentInfo->fOffset.y; 503 break; 504 case BackgroundImage::kTiled: 505 cmd = kMsgTilePlacement; 506 break; 507 } 508 509 if (cmd != 0) 510 fPlacementMenu->FindItem(cmd)->SetMarked(true); 511 512 fXPlacementText->SetText(xtext.String()); 513 fYPlacementText->SetText(ytext.String()); 514 515 fLastImageIndex = fCurrentInfo->fImageIndex; 516 FindImageItem(fLastImageIndex)->SetMarked(true); 517 } 518 519 rgb_color color = {255, 255, 255, 255}; 520 if (fCurrent->IsDesktop()) { 521 color = BScreen().DesktopColor(); 522 fPicker->SetEnabled(true); 523 } else 524 fPicker->SetEnabled(false); 525 526 fPicker->SetValue(color); 527 528 UpdatePreview(); 529 UpdateButtons(); 530 } 531 532 533 void 534 BackgroundsView::Save() 535 { 536 bool eraseTextWidgetBackground = 537 fIconLabelBackground->Value() == B_CONTROL_ON; 538 BackgroundImage::Mode mode = FindPlacementMode(); 539 BPoint offset(atoi(fXPlacementText->Text()), atoi(fYPlacementText->Text())); 540 541 if (!fCurrent->IsDesktop()) { 542 if (fCurrentInfo == NULL) { 543 fCurrentInfo = new BackgroundImage::BackgroundImageInfo(B_ALL_WORKSPACES, 544 fLastImageIndex, mode, offset, eraseTextWidgetBackground, 0, 0); 545 fCurrent->Add(fCurrentInfo); 546 } else { 547 fCurrentInfo->fEraseTextWidgetBackground = eraseTextWidgetBackground; 548 fCurrentInfo->fMode = mode; 549 if (fCurrentInfo->fMode == BackgroundImage::kAtOffset) 550 fCurrentInfo->fOffset = offset; 551 fCurrentInfo->fImageIndex = fLastImageIndex; 552 } 553 } else { 554 uint32 workspaceMask = 1; 555 int32 workspace = current_workspace(); 556 for (; workspace; workspace--) 557 workspaceMask *= 2; 558 559 if (fCurrentInfo != NULL) { 560 if (fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()) { 561 if (fCurrentInfo->fWorkspace != workspaceMask) { 562 fCurrentInfo->fWorkspace = fCurrentInfo->fWorkspace 563 ^ workspaceMask; 564 if (fLastImageIndex > -1) { 565 fCurrentInfo = new BackgroundImage::BackgroundImageInfo( 566 workspaceMask, fLastImageIndex, mode, offset, 567 eraseTextWidgetBackground, fCurrentInfo->fImageSet, 568 fCurrentInfo->fCacheMode); 569 fCurrent->Add(fCurrentInfo); 570 } 571 } else { 572 if (fLastImageIndex > -1) { 573 fCurrentInfo->fEraseTextWidgetBackground = 574 eraseTextWidgetBackground; 575 fCurrentInfo->fMode = mode; 576 if (fCurrentInfo->fMode == BackgroundImage::kAtOffset) 577 fCurrentInfo->fOffset = offset; 578 579 fCurrentInfo->fImageIndex = fLastImageIndex; 580 } else { 581 fCurrent->Remove(fCurrentInfo); 582 fCurrentInfo = NULL; 583 } 584 } 585 } else if (fLastImageIndex > -1) { 586 fCurrent->RemoveAll(); 587 fCurrentInfo = new BackgroundImage::BackgroundImageInfo( 588 B_ALL_WORKSPACES, fLastImageIndex, mode, offset, 589 eraseTextWidgetBackground, fCurrent->GetShowingImageSet(), 590 fCurrentInfo->fCacheMode); 591 fCurrent->Add(fCurrentInfo); 592 } 593 } else if (fLastImageIndex > -1) { 594 if (fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()) { 595 fCurrentInfo = new BackgroundImage::BackgroundImageInfo( 596 workspaceMask, fLastImageIndex, mode, offset, 597 eraseTextWidgetBackground, fCurrent->GetShowingImageSet(), 0); 598 } else { 599 fCurrent->RemoveAll(); 600 fCurrentInfo = new BackgroundImage::BackgroundImageInfo( 601 B_ALL_WORKSPACES, fLastImageIndex, mode, offset, 602 eraseTextWidgetBackground, fCurrent->GetShowingImageSet(), 0); 603 } 604 fCurrent->Add(fCurrentInfo); 605 } 606 607 if (!fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()) { 608 for (int32 i = 0; i < count_workspaces(); i++) { 609 BScreen().SetDesktopColor(fPicker->ValueAsColor(), i, true); 610 } 611 } else 612 BScreen().SetDesktopColor(fPicker->ValueAsColor(), true); 613 } 614 615 BNode node(&fCurrentRef); 616 617 status_t status = fCurrent->SetBackgroundImage(&node); 618 if (status != B_OK) { 619 // TODO: this should be a BAlert! 620 printf("setting background image failed: %s\n", strerror(status)); 621 } 622 } 623 624 625 void 626 BackgroundsView::NotifyServer() 627 { 628 BMessenger tracker("application/x-vnd.Be-TRAK"); 629 630 if (fCurrent->IsDesktop()) { 631 tracker.SendMessage(new BMessage(B_RESTORE_BACKGROUND_IMAGE)); 632 } else { 633 int32 i = -1; 634 BMessage reply; 635 int32 err; 636 BEntry currentEntry(&fCurrentRef); 637 BPath currentPath(¤tEntry); 638 bool isCustomFolder = !fWorkspaceMenu->FindItem(kMsgDefaultFolder)->IsMarked(); 639 640 do { 641 BMessage msg(B_GET_PROPERTY); 642 i++; 643 644 // look at the "Poses" in every Tracker window 645 msg.AddSpecifier("Poses"); 646 msg.AddSpecifier("Window", i); 647 648 reply.MakeEmpty(); 649 tracker.SendMessage(&msg, &reply); 650 651 // break out of the loop when we're at the end of 652 // the windows 653 if (reply.what == B_MESSAGE_NOT_UNDERSTOOD 654 && reply.FindInt32("error", &err) == B_OK 655 && err == B_BAD_INDEX) 656 break; 657 658 // don't stop for windows that don't understand 659 // a request for "Poses"; they're not displaying 660 // folders 661 if (reply.what == B_MESSAGE_NOT_UNDERSTOOD 662 && reply.FindInt32("error", &err) == B_OK 663 && err != B_BAD_SCRIPT_SYNTAX) 664 continue; 665 666 BMessenger trackerWindow; 667 if (reply.FindMessenger("result", &trackerWindow) != B_OK) 668 continue; 669 670 if (isCustomFolder) { 671 // found a window with poses, ask for its path 672 msg.MakeEmpty(); 673 msg.what = B_GET_PROPERTY; 674 msg.AddSpecifier("Path"); 675 msg.AddSpecifier("Poses"); 676 msg.AddSpecifier("Window", i); 677 678 reply.MakeEmpty(); 679 tracker.SendMessage(&msg, &reply); 680 681 // go on with the next if this din't have a path 682 if (reply.what == B_MESSAGE_NOT_UNDERSTOOD) 683 continue; 684 685 entry_ref ref; 686 if (reply.FindRef("result", &ref) == B_OK) { 687 BEntry entry(&ref); 688 BPath path(&entry); 689 690 // these are not the paths you're looking for 691 if (currentPath != path) 692 continue; 693 } 694 } 695 696 trackerWindow.SendMessage(B_RESTORE_BACKGROUND_IMAGE); 697 } while (true); 698 } 699 } 700 701 702 int32 703 BackgroundsView::NotifyThread(void *data) 704 { 705 BackgroundsView *view = (BackgroundsView*)data; 706 707 view->NotifyServer(); 708 return B_OK; 709 } 710 711 712 void 713 BackgroundsView::SaveSettings(void) 714 { 715 BPath path; 716 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) { 717 path.Append(SETTINGS_FILE); 718 BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); 719 720 BPoint point = Window()->Frame().LeftTop(); 721 if (fSettings.ReplacePoint("pos", point)!=B_OK) 722 fSettings.AddPoint("pos", point); 723 724 entry_ref ref; 725 BEntry entry; 726 BPath path; 727 728 fPanel->GetPanelDirectory(&ref); 729 entry.SetTo(&ref); 730 entry.GetPath(&path); 731 if (fSettings.ReplaceString("paneldir", path.Path()) != B_OK) 732 fSettings.AddString("paneldir", path.Path()); 733 734 fFolderPanel->GetPanelDirectory(&ref); 735 entry.SetTo(&ref); 736 entry.GetPath(&path); 737 if (fSettings.ReplaceString("folderpaneldir", path.Path()) != B_OK) 738 fSettings.AddString("folderpaneldir", path.Path()); 739 740 fSettings.RemoveName("recentfolder"); 741 for (int32 i = 0; i < fPathList.CountItems(); i++) { 742 fSettings.AddString("recentfolder", fPathList.ItemAt(i)->Path()); 743 } 744 745 fSettings.Flatten(&file); 746 } 747 } 748 749 750 void 751 BackgroundsView::LoadSettings() 752 { 753 fSettings.MakeEmpty(); 754 755 BPath path; 756 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 757 return; 758 759 path.Append(SETTINGS_FILE); 760 BFile file(path.Path(), B_READ_ONLY); 761 if (file.InitCheck() != B_OK) 762 return; 763 764 if (fSettings.Unflatten(&file) != B_OK) { 765 printf("Error unflattening settings file %s\n", path.Path()); 766 return; 767 } 768 769 PRINT_OBJECT(fSettings); 770 771 BPoint point; 772 if (fSettings.FindPoint("pos", &point) == B_OK) 773 Window()->MoveTo(point); 774 775 BString string; 776 if (fSettings.FindString("paneldir", &string) == B_OK) 777 fPanel->SetPanelDirectory(string.String()); 778 779 if (fSettings.FindString("folderpaneldir", &string) == B_OK) 780 fFolderPanel->SetPanelDirectory(string.String()); 781 782 int32 index = 0; 783 while (fSettings.FindString("recentfolder", index, &string) == B_OK) { 784 if (index == 0) 785 fWorkspaceMenu->AddSeparatorItem(); 786 787 BPath path(string.String()); 788 int32 i = AddPath(path); 789 BString s; 790 s << "Folder: " << path.Leaf(); 791 BMenuItem *item = new BMenuItem(s.String(), 792 new BMessage(kMsgFolderSelected)); 793 fWorkspaceMenu->AddItem(item, -i-1+6); 794 index++; 795 } 796 fWorkspaceMenu->SetTargetForItems(this); 797 798 PRINT(("Settings Loaded\n")); 799 } 800 801 802 void 803 BackgroundsView::WorkspaceActivated(uint32 oldWorkspaces, bool active) 804 { 805 UpdateWithCurrent(); 806 } 807 808 809 void 810 BackgroundsView::UpdatePreview() 811 { 812 bool imageEnabled = !(fImageMenu->FindItem(kMsgNoImage)->IsMarked()); 813 if (fPlacementMenu->IsEnabled() ^ imageEnabled) 814 fPlacementMenu->SetEnabled(imageEnabled); 815 if (fIconLabelBackground->IsEnabled() ^ imageEnabled) 816 fIconLabelBackground->SetEnabled(imageEnabled); 817 818 bool textEnabled = (fPlacementMenu->FindItem(kMsgManualPlacement)->IsMarked()) 819 && imageEnabled; 820 if (fXPlacementText->IsEnabled() ^ textEnabled) 821 fXPlacementText->SetEnabled(textEnabled); 822 if (fYPlacementText->IsEnabled() ^ textEnabled) 823 fYPlacementText->SetEnabled(textEnabled); 824 825 if (textEnabled && (strcmp(fXPlacementText->Text(), "") == 0)) { 826 fXPlacementText->SetText("0"); 827 fYPlacementText->SetText("0"); 828 } 829 if (!textEnabled) { 830 fXPlacementText->SetText(NULL); 831 fYPlacementText->SetText(NULL); 832 } 833 834 fXPlacementText->TextView()->MakeSelectable(textEnabled); 835 fYPlacementText->TextView()->MakeSelectable(textEnabled); 836 fXPlacementText->TextView()->MakeEditable(textEnabled); 837 fYPlacementText->TextView()->MakeEditable(textEnabled); 838 839 fPreView->ClearViewBitmap(); 840 841 int32 index = ((BGImageMenuItem*)fImageMenu->FindMarked())->ImageIndex(); 842 if (index >= 0) { 843 BBitmap *bitmap = GetImage(index)->GetBitmap(); 844 if (bitmap) { 845 BackgroundImage::BackgroundImageInfo *info = 846 new BackgroundImage::BackgroundImageInfo(0, index, 847 FindPlacementMode(), BPoint(atoi(fXPlacementText->Text()), 848 atoi(fYPlacementText->Text())), 849 fIconLabelBackground->Value() == B_CONTROL_ON, 0, 0); 850 if (info->fMode == BackgroundImage::kAtOffset) { 851 fPreView->SetEnabled(true); 852 fPreView->fPoint.x = atoi(fXPlacementText->Text()); 853 fPreView->fPoint.y = atoi(fYPlacementText->Text()); 854 } else 855 fPreView->SetEnabled(false); 856 857 fPreView->fImageBounds = BRect(bitmap->Bounds()); 858 fCurrent->Show(info, fPreView); 859 } 860 } else 861 fPreView->SetEnabled(false); 862 863 fPreView->SetViewColor(fPicker->ValueAsColor()); 864 fPreView->Invalidate(); 865 } 866 867 868 BackgroundImage::Mode 869 BackgroundsView::FindPlacementMode() 870 { 871 BackgroundImage::Mode mode = BackgroundImage::kAtOffset; 872 873 if (fPlacementMenu->FindItem(kMsgCenterPlacement)->IsMarked()) 874 mode = BackgroundImage::kCentered; 875 if (fPlacementMenu->FindItem(kMsgScalePlacement)->IsMarked()) 876 mode = BackgroundImage::kScaledToFit; 877 if (fPlacementMenu->FindItem(kMsgManualPlacement)->IsMarked()) 878 mode = BackgroundImage::kAtOffset; 879 if (fPlacementMenu->FindItem(kMsgTilePlacement)->IsMarked()) 880 mode = BackgroundImage::kTiled; 881 882 return mode; 883 } 884 885 886 #ifndef __HAIKU__ 887 inline bool operator!=(const rgb_color& x, const rgb_color& y) 888 { 889 return (x.red!=y.red || x.blue!=y.blue || x.green!=y.green); 890 } 891 #endif 892 893 894 void 895 BackgroundsView::UpdateButtons() 896 { 897 bool hasChanged = false; 898 if (fPicker->IsEnabled() 899 && fPicker->ValueAsColor() != BScreen().DesktopColor()) { 900 hasChanged = true; 901 } else if (fCurrentInfo) { 902 if ((fIconLabelBackground->Value() == B_CONTROL_ON) ^ 903 fCurrentInfo->fEraseTextWidgetBackground) { 904 hasChanged = true; 905 } else if (FindPlacementMode() != fCurrentInfo->fMode) { 906 hasChanged = true; 907 } else if (fCurrentInfo->fImageIndex != 908 ((BGImageMenuItem*)fImageMenu->FindMarked())->ImageIndex()) { 909 hasChanged = true; 910 } else if (fCurrent->IsDesktop() 911 && ((fCurrentInfo->fWorkspace != B_ALL_WORKSPACES) 912 ^ (fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()))) { 913 hasChanged = true; 914 } else if (fCurrentInfo->fMode == BackgroundImage::kAtOffset) { 915 BString oldString, newString; 916 oldString << (int)fCurrentInfo->fOffset.x; 917 if (oldString != BString(fXPlacementText->Text())) { 918 hasChanged = true; 919 } 920 oldString = ""; 921 oldString << (int)fCurrentInfo->fOffset.y; 922 if (oldString != BString(fYPlacementText->Text())) { 923 hasChanged = true; 924 } 925 } 926 } else if (fImageMenu->IndexOf(fImageMenu->FindMarked()) > 0) { 927 hasChanged = true; 928 } 929 930 fApply->SetEnabled(hasChanged); 931 fRevert->SetEnabled(hasChanged); 932 } 933 934 935 void 936 BackgroundsView::RefsReceived(BMessage *msg) 937 { 938 entry_ref ref; 939 int32 i = 0; 940 BMimeType imageType("image"); 941 BPath desktopPath; 942 find_directory(B_DESKTOP_DIRECTORY, &desktopPath); 943 944 while (msg->FindRef("refs", i++, &ref) == B_OK) { 945 BPath path; 946 BEntry entry(&ref, true); 947 path.SetTo(&entry); 948 BNode node(&entry); 949 950 if (node.IsFile()) { 951 BNodeInfo nodeInfo(&node); 952 char fileType[B_MIME_TYPE_LENGTH]; 953 if (nodeInfo.GetType(fileType) != B_OK) 954 continue; 955 956 BMimeType refType(fileType); 957 if (!imageType.Contains(&refType)) 958 continue; 959 960 BGImageMenuItem *item; 961 int32 index = AddImage(path); 962 if (index >= 0) { 963 item = FindImageItem(index); 964 fLastImageIndex = index; 965 } else { 966 const char* name = GetImage(-index-1)->GetName(); 967 item = new BGImageMenuItem(name, -index-1, 968 new BMessage(kMsgImageSelected)); 969 AddItem(item); 970 item->SetTarget(this); 971 fLastImageIndex = -index-1; 972 } 973 974 item->SetMarked(true); 975 BMessenger(this).SendMessage(kMsgImageSelected); 976 } else if (node.IsDirectory()) { 977 if (desktopPath == path) { 978 fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->SetMarked(true); 979 BMessenger(this).SendMessage(kMsgCurrentWorkspace); 980 break; 981 } 982 BMenuItem *item; 983 int32 index = AddPath(path); 984 if (index >= 0) { 985 item = fWorkspaceMenu->ItemAt(index + 6); 986 fLastWorkspaceIndex = index + 6; 987 } else { 988 if (fWorkspaceMenu->CountItems() <= 5) 989 fWorkspaceMenu->AddSeparatorItem(); 990 BString s; 991 s << "Folder: " << path.Leaf(); 992 item = new BMenuItem(s.String(), new BMessage(kMsgFolderSelected)); 993 fWorkspaceMenu->AddItem(item, -index-1+6); 994 item->SetTarget(this); 995 fLastWorkspaceIndex = -index-1 + 6; 996 } 997 998 item->SetMarked(true); 999 BMessenger(this).SendMessage(kMsgFolderSelected); 1000 } 1001 } 1002 } 1003 1004 1005 int32 1006 BackgroundsView::AddPath(BPath path) 1007 { 1008 int32 count = fPathList.CountItems(); 1009 int32 index = 0; 1010 for(; index < count; index++) { 1011 BPath *p = fPathList.ItemAt(index); 1012 int c = BString(p->Path()).ICompare(path.Path()); 1013 if (c == 0) 1014 return index; 1015 1016 if (c > 0) 1017 break; 1018 } 1019 fPathList.AddItem(new BPath(path), index); 1020 return -index-1; 1021 } 1022 1023 1024 int32 1025 BackgroundsView::AddImage(BPath path) 1026 { 1027 int32 count = fImageList.CountItems(); 1028 int32 index = 0; 1029 for(; index < count; index++) { 1030 Image *image = fImageList.ItemAt(index); 1031 if (image->GetPath() == path) 1032 return index; 1033 } 1034 1035 fImageList.AddItem(new Image(path)); 1036 return -index-1; 1037 } 1038 1039 1040 void 1041 BackgroundsView::ProcessRefs(entry_ref dir, BMessage* refs) 1042 { 1043 fWorkspaceMenu->FindItem(kMsgDefaultFolder)->SetMarked(true); 1044 BMessenger messenger(this); 1045 messenger.SendMessage(kMsgDefaultFolder); 1046 1047 if (refs->CountNames(B_REF_TYPE) > 0) { 1048 messenger.SendMessage(refs); 1049 } else { 1050 BMessage message(B_REFS_RECEIVED); 1051 message.AddRef("refs", &dir); 1052 messenger.SendMessage(&message); 1053 } 1054 } 1055 1056 1057 Image* 1058 BackgroundsView::GetImage(int32 imageIndex) 1059 { 1060 return fImageList.ItemAt(imageIndex); 1061 } 1062 1063 1064 BGImageMenuItem* 1065 BackgroundsView::FindImageItem(const int32 imageIndex) 1066 { 1067 if (imageIndex < 0) 1068 return (BGImageMenuItem *)fImageMenu->ItemAt(0); 1069 1070 int32 count = fImageMenu->CountItems() - 2; 1071 int32 index = 2; 1072 for (; index < count; index++) { 1073 BGImageMenuItem *image = (BGImageMenuItem *)fImageMenu->ItemAt(index); 1074 if (image->ImageIndex() == imageIndex) 1075 return image; 1076 } 1077 return NULL; 1078 } 1079 1080 1081 bool 1082 BackgroundsView::AddItem(BGImageMenuItem *item) 1083 { 1084 int32 count = fImageMenu->CountItems() - 2; 1085 int32 index = 2; 1086 if (count < index) { 1087 fImageMenu->AddItem(new BSeparatorItem(), 1); 1088 count = fImageMenu->CountItems() - 2; 1089 } 1090 1091 for (; index < count; index++) { 1092 BGImageMenuItem* image = (BGImageMenuItem *)fImageMenu->ItemAt(index); 1093 int c = (BString(image->Label()).ICompare(BString(item->Label()))); 1094 if (c > 0) 1095 break; 1096 } 1097 return fImageMenu->AddItem(item, index); 1098 } 1099 1100 1101 // #pragma mark - 1102 1103 1104 PreView::PreView(BRect frame, const char *name, int32 resize, int32 flags) 1105 : BControl(frame, name, NULL, NULL, resize, flags), 1106 fMoveHandCursor(kHandCursorData) 1107 { 1108 } 1109 1110 1111 void 1112 PreView::AttachedToWindow() 1113 { 1114 rgb_color color = ViewColor(); 1115 BControl::AttachedToWindow(); 1116 SetViewColor(color); 1117 } 1118 1119 1120 void 1121 PreView::MouseDown(BPoint point) 1122 { 1123 if (IsEnabled() && Bounds().Contains(point)) { 1124 uint32 buttons; 1125 GetMouse(&point, &buttons); 1126 if(buttons & B_PRIMARY_MOUSE_BUTTON) { 1127 fOldPoint = point; 1128 SetTracking(true); 1129 BScreen().GetMode(&mode); 1130 x_ratio = Bounds().Width() / mode.virtual_width; 1131 y_ratio = Bounds().Height() / mode.virtual_height; 1132 SetMouseEventMask(B_POINTER_EVENTS, 1133 B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY); 1134 } 1135 } 1136 } 1137 1138 1139 void 1140 PreView::MouseUp(BPoint point) 1141 { 1142 if (IsTracking()) 1143 SetTracking(false); 1144 } 1145 1146 1147 void 1148 PreView::MouseMoved(BPoint point, uint32 transit, const BMessage *message) 1149 { 1150 if (IsEnabled()) 1151 SetViewCursor(&fMoveHandCursor); 1152 else 1153 SetViewCursor(B_CURSOR_SYSTEM_DEFAULT); 1154 1155 if (IsTracking()) { 1156 float x, y; 1157 x = fPoint.x + (point.x - fOldPoint.x)/ x_ratio; 1158 y = fPoint.y + (point.y - fOldPoint.y)/ y_ratio; 1159 bool min, max, mustSend = false; 1160 min = (x > -fImageBounds.Width()); 1161 max = (x < mode.virtual_width); 1162 if (min && max) { 1163 fOldPoint.x = point.x; 1164 fPoint.x = x; 1165 mustSend = true; 1166 } else { 1167 if (!min && fPoint.x > -fImageBounds.Width()) { 1168 fPoint.x = -fImageBounds.Width(); 1169 fOldPoint.x = point.x - (x - fPoint.x) * x_ratio; 1170 mustSend = true; 1171 } 1172 if (!max && fPoint.x < mode.virtual_width) { 1173 fPoint.x = mode.virtual_width; 1174 fOldPoint.x = point.x - (x - fPoint.x) * x_ratio; 1175 mustSend = true; 1176 } 1177 } 1178 1179 min = (y > -fImageBounds.Height()); 1180 max = (y < mode.virtual_height); 1181 if (min && max) { 1182 fOldPoint.y = point.y; 1183 fPoint.y = y; 1184 mustSend = true; 1185 } else { 1186 if (!min && fPoint.y > -fImageBounds.Height()) { 1187 fPoint.y = -fImageBounds.Height(); 1188 fOldPoint.y = point.y - (y - fPoint.y) * y_ratio; 1189 mustSend = true; 1190 } 1191 if (!max && fPoint.y < mode.virtual_height) { 1192 fPoint.y = mode.virtual_height; 1193 fOldPoint.y = point.y - (y - fPoint.y) * y_ratio; 1194 mustSend = true; 1195 } 1196 } 1197 1198 if (mustSend) { 1199 BMessenger messenger(Parent()); 1200 messenger.SendMessage(kMsgUpdatePreviewPlacement); 1201 } 1202 } 1203 BControl::MouseMoved(point, transit, message); 1204 } 1205 1206 1207 // #pragma mark - 1208 1209 1210 PreviewBox::PreviewBox(BRect frame, const char *name) 1211 : BBox(frame, name) 1212 { 1213 fIsDesktop = true; 1214 } 1215 1216 1217 void 1218 PreviewBox::Draw(BRect rect) 1219 { 1220 rgb_color color = HighColor(); 1221 BPoint points[] = { 1222 BPoint(11,19), BPoint(139,19), BPoint(141,21), 1223 BPoint(141,119), BPoint(139,121), BPoint(118,121), 1224 BPoint(118,126), BPoint(117,127), BPoint(33,127), 1225 BPoint(32,126), BPoint(32,121),BPoint(11,121), 1226 BPoint(9,119),BPoint(9,21),BPoint(11,19) 1227 }; 1228 1229 SetHighColor(LowColor()); 1230 FillRect(BRect(9,19,141,127)); 1231 1232 if (fIsDesktop) { 1233 SetHighColor(184,184,184); 1234 FillPolygon(points, 15); 1235 SetHighColor(96,96,96); 1236 StrokePolygon(points, 15); 1237 FillRect(BRect(107,121,111,123)); 1238 SetHighColor(0,0,0); 1239 StrokeRect(BRect(14,24,136,116)); 1240 SetHighColor(0,255,0); 1241 FillRect(BRect(101,122,103,123)); 1242 } else { 1243 SetHighColor(152,152,152); 1244 StrokeLine(BPoint(11,13), BPoint(67,13)); 1245 StrokeLine(BPoint(67,21)); 1246 StrokeLine(BPoint(139,21)); 1247 StrokeLine(BPoint(139,119)); 1248 StrokeLine(BPoint(11,119)); 1249 StrokeLine(BPoint(11,13)); 1250 StrokeRect(BRect(14,24,136,116)); 1251 SetHighColor(255,203,0); 1252 FillRect(BRect(12,14,66,21)); 1253 SetHighColor(240,240,240); 1254 StrokeRect(BRect(12,22,137,117)); 1255 StrokeLine(BPoint(138,22), BPoint(138,22)); 1256 StrokeLine(BPoint(12,118), BPoint(12,118)); 1257 SetHighColor(200,200,200); 1258 StrokeRect(BRect(13,23,138,118)); 1259 } 1260 1261 SetHighColor(color); 1262 BBox::Draw(rect); 1263 } 1264 1265 1266 void 1267 PreviewBox::SetDesktop(bool isDesktop) 1268 { 1269 fIsDesktop = isDesktop; 1270 Invalidate(); 1271 } 1272 1273 1274 // #pragma mark - 1275 1276 1277 BGImageMenuItem::BGImageMenuItem(const char *label, int32 imageIndex, 1278 BMessage *message, char shortcut, uint32 modifiers) 1279 : BMenuItem(label, message, shortcut, modifiers), 1280 fImageIndex(imageIndex) 1281 { 1282 } 1283