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
BackgroundsView()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
~BackgroundsView()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
AllAttached()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
MessageReceived(BMessage * message)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
_LoadDesktopFolder()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
_LoadDefaultFolder()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
_LoadRecentFolder(BPath path)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
_LoadFolder(bool isDesktop)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
_UpdateWithCurrent(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
_Save()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
_NotifyServer()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
_NotifyScreenPreflet()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
_NotifyThread(void * data)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
SaveSettings(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
_LoadSettings()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
WorkspaceActivated(uint32 oldWorkspaces,bool active)850 BackgroundsView::WorkspaceActivated(uint32 oldWorkspaces, bool active)
851 {
852 _UpdateWithCurrent();
853 }
854
855
856 void
_UpdatePreview()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
_FindPlacementMode()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
_UpdateButtons()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
RefsReceived(BMessage * message)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*
FindPath(BPath * currentPath,void * newPath)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
_AddRecentFolder(BPath path,bool notifyApp)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
AddImage(BPath path)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*
GetImage(int32 imageIndex)1113 BackgroundsView::GetImage(int32 imageIndex)
1114 {
1115 return fImageList.ItemAt(imageIndex);
1116 }
1117
1118
1119 BGImageMenuItem*
_FindImageItem(const int32 imageIndex)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
_AddItem(BGImageMenuItem * item)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
_SetDesktop(bool isDesktop)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
FoundPositionSetting()1173 BackgroundsView::FoundPositionSetting()
1174 {
1175 return fFoundPositionSetting;
1176 }
1177
1178
1179 // #pragma mark -
1180
1181
Preview()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
AttachedToWindow()1197 Preview::AttachedToWindow()
1198 {
1199 rgb_color color = ViewColor();
1200 BControl::AttachedToWindow();
1201 SetViewColor(color);
1202 }
1203
1204
1205 void
MouseDown(BPoint point)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
MouseUp(BPoint point)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
MouseMoved(BPoint point,uint32 transit,const BMessage * message)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
BGImageMenuItem(const char * label,int32 imageIndex,BMessage * message,char shortcut,uint32 modifiers)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
FramePart(int32 part)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
Draw(BRect rect)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
SetDesktop(bool isDesktop)1511 FramePart::SetDesktop(bool isDesktop)
1512 {
1513 fIsDesktop = isDesktop;
1514
1515 _SetSizeAndAlignment();
1516 Invalidate();
1517 }
1518
1519
1520 void
_SetSizeAndAlignment()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