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