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