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