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