1 /* 2 * Copyright 2002-2017 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 * Jerome Duval, jerome.duval@free.fr 8 * Jonas Sundström, jonas@kirilla.se 9 * John Scipione, jscipione@gmail.com 10 * Brian Hill, supernova@warpmail.net 11 */ 12 13 14 #include "BackgroundsView.h" 15 16 #include <algorithm> 17 18 #include <stdio.h> 19 #include <stdlib.h> 20 21 #include <Alert.h> 22 #include <Bitmap.h> 23 #include <Catalog.h> 24 #include <ControlLook.h> 25 #include <Cursor.h> 26 #include <Debug.h> 27 #include <File.h> 28 #include <FindDirectory.h> 29 #include <LayoutBuilder.h> 30 #include <Locale.h> 31 #include <MenuField.h> 32 #include <Messenger.h> 33 #include <MimeType.h> 34 #include <Point.h> 35 #include <PopUpMenu.h> 36 37 #include <be_apps/Tracker/Background.h> 38 #include <ScreenDefs.h> 39 40 #include "ImageFilePanel.h" 41 42 43 #undef B_TRANSLATION_CONTEXT 44 #define B_TRANSLATION_CONTEXT "Main View" 45 46 47 static const uint32 kMsgApplySettings = 'aply'; 48 static const uint32 kMsgRevertSettings = 'rvrt'; 49 50 static const uint32 kMsgUpdateColor = 'upcl'; 51 static const uint32 kMsgAllWorkspaces = 'alwk'; 52 static const uint32 kMsgCurrentWorkspace = 'crwk'; 53 static const uint32 kMsgDefaultFolder = 'dffl'; 54 static const uint32 kMsgOtherFolder = 'otfl'; 55 static const uint32 kMsgNoImage = 'noim'; 56 static const uint32 kMsgOtherImage = 'otim'; 57 static const uint32 kMsgImageSelected = 'imsl'; 58 static const uint32 kMsgFolderSelected = 'flsl'; 59 60 static const uint32 kMsgCenterPlacement = 'cnpl'; 61 static const uint32 kMsgManualPlacement = 'mnpl'; 62 static const uint32 kMsgScalePlacement = 'scpl'; 63 static const uint32 kMsgTilePlacement = 'tlpl'; 64 static const uint32 kMsgIconLabelOutline = 'ilol'; 65 66 static const uint32 kMsgImagePlacement = 'xypl'; 67 static const uint32 kMsgUpdatePreviewPlacement = 'pvpl'; 68 69 70 BackgroundsView::BackgroundsView() 71 : 72 BBox("BackgroundsView"), 73 fCurrent(NULL), 74 fCurrentInfo(NULL), 75 fLastImageIndex(-1), 76 fRecentFoldersLimit(10), 77 fPathList(1, true), 78 fImageList(1, true), 79 fFoundPositionSetting(false) 80 { 81 SetBorder(B_NO_BORDER); 82 83 BBox* previewBox = new BBox("preview"); 84 previewBox->SetLabel(B_TRANSLATE("Preview")); 85 86 fPreview = new Preview(); 87 88 fTopLeft = new FramePart(FRAME_TOP_LEFT); 89 fTop = new FramePart(FRAME_TOP); 90 fTopRight = new FramePart(FRAME_TOP_RIGHT); 91 fLeft = new FramePart(FRAME_LEFT_SIDE); 92 fRight = new FramePart(FRAME_RIGHT_SIDE); 93 fBottomLeft = new FramePart(FRAME_BOTTOM_LEFT); 94 fBottom = new FramePart(FRAME_BOTTOM); 95 fBottomRight = new FramePart(FRAME_BOTTOM_RIGHT); 96 97 fXPlacementText = new BTextControl(B_TRANSLATE("X:"), NULL, 98 new BMessage(kMsgImagePlacement)); 99 fYPlacementText = new BTextControl(B_TRANSLATE("Y:"), NULL, 100 new BMessage(kMsgImagePlacement)); 101 102 // right-align text view 103 fXPlacementText->TextView()->SetAlignment(B_ALIGN_RIGHT); 104 fYPlacementText->TextView()->SetAlignment(B_ALIGN_RIGHT); 105 106 // max 5 characters allowed 107 fXPlacementText->TextView()->SetMaxBytes(5); 108 fYPlacementText->TextView()->SetMaxBytes(5); 109 110 // limit to numbers only 111 for (int32 i = 0; i < 256; i++) { 112 if ((i < '0' || i > '9') && i != '-') { 113 fXPlacementText->TextView()->DisallowChar(i); 114 fYPlacementText->TextView()->DisallowChar(i); 115 } 116 } 117 118 previewBox->AddChild(BLayoutBuilder::Group<>() 119 .AddGlue() 120 .AddGroup(B_VERTICAL, 0) 121 .AddGroup(B_HORIZONTAL, 0) 122 .AddGlue() 123 .AddGrid(0, 0, 1) 124 .Add(fTopLeft, 0, 0) 125 .Add(fTop, 1, 0) 126 .Add(fTopRight, 2, 0) 127 .Add(fLeft, 0, 1) 128 .Add(fPreview, 1, 1) 129 .Add(fRight, 2, 1) 130 .Add(fBottomLeft, 0, 2) 131 .Add(fBottom, 1, 2) 132 .Add(fBottomRight, 2, 2) 133 .End() 134 .AddGlue() 135 .End() 136 .AddStrut(be_control_look->DefaultItemSpacing() * 2) 137 .AddGroup(B_HORIZONTAL) 138 .Add(fXPlacementText) 139 .Add(fYPlacementText) 140 .End() 141 .AddGlue() 142 .SetInsets(B_USE_DEFAULT_SPACING) 143 .End() 144 .AddGlue() 145 .View()); 146 147 BBox* rightbox = new BBox("rightbox"); 148 149 fWorkspaceMenu = new BPopUpMenu(B_TRANSLATE("pick one")); 150 fWorkspaceMenu->AddItem(new BMenuItem(B_TRANSLATE("All workspaces"), 151 new BMessage(kMsgAllWorkspaces))); 152 BMenuItem* menuItem; 153 fWorkspaceMenu->AddItem(menuItem = new BMenuItem( 154 B_TRANSLATE("Current workspace"), 155 new BMessage(kMsgCurrentWorkspace))); 156 menuItem->SetMarked(true); 157 fWorkspaceMenu->AddSeparatorItem(); 158 fWorkspaceMenu->AddItem(new BMenuItem(B_TRANSLATE("Default folder"), 159 new BMessage(kMsgDefaultFolder))); 160 fWorkspaceMenu->AddItem(new BMenuItem( 161 B_TRANSLATE("Other folder" B_UTF8_ELLIPSIS), 162 new BMessage(kMsgOtherFolder))); 163 164 BMenuField* workspaceMenuField = new BMenuField("workspaceMenuField", 165 NULL, fWorkspaceMenu); 166 workspaceMenuField->ResizeToPreferred(); 167 rightbox->SetLabel(workspaceMenuField); 168 169 fImageMenu = new BPopUpMenu(B_TRANSLATE("pick one")); 170 fImageMenu->AddItem(new BGImageMenuItem(B_TRANSLATE("None"), -1, 171 new BMessage(kMsgNoImage))); 172 fImageMenu->AddSeparatorItem(); 173 fImageMenu->AddItem(new BMenuItem(B_TRANSLATE("Other" B_UTF8_ELLIPSIS), 174 new BMessage(kMsgOtherImage))); 175 176 BMenuField* imageMenuField = new BMenuField("image", 177 B_TRANSLATE("Image:"), fImageMenu); 178 imageMenuField->SetAlignment(B_ALIGN_RIGHT); 179 180 fPlacementMenu = new BPopUpMenu(B_TRANSLATE("pick one")); 181 fPlacementMenu->AddItem(new BMenuItem(B_TRANSLATE("Manual"), 182 new BMessage(kMsgManualPlacement))); 183 fPlacementMenu->AddItem(new BMenuItem(B_TRANSLATE("Center"), 184 new BMessage(kMsgCenterPlacement))); 185 fPlacementMenu->AddItem(new BMenuItem(B_TRANSLATE("Scale to fit"), 186 new BMessage(kMsgScalePlacement))); 187 fPlacementMenu->AddItem(new BMenuItem(B_TRANSLATE("Tile"), 188 new BMessage(kMsgTilePlacement))); 189 190 BMenuField* placementMenuField = new BMenuField("placement", 191 B_TRANSLATE("Placement:"), fPlacementMenu); 192 placementMenuField->SetAlignment(B_ALIGN_RIGHT); 193 194 fIconLabelOutline = new BCheckBox(B_TRANSLATE("Icon label outline"), 195 new BMessage(kMsgIconLabelOutline)); 196 fIconLabelOutline->SetValue(B_CONTROL_OFF); 197 198 fPicker = new BColorControl(BPoint(0, 0), B_CELLS_32x8, 8.0, "Picker", 199 new BMessage(kMsgUpdateColor)); 200 201 rightbox->AddChild(BLayoutBuilder::Group<>(B_VERTICAL) 202 .AddGroup(B_HORIZONTAL, 0.0f) 203 .AddGrid(B_USE_DEFAULT_SPACING, B_USE_SMALL_SPACING) 204 .Add(imageMenuField->CreateLabelLayoutItem(), 0, 0) 205 .AddGroup(B_HORIZONTAL, 0.0f, 1, 0) 206 .Add(imageMenuField->CreateMenuBarLayoutItem(), 0.0f) 207 .AddGlue() 208 .End() 209 .Add(placementMenuField->CreateLabelLayoutItem(), 0, 1) 210 .AddGroup(B_HORIZONTAL, 0.0f, 1, 1) 211 .Add(placementMenuField->CreateMenuBarLayoutItem(), 0.0f) 212 .AddGlue() 213 .End() 214 .Add(fIconLabelOutline, 1, 2) 215 .End() 216 .AddGlue() 217 .End() 218 .AddGlue() 219 .Add(fPicker) 220 .SetInsets(B_USE_DEFAULT_SPACING) 221 .View()); 222 223 fRevert = new BButton(B_TRANSLATE("Revert"), 224 new BMessage(kMsgRevertSettings)); 225 fApply = new BButton(B_TRANSLATE("Apply"), 226 new BMessage(kMsgApplySettings)); 227 228 fRevert->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, 229 B_ALIGN_NO_VERTICAL)); 230 fApply->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT, 231 B_ALIGN_NO_VERTICAL)); 232 233 BLayoutBuilder::Group<>(this, B_VERTICAL, 0) 234 .SetInsets(B_USE_WINDOW_SPACING) 235 .AddGroup(B_HORIZONTAL, 0) 236 .AddGroup(B_VERTICAL, 0) 237 .AddStrut(floorf(rightbox->TopBorderOffset() 238 - previewBox->TopBorderOffset()) - 1) 239 .Add(previewBox) 240 .End() 241 .AddStrut(B_USE_DEFAULT_SPACING) 242 .Add(rightbox) 243 .End() 244 .AddGroup(B_HORIZONTAL, 0) 245 .Add(fRevert) 246 .Add(fApply) 247 .SetInsets(0, B_USE_DEFAULT_SPACING, 0, 0) 248 .End(); 249 250 fApply->MakeDefault(true); 251 } 252 253 254 BackgroundsView::~BackgroundsView() 255 { 256 // The order matter. The last panel saves the state 257 delete fFolderPanel; 258 delete fPanel; 259 } 260 261 262 void 263 BackgroundsView::AllAttached() 264 { 265 fPlacementMenu->SetTargetForItems(this); 266 fImageMenu->SetTargetForItems(this); 267 fWorkspaceMenu->SetTargetForItems(this); 268 fXPlacementText->SetTarget(this); 269 fYPlacementText->SetTarget(this); 270 fIconLabelOutline->SetTarget(this); 271 fPicker->SetTarget(this); 272 fApply->SetTarget(this); 273 fRevert->SetTarget(this); 274 275 BPath path; 276 entry_ref ref; 277 if (find_directory(B_SYSTEM_DATA_DIRECTORY, &path) == B_OK) { 278 path.Append("artwork"); 279 get_ref_for_path(path.Path(), &ref); 280 } 281 282 BMessenger messenger(this); 283 fPanel = new ImageFilePanel(B_OPEN_PANEL, &messenger, &ref, 284 B_FILE_NODE, false, NULL, new ImageFilter(true)); 285 fPanel->SetButtonLabel(B_DEFAULT_BUTTON, B_TRANSLATE("Select")); 286 287 fFolderPanel = new BFilePanel(B_OPEN_PANEL, &messenger, NULL, 288 B_DIRECTORY_NODE, false, NULL, new ImageFilter(false)); 289 fFolderPanel->SetButtonLabel(B_DEFAULT_BUTTON, B_TRANSLATE("Select")); 290 291 _LoadSettings(); 292 _LoadDesktopFolder(); 293 294 BPoint point; 295 if (fSettings.FindPoint("pos", &point) == B_OK) { 296 fFoundPositionSetting = true; 297 Window()->MoveTo(point); 298 Window()->MoveOnScreen(B_MOVE_IF_PARTIALLY_OFFSCREEN); 299 } 300 301 fApply->SetEnabled(false); 302 fRevert->SetEnabled(false); 303 } 304 305 306 void 307 BackgroundsView::MessageReceived(BMessage* message) 308 { 309 // Color drop 310 if (message->WasDropped()) { 311 rgb_color *clr; 312 ssize_t out_size; 313 if (message->FindData("RGBColor", B_RGB_COLOR_TYPE, 314 (const void **)&clr, &out_size) == B_OK) { 315 fPicker->SetValue(*clr); 316 _UpdatePreview(); 317 _UpdateButtons(); 318 return; 319 } 320 } 321 322 switch (message->what) { 323 case B_SIMPLE_DATA: 324 case B_REFS_RECEIVED: 325 RefsReceived(message); 326 break; 327 328 case kMsgUpdatePreviewPlacement: 329 { 330 BString xstring, ystring; 331 xstring << (int)fPreview->fPoint.x; 332 ystring << (int)fPreview->fPoint.y; 333 fXPlacementText->SetText(xstring.String()); 334 fYPlacementText->SetText(ystring.String()); 335 _UpdatePreview(); 336 _UpdateButtons(); 337 break; 338 } 339 340 case kMsgManualPlacement: 341 case kMsgTilePlacement: 342 case kMsgScalePlacement: 343 case kMsgCenterPlacement: 344 _UpdatePreview(); 345 _UpdateButtons(); 346 break; 347 348 case kMsgIconLabelOutline: 349 _UpdateButtons(); 350 break; 351 352 case kMsgUpdateColor: 353 case kMsgImagePlacement: 354 _UpdatePreview(); 355 _UpdateButtons(); 356 break; 357 358 case kMsgCurrentWorkspace: 359 case kMsgAllWorkspaces: 360 fImageMenu->FindItem(kMsgNoImage)->SetLabel(B_TRANSLATE("None")); 361 if (fCurrent && fCurrent->IsDesktop()) { 362 _UpdateButtons(); 363 } else { 364 _SetDesktop(true); 365 _LoadDesktopFolder(); 366 } 367 break; 368 369 case kMsgDefaultFolder: 370 fImageMenu->FindItem(kMsgNoImage)->SetLabel(B_TRANSLATE("None")); 371 _SetDesktop(false); 372 _LoadDefaultFolder(); 373 break; 374 375 case kMsgOtherFolder: 376 fFolderPanel->Show(); 377 break; 378 379 case kMsgOtherImage: 380 fPanel->Show(); 381 break; 382 383 case B_CANCEL: 384 { 385 PRINT(("cancel received\n")); 386 void* pointer; 387 message->FindPointer("source", &pointer); 388 if (pointer == fPanel) { 389 if (fLastImageIndex >= 0) 390 _FindImageItem(fLastImageIndex)->SetMarked(true); 391 else 392 fImageMenu->ItemAt(0)->SetMarked(true); 393 } 394 break; 395 } 396 397 case kMsgImageSelected: 398 case kMsgNoImage: 399 fLastImageIndex = ((BGImageMenuItem*)fImageMenu->FindMarked()) 400 ->ImageIndex(); 401 _UpdatePreview(); 402 _UpdateButtons(); 403 break; 404 405 case kMsgFolderSelected: 406 { 407 fImageMenu->FindItem(kMsgNoImage)->SetLabel(B_TRANSLATE("Default")); 408 _SetDesktop(false); 409 BString folderPathStr; 410 if (message->FindString("folderPath", &folderPathStr) == B_OK) { 411 BPath folderPath(folderPathStr); 412 _LoadRecentFolder(folderPath); 413 } 414 break; 415 } 416 case kMsgApplySettings: 417 { 418 _Save(); 419 420 // Notify the server and Screen preflet 421 thread_id notifyThread; 422 notifyThread = spawn_thread(BackgroundsView::_NotifyThread, 423 "notifyThread", B_NORMAL_PRIORITY, this); 424 resume_thread(notifyThread); 425 _UpdateButtons(); 426 break; 427 } 428 case kMsgRevertSettings: 429 _UpdateWithCurrent(); 430 break; 431 432 default: 433 BView::MessageReceived(message); 434 break; 435 } 436 } 437 438 439 void 440 BackgroundsView::_LoadDesktopFolder() 441 { 442 BPath path; 443 if (find_directory(B_DESKTOP_DIRECTORY, &path) == B_OK) { 444 status_t error = get_ref_for_path(path.Path(), &fCurrentRef); 445 if (error != B_OK) 446 printf("error in LoadDesktopSettings\n"); 447 _LoadFolder(true); 448 } 449 } 450 451 452 void 453 BackgroundsView::_LoadDefaultFolder() 454 { 455 BPath path; 456 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) { 457 BString pathString = path.Path(); 458 pathString << "/Tracker/DefaultFolderTemplate"; 459 status_t error = get_ref_for_path(pathString.String(), &fCurrentRef); 460 if (error != B_OK) 461 printf("error in LoadDefaultFolderSettings\n"); 462 _LoadFolder(false); 463 } 464 } 465 466 467 void 468 BackgroundsView::_LoadRecentFolder(BPath path) 469 { 470 status_t error = get_ref_for_path(path.Path(), &fCurrentRef); 471 if (error != B_OK) 472 printf("error in LoadRecentFolder\n"); 473 _LoadFolder(false); 474 } 475 476 477 void 478 BackgroundsView::_LoadFolder(bool isDesktop) 479 { 480 if (fCurrent) { 481 delete fCurrent; 482 fCurrent = NULL; 483 } 484 485 BNode node(&fCurrentRef); 486 if (node.InitCheck() == B_OK) 487 fCurrent = BackgroundImage::GetBackgroundImage(&node, isDesktop, this); 488 489 _UpdateWithCurrent(); 490 } 491 492 493 void 494 BackgroundsView::_UpdateWithCurrent(void) 495 { 496 if (fCurrent == NULL) 497 return; 498 499 fPlacementMenu->FindItem(kMsgScalePlacement) 500 ->SetEnabled(fCurrent->IsDesktop()); 501 fPlacementMenu->FindItem(kMsgCenterPlacement) 502 ->SetEnabled(fCurrent->IsDesktop()); 503 504 if (fWorkspaceMenu->IndexOf(fWorkspaceMenu->FindMarked()) > 5) 505 fImageMenu->FindItem(kMsgNoImage)->SetLabel(B_TRANSLATE("Default")); 506 else 507 fImageMenu->FindItem(kMsgNoImage)->SetLabel(B_TRANSLATE("None")); 508 509 for (int32 i = fImageMenu->CountItems() - 5; i >= 0; i--) { 510 fImageMenu->RemoveItem(2); 511 } 512 513 for (int32 i = fImageList.CountItems() - 1; i >= 0; i--) { 514 BMessage* message = new BMessage(kMsgImageSelected); 515 _AddItem(new BGImageMenuItem(GetImage(i)->GetName(), i, message)); 516 } 517 518 fImageMenu->SetTargetForItems(this); 519 520 fCurrentInfo = fCurrent->ImageInfoForWorkspace(current_workspace()); 521 522 if (!fCurrentInfo) { 523 fImageMenu->FindItem(kMsgNoImage)->SetMarked(true); 524 fPlacementMenu->FindItem(kMsgManualPlacement)->SetMarked(true); 525 fIconLabelOutline->SetValue(B_CONTROL_ON); 526 } else { 527 fIconLabelOutline->SetValue(fCurrentInfo->fTextWidgetLabelOutline 528 ? B_CONTROL_ON : B_CONTROL_OFF); 529 530 fLastImageIndex = fCurrentInfo->fImageIndex; 531 _FindImageItem(fLastImageIndex)->SetMarked(true); 532 533 if (fLastImageIndex > -1) { 534 535 BString xtext, ytext; 536 int32 cmd = 0; 537 switch (fCurrentInfo->fMode) { 538 case BackgroundImage::kCentered: 539 cmd = kMsgCenterPlacement; 540 break; 541 case BackgroundImage::kScaledToFit: 542 cmd = kMsgScalePlacement; 543 break; 544 case BackgroundImage::kAtOffset: 545 cmd = kMsgManualPlacement; 546 xtext << (int)fCurrentInfo->fOffset.x; 547 ytext << (int)fCurrentInfo->fOffset.y; 548 break; 549 case BackgroundImage::kTiled: 550 cmd = kMsgTilePlacement; 551 break; 552 } 553 554 if (cmd != 0) 555 fPlacementMenu->FindItem(cmd)->SetMarked(true); 556 557 fXPlacementText->SetText(xtext.String()); 558 fYPlacementText->SetText(ytext.String()); 559 } else { 560 fPlacementMenu->FindItem(kMsgManualPlacement)->SetMarked(true); 561 } 562 } 563 564 rgb_color color = {255, 255, 255, 255}; 565 if (fCurrent->IsDesktop()) { 566 color = BScreen().DesktopColor(); 567 fPicker->SetEnabled(true); 568 } else 569 fPicker->SetEnabled(false); 570 571 fPicker->SetValue(color); 572 573 _UpdatePreview(); 574 _UpdateButtons(); 575 } 576 577 578 void 579 BackgroundsView::_Save() 580 { 581 bool textWidgetLabelOutline = fIconLabelOutline->Value() == B_CONTROL_ON; 582 583 BackgroundImage::Mode mode = _FindPlacementMode(); 584 BPoint offset(atoi(fXPlacementText->Text()), atoi(fYPlacementText->Text())); 585 586 if (!fCurrent->IsDesktop()) { 587 if (fCurrentInfo == NULL) { 588 fCurrentInfo = new BackgroundImage::BackgroundImageInfo( 589 B_ALL_WORKSPACES, fLastImageIndex, mode, offset, 590 textWidgetLabelOutline, 0, 0); 591 fCurrent->Add(fCurrentInfo); 592 } else { 593 fCurrentInfo->fTextWidgetLabelOutline = textWidgetLabelOutline; 594 fCurrentInfo->fMode = mode; 595 if (fCurrentInfo->fMode == BackgroundImage::kAtOffset) 596 fCurrentInfo->fOffset = offset; 597 fCurrentInfo->fImageIndex = fLastImageIndex; 598 } 599 } else { 600 uint32 workspaceMask = 1; 601 int32 workspace = current_workspace(); 602 for (; workspace; workspace--) 603 workspaceMask *= 2; 604 605 if (fCurrentInfo != NULL) { 606 if (fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()) { 607 if (fCurrentInfo->fWorkspace & workspaceMask 608 && fCurrentInfo->fWorkspace != workspaceMask) { 609 fCurrentInfo->fWorkspace = fCurrentInfo->fWorkspace 610 ^ workspaceMask; 611 fCurrentInfo = new BackgroundImage::BackgroundImageInfo( 612 workspaceMask, fLastImageIndex, mode, offset, 613 textWidgetLabelOutline, fCurrentInfo->fImageSet, 614 fCurrentInfo->fCacheMode); 615 fCurrent->Add(fCurrentInfo); 616 } else if (fCurrentInfo->fWorkspace == workspaceMask) { 617 fCurrentInfo->fTextWidgetLabelOutline 618 = textWidgetLabelOutline; 619 fCurrentInfo->fMode = mode; 620 if (fCurrentInfo->fMode == BackgroundImage::kAtOffset) 621 fCurrentInfo->fOffset = offset; 622 623 fCurrentInfo->fImageIndex = fLastImageIndex; 624 } 625 } else { 626 fCurrent->RemoveAll(); 627 628 fCurrentInfo = new BackgroundImage::BackgroundImageInfo( 629 B_ALL_WORKSPACES, fLastImageIndex, mode, offset, 630 textWidgetLabelOutline, fCurrent->GetShowingImageSet(), 631 fCurrentInfo->fCacheMode); 632 fCurrent->Add(fCurrentInfo); 633 } 634 } else { 635 if (fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()) { 636 fCurrentInfo = new BackgroundImage::BackgroundImageInfo( 637 workspaceMask, fLastImageIndex, mode, offset, 638 textWidgetLabelOutline, fCurrent->GetShowingImageSet(), 0); 639 } else { 640 fCurrent->RemoveAll(); 641 fCurrentInfo = new BackgroundImage::BackgroundImageInfo( 642 B_ALL_WORKSPACES, fLastImageIndex, mode, offset, 643 textWidgetLabelOutline, fCurrent->GetShowingImageSet(), 0); 644 } 645 fCurrent->Add(fCurrentInfo); 646 } 647 648 if (!fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()) { 649 for (int32 i = 0; i < count_workspaces(); i++) { 650 BScreen().SetDesktopColor(fPicker->ValueAsColor(), i, true); 651 } 652 } else 653 BScreen().SetDesktopColor(fPicker->ValueAsColor(), true); 654 } 655 656 BNode node(&fCurrentRef); 657 658 status_t status = fCurrent->SetBackgroundImage(&node); 659 if (status != B_OK) { 660 BString error(strerror(status)); 661 BString text(B_TRANSLATE("Setting the background image failed:")); 662 text.Append("\n").Append(error); 663 BAlert* alert = new BAlert(B_TRANSLATE("Set background image error"), 664 text, B_TRANSLATE("OK")); 665 alert->SetShortcut(0, B_ESCAPE); 666 alert->Go(NULL); 667 printf("setting background image failed: %s\n", error.String()); 668 } 669 } 670 671 672 void 673 BackgroundsView::_NotifyServer() 674 { 675 BMessenger tracker("application/x-vnd.Be-TRAK"); 676 677 if (fCurrent->IsDesktop()) { 678 tracker.SendMessage(new BMessage(B_RESTORE_BACKGROUND_IMAGE)); 679 } else { 680 int32 i = -1; 681 BMessage reply; 682 int32 error; 683 BEntry currentEntry(&fCurrentRef); 684 BPath currentPath(¤tEntry); 685 bool isCustomFolder 686 = !fWorkspaceMenu->FindItem(kMsgDefaultFolder)->IsMarked(); 687 688 do { 689 BMessage message(B_GET_PROPERTY); 690 i++; 691 692 // look at the "Poses" in every Tracker window 693 message.AddSpecifier("Poses"); 694 message.AddSpecifier("Window", i); 695 696 reply.MakeEmpty(); 697 tracker.SendMessage(&message, &reply); 698 699 // break out of the loop when we're at the end of 700 // the windows 701 if (reply.what == B_MESSAGE_NOT_UNDERSTOOD 702 && reply.FindInt32("error", &error) == B_OK 703 && error == B_BAD_INDEX) 704 break; 705 706 // don't stop for windows that don't understand 707 // a request for "Poses"; they're not displaying 708 // folders 709 if (reply.what == B_MESSAGE_NOT_UNDERSTOOD 710 && reply.FindInt32("error", &error) == B_OK 711 && error != B_BAD_SCRIPT_SYNTAX) 712 continue; 713 714 BMessenger trackerWindow; 715 if (reply.FindMessenger("result", &trackerWindow) != B_OK) 716 continue; 717 718 if (isCustomFolder) { 719 // found a window with poses, ask for its path 720 message.MakeEmpty(); 721 message.what = B_GET_PROPERTY; 722 message.AddSpecifier("Path"); 723 message.AddSpecifier("Poses"); 724 message.AddSpecifier("Window", i); 725 726 reply.MakeEmpty(); 727 tracker.SendMessage(&message, &reply); 728 729 // go on with the next if this din't have a path 730 if (reply.what == B_MESSAGE_NOT_UNDERSTOOD) 731 continue; 732 733 entry_ref ref; 734 if (reply.FindRef("result", &ref) == B_OK) { 735 BEntry entry(&ref); 736 BPath path(&entry); 737 738 // these are not the paths you're looking for 739 if (currentPath != path) 740 continue; 741 } 742 } 743 744 trackerWindow.SendMessage(B_RESTORE_BACKGROUND_IMAGE); 745 } while (true); 746 } 747 } 748 749 750 void 751 BackgroundsView::_NotifyScreenPreflet() 752 { 753 BMessenger messenger("application/x-vnd.Haiku-Screen"); 754 if (messenger.IsValid()) 755 messenger.SendMessage(UPDATE_DESKTOP_COLOR_MSG); 756 } 757 758 759 int32 760 BackgroundsView::_NotifyThread(void* data) 761 { 762 BackgroundsView* view = (BackgroundsView*)data; 763 764 view->_NotifyServer(); 765 view->_NotifyScreenPreflet(); 766 return B_OK; 767 } 768 769 770 void 771 BackgroundsView::SaveSettings(void) 772 { 773 BPath path; 774 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) { 775 path.Append(SETTINGS_FILE); 776 BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); 777 778 BPoint point = Window()->Frame().LeftTop(); 779 if (fSettings.ReplacePoint("pos", point) != B_OK) 780 fSettings.AddPoint("pos", point); 781 782 entry_ref ref; 783 BEntry entry; 784 785 fPanel->GetPanelDirectory(&ref); 786 entry.SetTo(&ref); 787 entry.GetPath(&path); 788 if (fSettings.ReplaceString("paneldir", path.Path()) != B_OK) 789 fSettings.AddString("paneldir", path.Path()); 790 791 fFolderPanel->GetPanelDirectory(&ref); 792 entry.SetTo(&ref); 793 entry.GetPath(&path); 794 if (fSettings.ReplaceString("folderpaneldir", path.Path()) != B_OK) 795 fSettings.AddString("folderpaneldir", path.Path()); 796 797 fSettings.RemoveName("recentfolder"); 798 for (int32 i = 0; i < fPathList.CountItems(); i++) { 799 fSettings.AddString("recentfolder", fPathList.ItemAt(i)->Path()); 800 } 801 802 fSettings.Flatten(&file); 803 } 804 } 805 806 807 void 808 BackgroundsView::_LoadSettings() 809 { 810 fSettings.MakeEmpty(); 811 812 BPath path; 813 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 814 return; 815 816 path.Append(SETTINGS_FILE); 817 BFile file(path.Path(), B_READ_ONLY); 818 if (file.InitCheck() != B_OK) 819 return; 820 821 if (fSettings.Unflatten(&file) != B_OK) { 822 printf("Error unflattening settings file %s\n", path.Path()); 823 return; 824 } 825 826 PRINT_OBJECT(fSettings); 827 828 BString settingStr; 829 if (fSettings.FindString("paneldir", &settingStr) == B_OK) 830 fPanel->SetPanelDirectory(settingStr.String()); 831 832 if (fSettings.FindString("folderpaneldir", &settingStr) == B_OK) 833 fFolderPanel->SetPanelDirectory(settingStr.String()); 834 835 int32 index = 0; 836 while (fSettings.FindString("recentfolder", index, &settingStr) == B_OK) { 837 path.SetTo(settingStr.String()); 838 _AddRecentFolder(path); 839 index++; 840 } 841 842 fWorkspaceMenu->ItemAt(1)->SetMarked(true); 843 fWorkspaceMenu->SetTargetForItems(this); 844 845 PRINT(("Settings Loaded\n")); 846 } 847 848 849 void 850 BackgroundsView::WorkspaceActivated(uint32 oldWorkspaces, bool active) 851 { 852 _UpdateWithCurrent(); 853 } 854 855 856 void 857 BackgroundsView::_UpdatePreview() 858 { 859 bool imageEnabled = !(fImageMenu->FindItem(kMsgNoImage)->IsMarked()); 860 if (fPlacementMenu->IsEnabled() ^ imageEnabled) 861 fPlacementMenu->SetEnabled(imageEnabled); 862 863 bool textEnabled 864 = (fPlacementMenu->FindItem(kMsgManualPlacement)->IsMarked()) 865 && imageEnabled; 866 if (fXPlacementText->IsEnabled() ^ textEnabled) 867 fXPlacementText->SetEnabled(textEnabled); 868 869 if (fYPlacementText->IsEnabled() ^ textEnabled) 870 fYPlacementText->SetEnabled(textEnabled); 871 872 if (textEnabled && (strcmp(fXPlacementText->Text(), "") == 0)) { 873 fXPlacementText->SetText("0"); 874 fYPlacementText->SetText("0"); 875 } 876 if (!textEnabled) { 877 fXPlacementText->SetText(NULL); 878 fYPlacementText->SetText(NULL); 879 } 880 881 fXPlacementText->TextView()->MakeSelectable(textEnabled); 882 fYPlacementText->TextView()->MakeSelectable(textEnabled); 883 fXPlacementText->TextView()->MakeEditable(textEnabled); 884 fYPlacementText->TextView()->MakeEditable(textEnabled); 885 886 fPreview->ClearViewBitmap(); 887 888 int32 index = ((BGImageMenuItem*)fImageMenu->FindMarked())->ImageIndex(); 889 if (index >= 0) { 890 BBitmap* bitmap = GetImage(index)->GetBitmap(); 891 if (bitmap) { 892 BackgroundImage::BackgroundImageInfo* info 893 = new BackgroundImage::BackgroundImageInfo(0, index, 894 _FindPlacementMode(), BPoint(atoi(fXPlacementText->Text()), 895 atoi(fYPlacementText->Text())), 896 fIconLabelOutline->Value() == B_CONTROL_ON, 0, 0); 897 if (info->fMode == BackgroundImage::kAtOffset) { 898 fPreview->SetEnabled(true); 899 fPreview->fPoint.x = atoi(fXPlacementText->Text()); 900 fPreview->fPoint.y = atoi(fYPlacementText->Text()); 901 } else 902 fPreview->SetEnabled(false); 903 904 fPreview->fImageBounds = BRect(bitmap->Bounds()); 905 fCurrent->Show(info, fPreview); 906 907 delete info; 908 } 909 } else 910 fPreview->SetEnabled(false); 911 912 fPreview->SetViewColor(fPicker->ValueAsColor()); 913 fPreview->Invalidate(); 914 } 915 916 917 BackgroundImage::Mode 918 BackgroundsView::_FindPlacementMode() 919 { 920 BackgroundImage::Mode mode = BackgroundImage::kAtOffset; 921 922 if (fPlacementMenu->FindItem(kMsgCenterPlacement)->IsMarked()) 923 mode = BackgroundImage::kCentered; 924 925 if (fPlacementMenu->FindItem(kMsgScalePlacement)->IsMarked()) 926 mode = BackgroundImage::kScaledToFit; 927 928 if (fPlacementMenu->FindItem(kMsgManualPlacement)->IsMarked()) 929 mode = BackgroundImage::kAtOffset; 930 931 if (fPlacementMenu->FindItem(kMsgTilePlacement)->IsMarked()) 932 mode = BackgroundImage::kTiled; 933 934 return mode; 935 } 936 937 938 void 939 BackgroundsView::_UpdateButtons() 940 { 941 bool hasChanged = false; 942 if (fPicker->IsEnabled() 943 && fPicker->ValueAsColor() != BScreen().DesktopColor()) { 944 hasChanged = true; 945 } else if (fCurrentInfo) { 946 if ((fIconLabelOutline->Value() == B_CONTROL_ON) 947 ^ fCurrentInfo->fTextWidgetLabelOutline) { 948 hasChanged = true; 949 } else if (_FindPlacementMode() != fCurrentInfo->fMode) { 950 hasChanged = true; 951 } else if (fCurrentInfo->fImageIndex 952 != ((BGImageMenuItem*)fImageMenu->FindMarked())->ImageIndex()) { 953 hasChanged = true; 954 } else if (fCurrent->IsDesktop() 955 && ((fCurrentInfo->fWorkspace != B_ALL_WORKSPACES) 956 ^ (fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()))) 957 { 958 hasChanged = true; 959 } else if (fCurrentInfo->fImageIndex > -1 960 && fCurrentInfo->fMode == BackgroundImage::kAtOffset) { 961 BString oldString, newString; 962 oldString << (int)fCurrentInfo->fOffset.x; 963 if (oldString != BString(fXPlacementText->Text())) { 964 hasChanged = true; 965 } 966 oldString = ""; 967 oldString << (int)fCurrentInfo->fOffset.y; 968 if (oldString != BString(fYPlacementText->Text())) { 969 hasChanged = true; 970 } 971 } 972 } else if (fImageMenu->IndexOf(fImageMenu->FindMarked()) > 0) { 973 hasChanged = true; 974 } else if (fIconLabelOutline->Value() == B_CONTROL_OFF) { 975 hasChanged = true; 976 } 977 978 fApply->SetEnabled(hasChanged); 979 fRevert->SetEnabled(hasChanged); 980 } 981 982 983 void 984 BackgroundsView::RefsReceived(BMessage* message) 985 { 986 if (!message->HasRef("refs") && message->HasRef("dir_ref")) { 987 entry_ref dirRef; 988 if (message->FindRef("dir_ref", &dirRef) == B_OK) 989 message->AddRef("refs", &dirRef); 990 } 991 992 entry_ref ref; 993 int32 i = 0; 994 BMimeType imageType("image"); 995 BPath desktopPath; 996 find_directory(B_DESKTOP_DIRECTORY, &desktopPath); 997 998 while (message->FindRef("refs", i++, &ref) == B_OK) { 999 BPath path; 1000 BEntry entry(&ref, true); 1001 path.SetTo(&entry); 1002 BNode node(&entry); 1003 1004 if (node.IsFile()) { 1005 BMimeType refType; 1006 if (BMimeType::GuessMimeType(&ref, &refType) == B_OK 1007 && !imageType.Contains(&refType)) { 1008 continue; 1009 } 1010 1011 BGImageMenuItem* item; 1012 int32 index = AddImage(path); 1013 if (index >= 0) { 1014 item = _FindImageItem(index); 1015 fLastImageIndex = index; 1016 } else { 1017 const char* name = GetImage(-index - 1)->GetName(); 1018 item = new BGImageMenuItem(name, -index - 1, 1019 new BMessage(kMsgImageSelected)); 1020 _AddItem(item); 1021 item->SetTarget(this); 1022 fLastImageIndex = -index - 1; 1023 } 1024 1025 // An optional placement may have been sent 1026 int32 placement = 0; 1027 if (message->FindInt32("placement", &placement) == B_OK) { 1028 BMenuItem* item = fPlacementMenu->FindItem(placement); 1029 if (item) 1030 item->SetMarked(true); 1031 } 1032 item->SetMarked(true); 1033 BMessenger(this).SendMessage(kMsgImageSelected); 1034 } else if (node.IsDirectory()) { 1035 if (desktopPath == path) { 1036 fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->SetMarked(true); 1037 BMessenger(this).SendMessage(kMsgCurrentWorkspace); 1038 break; 1039 } 1040 1041 // Add the newly selected path as a recent folder, 1042 // removing the oldest entry if needed 1043 _AddRecentFolder(path, true); 1044 } 1045 } 1046 } 1047 1048 1049 static BPath* 1050 FindPath(BPath* currentPath, void* newPath) 1051 { 1052 BPath* pathToCheck = static_cast<BPath*>(newPath); 1053 int compare = ICompare(currentPath->Path(), pathToCheck->Path()); 1054 return compare == 0 ? currentPath : NULL; 1055 } 1056 1057 1058 void 1059 BackgroundsView::_AddRecentFolder(BPath path, bool notifyApp) 1060 { 1061 BPath* currentPath = fPathList.EachElement(FindPath, &path); 1062 BMenuItem* item; 1063 BMessage* folderSelectedMsg = new BMessage(kMsgFolderSelected); 1064 folderSelectedMsg->AddString("folderPath", path.Path()); 1065 1066 if (currentPath == NULL) { 1067 // "All Workspaces", "Current Workspace", "--", "Default folder", 1068 // "Other folder...", If only these 5 exist, 1069 // we need a new separator to add path specific recent folders. 1070 if (fWorkspaceMenu->CountItems() <= 5) 1071 fWorkspaceMenu->AddSeparatorItem(); 1072 // Maxed out the number of recent folders, remove the oldest entry 1073 if (fPathList.CountItems() == fRecentFoldersLimit) { 1074 fPathList.RemoveItemAt(0); 1075 fWorkspaceMenu->RemoveItem(6); 1076 } 1077 // Add the new recent folder 1078 BString folderMenuText(B_TRANSLATE("Folder: %path")); 1079 folderMenuText.ReplaceFirst("%path", path.Leaf()); 1080 item = new BMenuItem(folderMenuText.String(), folderSelectedMsg); 1081 fWorkspaceMenu->AddItem(item); 1082 fPathList.AddItem(new BPath(path)); 1083 item->SetTarget(this); 1084 } else { 1085 int32 itemIndex = fPathList.IndexOf(currentPath); 1086 item = fWorkspaceMenu->ItemAt(itemIndex + 6); 1087 } 1088 1089 item->SetMarked(true); 1090 1091 if (notifyApp) 1092 BMessenger(this).SendMessage(folderSelectedMsg); 1093 } 1094 1095 1096 int32 1097 BackgroundsView::AddImage(BPath path) 1098 { 1099 int32 count = fImageList.CountItems(); 1100 int32 index = 0; 1101 for (; index < count; index++) { 1102 Image* image = fImageList.ItemAt(index); 1103 if (image->GetPath() == path) 1104 return index; 1105 } 1106 1107 fImageList.AddItem(new Image(path)); 1108 return -index - 1; 1109 } 1110 1111 1112 Image* 1113 BackgroundsView::GetImage(int32 imageIndex) 1114 { 1115 return fImageList.ItemAt(imageIndex); 1116 } 1117 1118 1119 BGImageMenuItem* 1120 BackgroundsView::_FindImageItem(const int32 imageIndex) 1121 { 1122 if (imageIndex < 0) 1123 return (BGImageMenuItem*)fImageMenu->ItemAt(0); 1124 1125 int32 count = fImageMenu->CountItems() - 2; 1126 int32 index = 2; 1127 for (; index < count; index++) { 1128 BGImageMenuItem* image = (BGImageMenuItem*)fImageMenu->ItemAt(index); 1129 if (image->ImageIndex() == imageIndex) 1130 return image; 1131 } 1132 return NULL; 1133 } 1134 1135 1136 bool 1137 BackgroundsView::_AddItem(BGImageMenuItem* item) 1138 { 1139 int32 count = fImageMenu->CountItems() - 2; 1140 int32 index = 2; 1141 if (count < index) { 1142 fImageMenu->AddItem(new BSeparatorItem(), 1); 1143 count = fImageMenu->CountItems() - 2; 1144 } 1145 1146 for (; index < count; index++) { 1147 BGImageMenuItem* image = (BGImageMenuItem*)fImageMenu->ItemAt(index); 1148 int c = (BString(image->Label()).ICompare(BString(item->Label()))); 1149 if (c > 0) 1150 break; 1151 } 1152 return fImageMenu->AddItem(item, index); 1153 } 1154 1155 1156 void 1157 BackgroundsView::_SetDesktop(bool isDesktop) 1158 { 1159 fTopLeft->SetDesktop(isDesktop); 1160 fTop->SetDesktop(isDesktop); 1161 fTopRight->SetDesktop(isDesktop); 1162 fLeft->SetDesktop(isDesktop); 1163 fRight->SetDesktop(isDesktop); 1164 fBottomLeft->SetDesktop(isDesktop); 1165 fBottom->SetDesktop(isDesktop); 1166 fBottomRight->SetDesktop(isDesktop); 1167 1168 Invalidate(); 1169 } 1170 1171 1172 bool 1173 BackgroundsView::FoundPositionSetting() 1174 { 1175 return fFoundPositionSetting; 1176 } 1177 1178 1179 // #pragma mark - 1180 1181 1182 Preview::Preview() 1183 : 1184 BControl("PreView", NULL, NULL, B_WILL_DRAW | B_SUBPIXEL_PRECISE) 1185 { 1186 float aspectRatio = BScreen().Frame().Width() / BScreen().Frame().Height(); 1187 float previewWidth = be_control_look->DefaultLabelSpacing() * 20.0f; 1188 float previewHeight = ceil(previewWidth / aspectRatio); 1189 1190 ResizeTo(previewWidth, previewHeight); 1191 SetExplicitMinSize(BSize(previewWidth, previewHeight)); 1192 SetExplicitMaxSize(BSize(previewWidth, previewHeight)); 1193 } 1194 1195 1196 void 1197 Preview::AttachedToWindow() 1198 { 1199 rgb_color color = ViewColor(); 1200 BControl::AttachedToWindow(); 1201 SetViewColor(color); 1202 } 1203 1204 1205 void 1206 Preview::MouseDown(BPoint point) 1207 { 1208 if (IsEnabled() && Bounds().Contains(point)) { 1209 uint32 buttons; 1210 GetMouse(&point, &buttons); 1211 if (buttons & B_PRIMARY_MOUSE_BUTTON) { 1212 fOldPoint = point; 1213 SetTracking(true); 1214 BScreen().GetMode(&fMode); 1215 fXRatio = Bounds().Width() / fMode.virtual_width; 1216 fYRatio = Bounds().Height() / fMode.virtual_height; 1217 SetMouseEventMask(B_POINTER_EVENTS, 1218 B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY); 1219 1220 BCursor grabbingCursor(B_CURSOR_ID_GRABBING); 1221 SetViewCursor(&grabbingCursor); 1222 } 1223 } 1224 } 1225 1226 1227 void 1228 Preview::MouseUp(BPoint point) 1229 { 1230 if (IsTracking()) { 1231 SetTracking(false); 1232 BCursor grabCursor(B_CURSOR_ID_GRAB); 1233 SetViewCursor(&grabCursor); 1234 } 1235 } 1236 1237 1238 void 1239 Preview::MouseMoved(BPoint point, uint32 transit, const BMessage* message) 1240 { 1241 if (!IsTracking()) { 1242 BCursor cursor(IsEnabled() 1243 ? B_CURSOR_ID_GRAB : B_CURSOR_ID_SYSTEM_DEFAULT); 1244 SetViewCursor(&cursor); 1245 } else { 1246 float x, y; 1247 x = fPoint.x + (point.x - fOldPoint.x) / fXRatio; 1248 y = fPoint.y + (point.y - fOldPoint.y) / fYRatio; 1249 bool min, max, mustSend = false; 1250 min = (x > -fImageBounds.Width()); 1251 max = (x < fMode.virtual_width); 1252 if (min && max) { 1253 fOldPoint.x = point.x; 1254 fPoint.x = x; 1255 mustSend = true; 1256 } else { 1257 if (!min && fPoint.x > -fImageBounds.Width()) { 1258 fPoint.x = -fImageBounds.Width(); 1259 fOldPoint.x = point.x - (x - fPoint.x) * fXRatio; 1260 mustSend = true; 1261 } 1262 if (!max && fPoint.x < fMode.virtual_width) { 1263 fPoint.x = fMode.virtual_width; 1264 fOldPoint.x = point.x - (x - fPoint.x) * fXRatio; 1265 mustSend = true; 1266 } 1267 } 1268 1269 min = (y > -fImageBounds.Height()); 1270 max = (y < fMode.virtual_height); 1271 if (min && max) { 1272 fOldPoint.y = point.y; 1273 fPoint.y = y; 1274 mustSend = true; 1275 } else { 1276 if (!min && fPoint.y > -fImageBounds.Height()) { 1277 fPoint.y = -fImageBounds.Height(); 1278 fOldPoint.y = point.y - (y - fPoint.y) * fYRatio; 1279 mustSend = true; 1280 } 1281 if (!max && fPoint.y < fMode.virtual_height) { 1282 fPoint.y = fMode.virtual_height; 1283 fOldPoint.y = point.y - (y - fPoint.y) * fYRatio; 1284 mustSend = true; 1285 } 1286 } 1287 1288 if (mustSend) { 1289 BMessenger messenger(Parent()); 1290 messenger.SendMessage(kMsgUpdatePreviewPlacement); 1291 } 1292 } 1293 1294 BControl::MouseMoved(point, transit, message); 1295 } 1296 1297 1298 // #pragma mark - 1299 1300 1301 BGImageMenuItem::BGImageMenuItem(const char* label, int32 imageIndex, 1302 BMessage* message, char shortcut, uint32 modifiers) 1303 : BMenuItem(label, message, shortcut, modifiers), 1304 fImageIndex(imageIndex) 1305 { 1306 } 1307 1308 1309 // #pragma mark - 1310 1311 1312 FramePart::FramePart(int32 part) 1313 : 1314 BView(NULL, B_WILL_DRAW | B_FRAME_EVENTS), 1315 fFramePart(part), 1316 fIsDesktop(true) 1317 { 1318 _SetSizeAndAlignment(); 1319 } 1320 1321 1322 void 1323 FramePart::Draw(BRect rect) 1324 { 1325 rgb_color color = HighColor(); 1326 SetDrawingMode(B_OP_COPY); 1327 SetHighColor(Parent()->ViewColor()); 1328 1329 if (fIsDesktop) { 1330 switch (fFramePart) { 1331 case FRAME_TOP_LEFT: 1332 FillRect(rect); 1333 SetHighColor(160, 160, 160); 1334 FillRoundRect(BRect(0, 0, 8, 8), 3, 3); 1335 SetHighColor(96, 96, 96); 1336 StrokeRoundRect(BRect(0, 0, 8, 8), 3, 3); 1337 break; 1338 1339 case FRAME_TOP: 1340 SetHighColor(160, 160, 160); 1341 FillRect(BRect(0, 1, rect.right, 3)); 1342 SetHighColor(96, 96, 96); 1343 StrokeLine(BPoint(0, 0), BPoint(rect.right, 0)); 1344 SetHighColor(0, 0, 0); 1345 StrokeLine(BPoint(0, 4), BPoint(rect.right, 4)); 1346 break; 1347 1348 case FRAME_TOP_RIGHT: 1349 FillRect(rect); 1350 SetHighColor(160, 160, 160); 1351 FillRoundRect(BRect(-4, 0, 4, 8), 3, 3); 1352 SetHighColor(96, 96, 96); 1353 StrokeRoundRect(BRect(-4, 0, 4, 8), 3, 3); 1354 break; 1355 1356 case FRAME_LEFT_SIDE: 1357 SetHighColor(160, 160, 160); 1358 FillRect(BRect(1, 0, 3, rect.bottom)); 1359 SetHighColor(96, 96, 96); 1360 StrokeLine(BPoint(0, 0), BPoint(0, rect.bottom)); 1361 SetHighColor(0, 0, 0); 1362 StrokeLine(BPoint(4, 0), BPoint(4, rect.bottom)); 1363 break; 1364 1365 case FRAME_RIGHT_SIDE: 1366 SetHighColor(160, 160, 160); 1367 FillRect(BRect(1, 0, 3, rect.bottom)); 1368 SetHighColor(0, 0, 0); 1369 StrokeLine(BPoint(0, 0), BPoint(0, rect.bottom)); 1370 SetHighColor(96, 96, 96); 1371 StrokeLine(BPoint(4, 0), BPoint(4, rect.bottom)); 1372 break; 1373 1374 case FRAME_BOTTOM_LEFT: 1375 FillRect(rect); 1376 SetHighColor(160, 160, 160); 1377 FillRoundRect(BRect(0, -4, 8, 4), 3, 3); 1378 SetHighColor(96, 96, 96); 1379 StrokeRoundRect(BRect(0, -4, 8, 4), 3, 3); 1380 break; 1381 1382 case FRAME_BOTTOM: 1383 SetHighColor(160, 160, 160); 1384 FillRect(BRect(0, 1, rect.right, 3)); 1385 SetHighColor(0, 0, 0); 1386 StrokeLine(BPoint(0, 0), BPoint(rect.right, 0)); 1387 SetHighColor(96, 96, 96); 1388 StrokeLine(BPoint(0, 4), BPoint(rect.right, 4)); 1389 SetHighColor(228, 0, 0); 1390 StrokeLine(BPoint(5, 2), BPoint(7, 2)); 1391 break; 1392 1393 case FRAME_BOTTOM_RIGHT: 1394 FillRect(rect); 1395 SetHighColor(160, 160, 160); 1396 FillRoundRect(BRect(-4, -4, 4, 4), 3, 3); 1397 SetHighColor(96, 96, 96); 1398 StrokeRoundRect(BRect(-4, -4, 4, 4), 3, 3); 1399 break; 1400 1401 default: 1402 break; 1403 } 1404 } else { 1405 switch (fFramePart) { 1406 case FRAME_TOP_LEFT: 1407 SetHighColor(152, 152, 152); 1408 StrokeLine(BPoint(0, 0), BPoint(0, 12)); 1409 StrokeLine(BPoint(0, 0), BPoint(4, 0)); 1410 StrokeLine(BPoint(3, 12), BPoint(3, 12)); 1411 SetHighColor(255, 203, 0); 1412 FillRect(BRect(1, 1, 3, 9)); 1413 SetHighColor(240, 240, 240); 1414 StrokeLine(BPoint(1, 12), BPoint(1, 10)); 1415 StrokeLine(BPoint(2, 10), BPoint(3, 10)); 1416 SetHighColor(200, 200, 200); 1417 StrokeLine(BPoint(2, 12), BPoint(2, 11)); 1418 StrokeLine(BPoint(3, 11), BPoint(3, 11)); 1419 break; 1420 1421 case FRAME_TOP: 1422 FillRect(BRect(54, 0, rect.right, 8)); 1423 SetHighColor(255, 203, 0); 1424 FillRect(BRect(0, 1, 52, 9)); 1425 SetHighColor(152, 152, 152); 1426 StrokeLine(BPoint(0, 0), BPoint(53, 0)); 1427 StrokeLine(BPoint(53, 1), BPoint(53, 9)); 1428 StrokeLine(BPoint(54, 9), BPoint(rect.right, 9)); 1429 SetHighColor(240, 240, 240); 1430 StrokeLine(BPoint(0, 10), BPoint(rect.right, 10)); 1431 SetHighColor(200, 200, 200); 1432 StrokeLine(BPoint(0, 11), BPoint(rect.right, 11)); 1433 SetHighColor(152, 152, 152); 1434 StrokeLine(BPoint(0, 12), BPoint(rect.right, 12)); 1435 break; 1436 1437 case FRAME_TOP_RIGHT: 1438 FillRect(BRect(0, 0, 3, 8)); 1439 SetHighColor(152, 152, 152); 1440 StrokeLine(BPoint(0, 12), BPoint(0, 12)); 1441 StrokeLine(BPoint(0, 9), BPoint(3, 9)); 1442 StrokeLine(BPoint(3, 12), BPoint(3, 9)); 1443 SetHighColor(240, 240, 240); 1444 StrokeLine(BPoint(0, 10), BPoint(2, 10)); 1445 StrokeLine(BPoint(1, 12), BPoint(1, 12)); 1446 SetHighColor(200, 200, 200); 1447 StrokeLine(BPoint(2, 12), BPoint(2, 12)); 1448 StrokeLine(BPoint(0, 11), BPoint(2, 11)); 1449 break; 1450 1451 case FRAME_LEFT_SIDE: 1452 case FRAME_RIGHT_SIDE: 1453 SetHighColor(152, 152, 152); 1454 StrokeLine(BPoint(0, 0), BPoint(0, rect.bottom)); 1455 SetHighColor(240, 240, 240); 1456 StrokeLine(BPoint(1, 0), BPoint(1, rect.bottom)); 1457 SetHighColor(200, 200, 200); 1458 StrokeLine(BPoint(2, 0), BPoint(2, rect.bottom)); 1459 SetHighColor(152, 152, 152); 1460 StrokeLine(BPoint(3, 0), BPoint(3, rect.bottom)); 1461 break; 1462 1463 case FRAME_BOTTOM_LEFT: 1464 SetHighColor(152, 152, 152); 1465 StrokeLine(BPoint(0, 0), BPoint(0, 3)); 1466 StrokeLine(BPoint(0, 3), BPoint(3, 3)); 1467 StrokeLine(BPoint(3, 0), BPoint(3, 0)); 1468 SetHighColor(240, 240, 240); 1469 StrokeLine(BPoint(1, 0), BPoint(1, 2)); 1470 StrokeLine(BPoint(3, 1), BPoint(3, 1)); 1471 SetHighColor(200, 200, 200); 1472 StrokeLine(BPoint(2, 0), BPoint(2, 2)); 1473 StrokeLine(BPoint(3, 2), BPoint(3, 2)); 1474 break; 1475 1476 case FRAME_BOTTOM: 1477 SetHighColor(152, 152, 152); 1478 StrokeLine(BPoint(0, 0), BPoint(rect.right, 0)); 1479 SetHighColor(240, 240, 240); 1480 StrokeLine(BPoint(0, 1), BPoint(rect.right, 1)); 1481 SetHighColor(200, 200, 200); 1482 StrokeLine(BPoint(0, 2), BPoint(rect.right, 2)); 1483 SetHighColor(152, 152, 152); 1484 StrokeLine(BPoint(0, 3), BPoint(rect.right, 3)); 1485 break; 1486 1487 case FRAME_BOTTOM_RIGHT: 1488 SetHighColor(152, 152, 152); 1489 StrokeLine(BPoint(0, 0), BPoint(0, 0)); 1490 SetHighColor(240, 240, 240); 1491 StrokeLine(BPoint(1, 0), BPoint(1, 1)); 1492 StrokeLine(BPoint(0, 1), BPoint(0, 1)); 1493 SetHighColor(200, 200, 200); 1494 StrokeLine(BPoint(2, 0), BPoint(2, 2)); 1495 StrokeLine(BPoint(0, 2), BPoint(1, 2)); 1496 SetHighColor(152, 152, 152); 1497 StrokeLine(BPoint(3, 0), BPoint(3, 3)); 1498 StrokeLine(BPoint(0, 3), BPoint(2, 3)); 1499 break; 1500 1501 default: 1502 break; 1503 } 1504 } 1505 1506 SetHighColor(color); 1507 } 1508 1509 1510 void 1511 FramePart::SetDesktop(bool isDesktop) 1512 { 1513 fIsDesktop = isDesktop; 1514 1515 _SetSizeAndAlignment(); 1516 Invalidate(); 1517 } 1518 1519 1520 void 1521 FramePart::_SetSizeAndAlignment() 1522 { 1523 if (fIsDesktop) { 1524 switch (fFramePart) { 1525 case FRAME_TOP_LEFT: 1526 SetExplicitMinSize(BSize(4, 4)); 1527 SetExplicitMaxSize(BSize(4, 4)); 1528 break; 1529 1530 case FRAME_TOP: 1531 SetExplicitMinSize(BSize(1, 4)); 1532 SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 4)); 1533 break; 1534 1535 case FRAME_TOP_RIGHT: 1536 SetExplicitMinSize(BSize(4, 4)); 1537 SetExplicitMaxSize(BSize(4, 4)); 1538 break; 1539 1540 case FRAME_LEFT_SIDE: 1541 SetExplicitMinSize(BSize(4, 1)); 1542 SetExplicitMaxSize(BSize(4, B_SIZE_UNLIMITED)); 1543 break; 1544 1545 case FRAME_RIGHT_SIDE: 1546 SetExplicitMinSize(BSize(4, 1)); 1547 SetExplicitMaxSize(BSize(4, B_SIZE_UNLIMITED)); 1548 break; 1549 1550 case FRAME_BOTTOM_LEFT: 1551 SetExplicitMinSize(BSize(4, 4)); 1552 SetExplicitMaxSize(BSize(4, 4)); 1553 break; 1554 1555 case FRAME_BOTTOM: 1556 SetExplicitMinSize(BSize(1, 4)); 1557 SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 4)); 1558 break; 1559 1560 case FRAME_BOTTOM_RIGHT: 1561 SetExplicitMaxSize(BSize(4, 4)); 1562 SetExplicitMinSize(BSize(4, 4)); 1563 break; 1564 1565 default: 1566 break; 1567 } 1568 } else { 1569 switch (fFramePart) { 1570 case FRAME_TOP_LEFT: 1571 SetExplicitMinSize(BSize(3, 12)); 1572 SetExplicitMaxSize(BSize(3, 12)); 1573 break; 1574 1575 case FRAME_TOP: 1576 SetExplicitMinSize(BSize(1, 12)); 1577 SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 12)); 1578 break; 1579 1580 case FRAME_TOP_RIGHT: 1581 SetExplicitMinSize(BSize(3, 12)); 1582 SetExplicitMaxSize(BSize(3, 12)); 1583 break; 1584 1585 case FRAME_LEFT_SIDE: 1586 SetExplicitMinSize(BSize(3, 1)); 1587 SetExplicitMaxSize(BSize(3, B_SIZE_UNLIMITED)); 1588 break; 1589 1590 case FRAME_RIGHT_SIDE: 1591 SetExplicitMinSize(BSize(3, 1)); 1592 SetExplicitMaxSize(BSize(3, B_SIZE_UNLIMITED)); 1593 break; 1594 1595 case FRAME_BOTTOM_LEFT: 1596 SetExplicitMinSize(BSize(3, 3)); 1597 SetExplicitMaxSize(BSize(3, 3)); 1598 break; 1599 1600 case FRAME_BOTTOM: 1601 SetExplicitMinSize(BSize(1, 3)); 1602 SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 3)); 1603 break; 1604 1605 case FRAME_BOTTOM_RIGHT: 1606 SetExplicitMaxSize(BSize(3, 3)); 1607 SetExplicitMinSize(BSize(3, 3)); 1608 break; 1609 1610 default: 1611 break; 1612 } 1613 } 1614 1615 switch (fFramePart) { 1616 case FRAME_TOP_LEFT: 1617 SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT, B_ALIGN_BOTTOM)); 1618 break; 1619 1620 case FRAME_TOP: 1621 SetExplicitAlignment(BAlignment(B_ALIGN_CENTER, B_ALIGN_BOTTOM)); 1622 break; 1623 1624 case FRAME_TOP_RIGHT: 1625 SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_BOTTOM)); 1626 break; 1627 1628 case FRAME_LEFT_SIDE: 1629 SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT, B_ALIGN_MIDDLE)); 1630 break; 1631 1632 case FRAME_RIGHT_SIDE: 1633 SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_MIDDLE)); 1634 break; 1635 1636 case FRAME_BOTTOM_LEFT: 1637 SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT, B_ALIGN_TOP)); 1638 break; 1639 1640 case FRAME_BOTTOM: 1641 SetExplicitAlignment(BAlignment(B_ALIGN_CENTER, B_ALIGN_TOP)); 1642 break; 1643 1644 case FRAME_BOTTOM_RIGHT: 1645 SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP)); 1646 break; 1647 1648 default: 1649 break; 1650 } 1651 } 1652 1653