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