xref: /haiku/src/preferences/backgrounds/BackgroundsView.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 /*
2  * Copyright 2002-2007, 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  */
9 
10 
11 #include "BackgroundsView.h"
12 #include "ImageFilePanel.h"
13 
14 #include <OS.h>
15 #include <MenuField.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <StorageKit.h>
19 #include <Background.h>
20 #include <Window.h>
21 #include <Messenger.h>
22 #include <Bitmap.h>
23 #include <Point.h>
24 #include <TranslationKit.h>
25 #include <PopUpMenu.h>
26 
27 
28 static const uint32 kMsgApplySettings = 'aply';
29 static const uint32 kMsgRevertSettings = 'rvrt';
30 
31 static const uint32 kMsgUpdateColor = 'upcl';
32 static const uint32 kMsgAllWorkspaces = 'alwk';
33 static const uint32 kMsgCurrentWorkspace = 'crwk';
34 static const uint32 kMsgDefaultFolder = 'dffl';
35 static const uint32 kMsgOtherFolder = 'otfl';
36 static const uint32 kMsgNoImage = 'noim';
37 static const uint32 kMsgOtherImage = 'otim';
38 static const uint32 kMsgImageSelected = 'imsl';
39 static const uint32 kMsgFolderSelected = 'flsl';
40 
41 static const uint32 kMsgCenterPlacement = 'cnpl';
42 static const uint32 kMsgManualPlacement = 'mnpl';
43 static const uint32 kMsgScalePlacement = 'scpl';
44 static const uint32 kMsgTilePlacement = 'tlpl';
45 static const uint32 kMsgIconLabelBackground = 'ilcb';
46 
47 static const uint32 kMsgImagePlacement = 'xypl';
48 static const uint32 kMsgUpdatePreviewPlacement = 'pvpl';
49 
50 
51 const uint8 kHandCursorData[68] = {
52 	16, 1, 2, 2,
53 
54 	0, 0,		// 0000000000000000
55 	7, 128,		// 0000011110000000
56 	61, 112,		// 0011110101110000
57 	37, 40,		// 0010010100101000
58 	36, 168,		// 0010010010101000
59 	18, 148,		// 0001001010010100
60 	18, 84,		// 0001001001010100
61 	9, 42,		// 0000100100101010
62 	8, 1,		// 0000100000000001
63 	60, 1,		// 0011110000000001
64 	76, 1,		// 0100110000000001
65 	66, 1,		// 0100001000000001
66 	48, 1,		// 0011000000000001
67 	12, 1,		// 0000110000000001
68 	2, 0,		// 0000001000000000
69 	1, 0,		// 0000000100000000
70 
71 	0, 0,		// 0000000000000000
72 	7, 128,		// 0000011110000000
73 	63, 240,		// 0011111111110000
74 	63, 248,		// 0011111111111000
75 	63, 248,		// 0011111111111000
76 	31, 252,		// 0001111111111100
77 	31, 252,		// 0001111111111100
78 	15, 254,		// 0000111111111110
79 	15, 255,		// 0000111111111111
80 	63, 255,		// 0011111111111111
81 	127, 255,	// 0111111111111111
82 	127, 255,	// 0111111111111111
83 	63, 255,		// 0011111111111111
84 	15, 255,		// 0000111111111111
85 	3, 254,		// 0000001111111110
86 	1, 248		// 0000000111111000
87 };
88 
89 
90 BackgroundsView::BackgroundsView(BRect frame, const char *name, int32 resize,
91 	int32 flags)
92 	: BBox(frame, name, resize, flags | B_WILL_DRAW | B_FRAME_EVENTS, B_NO_BORDER),
93 	fCurrent(NULL),
94 	fCurrentInfo(NULL),
95 	fLastImageIndex(-1),
96 	fPathList(1, true),
97 	fImageList(1, true)
98 {
99 	// we need the "Current Workspace" first to get its height
100 
101 	BMenuItem *menuItem;
102 	fWorkspaceMenu = new BPopUpMenu("pick one");
103 	fWorkspaceMenu->AddItem(menuItem = new BMenuItem("All Workspaces",
104 		new BMessage(kMsgAllWorkspaces)));
105 	fWorkspaceMenu->AddItem(menuItem = new BMenuItem("Current Workspace",
106 		new BMessage(kMsgCurrentWorkspace)));
107 	menuItem->SetMarked(true);
108 	fLastWorkspaceIndex = fWorkspaceMenu->IndexOf(fWorkspaceMenu->FindMarked());
109 	fWorkspaceMenu->AddSeparatorItem();
110 	fWorkspaceMenu->AddItem(menuItem = new BMenuItem("Default folder",
111 		new BMessage(kMsgDefaultFolder)));
112 	fWorkspaceMenu->AddItem(menuItem = new BMenuItem("Other folder" B_UTF8_ELLIPSIS,
113 		new BMessage(kMsgOtherFolder)));
114 
115 	BMenuField *workspaceMenuField = new BMenuField(BRect(0, 0, 130, 18),
116 		"workspaceMenuField", NULL, fWorkspaceMenu, true);
117 	workspaceMenuField->ResizeToPreferred();
118 
119 	/* the preview box */
120 
121 	BFont font(be_plain_font);
122 	font_height fontHeight;
123 	font.GetHeight(&fontHeight);
124 
125 	fPreview = new PreviewBox(BRect(10, 8.0 + workspaceMenuField->Bounds().Height() / 2.0f
126 		- ceilf(fontHeight.ascent + fontHeight.descent) / 2.0f, 160, 180), "preview");
127 	fPreview->SetFont(&font);
128 	fPreview->SetLabel("Preview");
129 	AddChild(fPreview);
130 
131 	BRect rect(10, fPreview->Bounds().bottom - 30, 70, fPreview->Bounds().bottom - 10);
132 	fXPlacementText = new BTextControl(rect, "xPlacementText", "X:", NULL,
133 		new BMessage(kMsgImagePlacement), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
134 	fXPlacementText->SetDivider(fXPlacementText->StringWidth(fXPlacementText->Label()) + 4.0f);
135 	fXPlacementText->TextView()->SetMaxBytes(5);
136 	float width, height;
137 	fXPlacementText->GetPreferredSize(&width, &height);
138 	float delta = fXPlacementText->Bounds().Height() - height;
139 	fXPlacementText->MoveBy(0, delta);
140 	fXPlacementText->ResizeTo(fXPlacementText->Bounds().Width(), height);
141 	fPreview->AddChild(fXPlacementText);
142 
143 	rect.OffsetBy(70, delta);
144 	fYPlacementText = new BTextControl(rect, "yPlacementText", "Y:", NULL,
145 		new BMessage(kMsgImagePlacement), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
146 	fYPlacementText->SetDivider(fYPlacementText->StringWidth(fYPlacementText->Label()) + 4.0f);
147 	fYPlacementText->TextView()->SetMaxBytes(5);
148 	fXPlacementText->ResizeTo(fYPlacementText->Bounds().Width(), height);
149 	fPreview->AddChild(fYPlacementText);
150 
151 	for (int32 i = 0; i < 256; i++) {
152 		if ((i < '0' || i > '9') && i != '-') {
153 			fXPlacementText->TextView()->DisallowChar(i);
154 			fYPlacementText->TextView()->DisallowChar(i);
155 		}
156 	}
157 
158 	fPreView = new PreView(BRect(15, 25, 135, 115), "preView",
159 		B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_SUBPIXEL_PRECISE);
160 	fPreview->AddChild(fPreView);
161 
162 	/* the right box */
163 
164 	BBox *rightbox = new BBox(BRect(fPreview->Frame().right + 10,
165 		7, Frame().right - 10, fPreview->Frame().bottom),
166 		"rightbox");
167 	rightbox->SetLabel(workspaceMenuField);
168 	AddChild(rightbox);
169 
170 	float offset = be_plain_font->StringWidth("Placement:") + 5;
171 	rect.Set(10, 0, rightbox->Bounds().right - 10, 30);
172 #ifdef __HAIKU__
173 	rect.top = 8 + rightbox->InnerFrame().top;
174 #else
175 	rect.top = 5 + workspaceMenuField->Bounds().Height();
176 	rect.bottom = rect.top + workspaceMenuField->Bounds().Height();
177 #endif
178 
179 	fImageMenu = new BPopUpMenu("pick one");
180 	fImageMenu->AddItem(new BGImageMenuItem("None", -1, new BMessage(kMsgNoImage)));
181 	fImageMenu->AddSeparatorItem();
182 	fImageMenu->AddItem(new BMenuItem("Other" B_UTF8_ELLIPSIS, new BMessage(kMsgOtherImage)));
183 
184 	BMenuField *imageMenuField = new BMenuField(rect, "imageMenuField",
185 		"Image:", fImageMenu);
186 	imageMenuField->SetDivider(offset);
187 	imageMenuField->SetAlignment(B_ALIGN_RIGHT);
188 	imageMenuField->ResizeToPreferred();
189 	rightbox->AddChild(imageMenuField);
190 
191 	fPlacementMenu = new BPopUpMenu("pick one");
192 	fPlacementMenu->AddItem(new BMenuItem("Manual",
193 		new BMessage(kMsgManualPlacement)));
194 	fPlacementMenu->AddItem(new BMenuItem("Center",
195 		new BMessage(kMsgCenterPlacement)));
196 	fPlacementMenu->AddItem(new BMenuItem("Scale to fit",
197 		new BMessage(kMsgScalePlacement)));
198 	fPlacementMenu->AddItem(new BMenuItem("Tile",
199 		new BMessage(kMsgTilePlacement)));
200 
201 	rect.OffsetBy(0, imageMenuField->Bounds().Height() + 5);
202 	BMenuField *placementMenuField = new BMenuField(rect, "placementMenuField",
203 		"Placement:", fPlacementMenu);
204 	placementMenuField->SetDivider(offset);
205 	placementMenuField->SetAlignment(B_ALIGN_RIGHT);
206 	placementMenuField->ResizeToPreferred();
207 	rightbox->AddChild(placementMenuField);
208 
209 	rect.OffsetBy(offset, placementMenuField->Bounds().Height() + 5);
210 	fIconLabelBackground = new BCheckBox(rect, "iconLabelBackground",
211 		"Icon label background", new BMessage(kMsgIconLabelBackground));
212 	fIconLabelBackground->SetValue(B_CONTROL_ON);
213 	fIconLabelBackground->ResizeToPreferred();
214 	rightbox->AddChild(fIconLabelBackground);
215 
216 	rect.top += fIconLabelBackground->Bounds().Height() + 15;
217 	fPicker = new BColorControl(BPoint(10, rect.top), B_CELLS_32x8, 5.0, "Picker",
218 		new BMessage(kMsgUpdateColor));
219 	rightbox->AddChild(fPicker);
220 
221 	float xDelta = max_c(fIconLabelBackground->Frame().right, fPicker->Frame().right)
222 		+ 10.0f - rightbox->Bounds().Width();
223 	delta = fPicker->Frame().bottom + 10.0f - rightbox->Bounds().Height();
224 
225 	rightbox->ResizeBy(xDelta, delta);
226 	fPreview->ResizeBy(0, delta);
227 
228 	// we're not yet attached to a view, so we need to move them manually
229 	fXPlacementText->MoveBy(0, delta);
230 	fYPlacementText->MoveBy(0, delta);
231 
232 	fRevert = new BButton(BRect(fPreview->Frame().left, fPreview->Frame().bottom + 10,
233 		fPreview->Frame().left + 80, Frame().bottom - 10), "RevertButton",
234 		"Revert", new BMessage(kMsgRevertSettings), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM,
235 		B_WILL_DRAW | B_NAVIGABLE);
236 	fRevert->ResizeToPreferred();
237 	AddChild(fRevert);
238 
239 	fApply = new BButton(BRect(rightbox->Frame().right, fPreview->Frame().bottom
240 		+ 10, rightbox->Frame().right, 110), "ApplyButton", "Apply",
241 		new BMessage(kMsgApplySettings), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM,
242 		B_WILL_DRAW | B_NAVIGABLE);
243 	fApply->ResizeToPreferred();
244 	fApply->MoveBy(-fApply->Bounds().Width(), 0);
245 	AddChild(fApply);
246 
247 	ResizeTo(rightbox->Frame().right + 10, fApply->Frame().bottom + 10);
248 }
249 
250 
251 BackgroundsView::~BackgroundsView()
252 {
253 	delete fPanel;
254 	delete fFolderPanel;
255 }
256 
257 
258 void
259 BackgroundsView::GetPreferredSize(float* _width, float* _height)
260 {
261 	if (_width)
262 		*_width = fApply->Frame().right + 10;
263 	if (_height)
264 		*_height = fApply->Frame().bottom + 10;
265 }
266 
267 
268 void
269 BackgroundsView::AllAttached()
270 {
271 	fPlacementMenu->SetTargetForItems(this);
272 	fImageMenu->SetTargetForItems(this);
273 	fWorkspaceMenu->SetTargetForItems(this);
274 	fXPlacementText->SetTarget(this);
275 	fYPlacementText->SetTarget(this);
276 	fIconLabelBackground->SetTarget(this);
277 	fPicker->SetTarget(this);
278 	fApply->SetTarget(this);
279 	fRevert->SetTarget(this);
280 
281 	fPanel = new ImageFilePanel(B_OPEN_PANEL, new BMessenger(this), NULL,
282 		B_FILE_NODE, false, NULL, new CustomRefFilter(true));
283 	fPanel->SetButtonLabel(B_DEFAULT_BUTTON, "Select");
284 
285 	fFolderPanel = new BFilePanel(B_OPEN_PANEL, new BMessenger(this), NULL,
286 		B_DIRECTORY_NODE, false, NULL, new CustomRefFilter(false));
287 	fFolderPanel->SetButtonLabel(B_DEFAULT_BUTTON, "Select");
288 
289 	Window()->ResizeTo(Frame().Width(), Frame().Height());
290 
291 	LoadSettings();
292 	LoadDesktopFolder();
293 }
294 
295 
296 void
297 BackgroundsView::MessageReceived(BMessage *msg)
298 {
299 	switch (msg->what) {
300 		case B_SIMPLE_DATA:
301 		case B_REFS_RECEIVED:
302 			RefsReceived(msg);
303 			break;
304 
305 		case kMsgUpdatePreviewPlacement:
306 		{
307 			BString xstring, ystring;
308 			xstring << (int)fPreView->fPoint.x;
309 			ystring << (int)fPreView->fPoint.y;
310 			fXPlacementText->SetText(xstring.String());
311 			fYPlacementText->SetText(ystring.String());
312 			UpdatePreview();
313 			UpdateButtons();
314 			break;
315 		}
316 
317 		case kMsgManualPlacement:
318 			UpdatePreview();
319 			UpdateButtons();
320 			break;
321 
322 		case kMsgTilePlacement:
323 		case kMsgScalePlacement:
324 		case kMsgCenterPlacement:
325 			UpdatePreview();
326 			UpdateButtons();
327 			break;
328 
329 		case kMsgIconLabelBackground:
330 			UpdateButtons();
331 			break;
332 
333 		case kMsgUpdateColor:
334 		case kMsgImagePlacement:
335 			UpdatePreview();
336 			UpdateButtons();
337 			break;
338 
339 		case kMsgCurrentWorkspace:
340 		case kMsgAllWorkspaces:
341 			fImageMenu->FindItem(kMsgNoImage)->SetLabel("None");
342 			fLastWorkspaceIndex = fWorkspaceMenu->IndexOf(
343 				fWorkspaceMenu->FindMarked());
344 			if (!fCurrent->IsDesktop()) {
345 				fPreview->SetDesktop(true);
346 				LoadDesktopFolder();
347 			} else
348 				UpdateButtons();
349 			break;
350 
351 		case kMsgDefaultFolder:
352 			fImageMenu->FindItem(kMsgNoImage)->SetLabel("None");
353 			fLastWorkspaceIndex = fWorkspaceMenu->IndexOf(
354 				fWorkspaceMenu->FindMarked());
355 			fPreview->SetDesktop(false);
356 			LoadDefaultFolder();
357 			break;
358 
359 		case kMsgOtherFolder:
360 			fFolderPanel->Show();
361 			break;
362 
363 		case kMsgOtherImage:
364 			fPanel->Show();
365 			break;
366 
367 		case B_CANCEL:
368 		{
369 			PRINT(("cancel received\n"));
370 			void* pointer;
371 			msg->FindPointer("source", &pointer);
372 			if (pointer == fPanel) {
373 				if (fLastImageIndex >= 0)
374 					FindImageItem(fLastImageIndex)->SetMarked(true);
375 				else
376 					fImageMenu->ItemAt(0)->SetMarked(true);
377 			} else if (pointer == fFolderPanel) {
378 				if (fLastWorkspaceIndex >= 0)
379 					fWorkspaceMenu->ItemAt(fLastWorkspaceIndex)->SetMarked(true);
380 			}
381 			break;
382 		}
383 
384 		case kMsgImageSelected:
385 		case kMsgNoImage:
386 			fLastImageIndex = ((BGImageMenuItem*)fImageMenu->FindMarked())->ImageIndex();
387 			UpdatePreview();
388 			UpdateButtons();
389 			break;
390 
391 		case kMsgFolderSelected:
392 			fImageMenu->FindItem(kMsgNoImage)->SetLabel("Default");
393 			fLastWorkspaceIndex = fWorkspaceMenu->IndexOf(
394 				fWorkspaceMenu->FindMarked());
395 			fPreview->SetDesktop(false);
396 			LoadRecentFolder(*fPathList.ItemAt(fWorkspaceMenu->IndexOf(
397 				fWorkspaceMenu->FindMarked()) - 6));
398 			break;
399 
400 		case kMsgApplySettings:
401 		{
402 			Save();
403 
404 			//NotifyServer();
405 			thread_id notify_thread;
406 			notify_thread = spawn_thread(BackgroundsView::NotifyThread, "notifyServer",
407 				B_NORMAL_PRIORITY, this);
408 			resume_thread(notify_thread);
409 			UpdateButtons();
410 			break;
411 		}
412 		case kMsgRevertSettings:
413 			UpdateWithCurrent();
414 			break;
415 
416 		default:
417 			BView::MessageReceived(msg);
418 			break;
419 	}
420 }
421 
422 
423 void
424 BackgroundsView::LoadDesktopFolder()
425 {
426 	BPath path;
427 	if (find_directory(B_DESKTOP_DIRECTORY, &path) == B_OK) {
428 		status_t err;
429 		err = get_ref_for_path(path.Path(), &fCurrentRef);
430 		if (err != B_OK)
431 			printf("error in LoadDesktopSettings\n");
432 		LoadFolder(true);
433 	}
434 }
435 
436 
437 void
438 BackgroundsView::LoadDefaultFolder()
439 {
440 	BPath path;
441 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
442 		BString pathString = path.Path();
443 		pathString << "/Tracker/DefaultFolderTemplate";
444 		status_t err;
445 		err = get_ref_for_path(pathString.String(), &fCurrentRef);
446 		if (err != B_OK)
447 			printf("error in LoadDefaultFolderSettings\n");
448 		LoadFolder(false);
449 	}
450 }
451 
452 
453 void
454 BackgroundsView::LoadRecentFolder(BPath path)
455 {
456 	status_t err;
457 	err = get_ref_for_path(path.Path(), &fCurrentRef);
458 	if (err != B_OK)
459 		printf("error in LoadRecentFolder\n");
460 	LoadFolder(false);
461 }
462 
463 
464 void
465 BackgroundsView::LoadFolder(bool isDesktop)
466 {
467 	if (fCurrent) {
468 		delete fCurrent;
469 		fCurrent = NULL;
470 	}
471 
472 	BNode node(&fCurrentRef);
473 	if (node.InitCheck() == B_OK)
474 		fCurrent = BackgroundImage::GetBackgroundImage(&node, isDesktop, this);
475 
476 	UpdateWithCurrent();
477 }
478 
479 
480 void
481 BackgroundsView::UpdateWithCurrent(void)
482 {
483 	if (fCurrent == NULL)
484 		return;
485 
486 	fPlacementMenu->FindItem(kMsgScalePlacement)->SetEnabled(fCurrent->IsDesktop());
487 	fPlacementMenu->FindItem(kMsgCenterPlacement)->SetEnabled(fCurrent->IsDesktop());
488 
489 	if (fWorkspaceMenu->IndexOf(fWorkspaceMenu->FindMarked()) > 5)
490 		fImageMenu->FindItem(kMsgNoImage)->SetLabel("Default");
491 	else
492 		fImageMenu->FindItem(kMsgNoImage)->SetLabel("None");
493 
494 	for (int32 i = fImageMenu->CountItems() - 5; i >= 0; i--) {
495 		fImageMenu->RemoveItem(2);
496 	}
497 
498 	for (int32 i = fImageList.CountItems() - 1; i >= 0; i--) {
499 		BMessage *message = new BMessage(kMsgImageSelected);
500 		AddItem(new BGImageMenuItem(GetImage(i)->GetName(), i, message));
501 	}
502 
503 	fImageMenu->SetTargetForItems(this);
504 
505 	fCurrentInfo = fCurrent->ImageInfoForWorkspace(current_workspace());
506 
507 	if (!fCurrentInfo) {
508 		fImageMenu->FindItem(kMsgNoImage)->SetMarked(true);
509 		fPlacementMenu->FindItem(kMsgManualPlacement)->SetMarked(true);
510 	} else {
511 		fIconLabelBackground->SetValue(fCurrentInfo->fEraseTextWidgetBackground
512 			? B_CONTROL_ON : B_CONTROL_OFF);
513 
514 		BString xtext, ytext;
515 		int32 cmd = 0;
516 		switch (fCurrentInfo->fMode) {
517 			case BackgroundImage::kCentered:
518 				cmd = kMsgCenterPlacement;
519 				break;
520 			case BackgroundImage::kScaledToFit:
521 				cmd = kMsgScalePlacement;
522 				break;
523 			case BackgroundImage::kAtOffset:
524 				cmd = kMsgManualPlacement;
525 				xtext << (int)fCurrentInfo->fOffset.x;
526 				ytext << (int)fCurrentInfo->fOffset.y;
527 				break;
528 			case BackgroundImage::kTiled:
529 				cmd = kMsgTilePlacement;
530 				break;
531 		}
532 
533 		if (cmd != 0)
534 			fPlacementMenu->FindItem(cmd)->SetMarked(true);
535 
536 		fXPlacementText->SetText(xtext.String());
537 		fYPlacementText->SetText(ytext.String());
538 
539 		fLastImageIndex = fCurrentInfo->fImageIndex;
540 		FindImageItem(fLastImageIndex)->SetMarked(true);
541 	}
542 
543 	rgb_color color = {255, 255, 255, 255};
544 	if (fCurrent->IsDesktop()) {
545 		color = BScreen().DesktopColor();
546 		fPicker->SetEnabled(true);
547 	} else
548 		fPicker->SetEnabled(false);
549 
550 	fPicker->SetValue(color);
551 
552 	UpdatePreview();
553 	UpdateButtons();
554 }
555 
556 
557 void
558 BackgroundsView::Save()
559 {
560 	bool eraseTextWidgetBackground =
561 		fIconLabelBackground->Value() == B_CONTROL_ON;
562 	BackgroundImage::Mode mode = FindPlacementMode();
563 	BPoint offset(atoi(fXPlacementText->Text()), atoi(fYPlacementText->Text()));
564 
565 	if (!fCurrent->IsDesktop()) {
566 		if (fCurrentInfo == NULL) {
567 			fCurrentInfo = new BackgroundImage::BackgroundImageInfo(B_ALL_WORKSPACES,
568 				fLastImageIndex, mode, offset, eraseTextWidgetBackground, 0, 0);
569 			fCurrent->Add(fCurrentInfo);
570 		} else {
571 			fCurrentInfo->fEraseTextWidgetBackground = eraseTextWidgetBackground;
572 			fCurrentInfo->fMode = mode;
573 			if (fCurrentInfo->fMode == BackgroundImage::kAtOffset)
574 				fCurrentInfo->fOffset = offset;
575 			fCurrentInfo->fImageIndex = fLastImageIndex;
576 		}
577 	} else {
578 		uint32 workspaceMask = 1;
579 		int32 workspace = current_workspace();
580 		for (; workspace; workspace--)
581 			workspaceMask *= 2;
582 
583 		if (fCurrentInfo != NULL) {
584 			if (fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()) {
585 				if (fCurrentInfo->fWorkspace != workspaceMask) {
586 					fCurrentInfo->fWorkspace = fCurrentInfo->fWorkspace
587 						^ workspaceMask;
588 					if (fLastImageIndex > -1) {
589 						fCurrentInfo = new BackgroundImage::BackgroundImageInfo(
590 							workspaceMask, fLastImageIndex, mode, offset,
591 							eraseTextWidgetBackground, fCurrentInfo->fImageSet,
592 							fCurrentInfo->fCacheMode);
593 						fCurrent->Add(fCurrentInfo);
594 					}
595 				} else {
596 					if (fLastImageIndex > -1) {
597 						fCurrentInfo->fEraseTextWidgetBackground =
598 							eraseTextWidgetBackground;
599 						fCurrentInfo->fMode = mode;
600 						if (fCurrentInfo->fMode == BackgroundImage::kAtOffset)
601 							fCurrentInfo->fOffset = offset;
602 
603 						fCurrentInfo->fImageIndex = fLastImageIndex;
604 					} else {
605 						fCurrent->Remove(fCurrentInfo);
606 						fCurrentInfo = NULL;
607 					}
608 				}
609 			} else if (fLastImageIndex > -1) {
610 				fCurrent->RemoveAll();
611 				fCurrentInfo = new BackgroundImage::BackgroundImageInfo(
612 					B_ALL_WORKSPACES, fLastImageIndex, mode, offset,
613 					eraseTextWidgetBackground, fCurrent->GetShowingImageSet(),
614 					fCurrentInfo->fCacheMode);
615 				fCurrent->Add(fCurrentInfo);
616 			}
617 		} else if (fLastImageIndex > -1) {
618 			if (fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()) {
619 				fCurrentInfo = new BackgroundImage::BackgroundImageInfo(
620 					workspaceMask, fLastImageIndex, mode, offset,
621 					eraseTextWidgetBackground, fCurrent->GetShowingImageSet(), 0);
622 			} else {
623 				fCurrent->RemoveAll();
624 				fCurrentInfo = new BackgroundImage::BackgroundImageInfo(
625 					B_ALL_WORKSPACES, fLastImageIndex, mode, offset,
626 					eraseTextWidgetBackground, fCurrent->GetShowingImageSet(), 0);
627 			}
628 			fCurrent->Add(fCurrentInfo);
629 		}
630 
631 		if (!fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()) {
632 			for (int32 i = 0; i < count_workspaces(); i++) {
633 				BScreen().SetDesktopColor(fPicker->ValueAsColor(), i, true);
634 			}
635 		} else
636 			BScreen().SetDesktopColor(fPicker->ValueAsColor(), true);
637 	}
638 
639 	BNode node(&fCurrentRef);
640 
641 	status_t status = fCurrent->SetBackgroundImage(&node);
642 	if (status != B_OK) {
643 		// TODO: this should be a BAlert!
644 		printf("setting background image failed: %s\n", strerror(status));
645 	}
646 }
647 
648 
649 void
650 BackgroundsView::NotifyServer()
651 {
652 	BMessenger tracker("application/x-vnd.Be-TRAK");
653 
654 	if (fCurrent->IsDesktop()) {
655 		tracker.SendMessage(new BMessage(B_RESTORE_BACKGROUND_IMAGE));
656 	} else {
657 		int32 i = -1;
658 		BMessage reply;
659 		int32 err;
660 		BEntry currentEntry(&fCurrentRef);
661 		BPath currentPath(&currentEntry);
662 		bool isCustomFolder = !fWorkspaceMenu->FindItem(kMsgDefaultFolder)->IsMarked();
663 
664 		do {
665 			BMessage msg(B_GET_PROPERTY);
666 			i++;
667 
668 			// look at the "Poses" in every Tracker window
669 			msg.AddSpecifier("Poses");
670 			msg.AddSpecifier("Window", i);
671 
672 			reply.MakeEmpty();
673 			tracker.SendMessage(&msg, &reply);
674 
675 			// break out of the loop when we're at the end of
676 			// the windows
677 			if (reply.what == B_MESSAGE_NOT_UNDERSTOOD
678 				&& reply.FindInt32("error", &err) == B_OK
679 				&& err == B_BAD_INDEX)
680 				break;
681 
682 			// don't stop for windows that don't understand
683 			// a request for "Poses"; they're not displaying
684 			// folders
685 			if (reply.what == B_MESSAGE_NOT_UNDERSTOOD
686 				&& reply.FindInt32("error", &err) == B_OK
687 				&& err != B_BAD_SCRIPT_SYNTAX)
688 				continue;
689 
690 			BMessenger trackerWindow;
691 			if (reply.FindMessenger("result", &trackerWindow) != B_OK)
692 				continue;
693 
694 			if (isCustomFolder) {
695 				// found a window with poses, ask for its path
696 				msg.MakeEmpty();
697 				msg.what = B_GET_PROPERTY;
698 				msg.AddSpecifier("Path");
699 				msg.AddSpecifier("Poses");
700 				msg.AddSpecifier("Window", i);
701 
702 				reply.MakeEmpty();
703 				tracker.SendMessage(&msg, &reply);
704 
705 				// go on with the next if this din't have a path
706 				if (reply.what == B_MESSAGE_NOT_UNDERSTOOD)
707 					continue;
708 
709 				entry_ref ref;
710 				if (reply.FindRef("result", &ref) == B_OK) {
711 					BEntry entry(&ref);
712 					BPath path(&entry);
713 
714 					// these are not the paths you're looking for
715 					if (currentPath != path)
716 						continue;
717 				}
718 			}
719 
720 			trackerWindow.SendMessage(B_RESTORE_BACKGROUND_IMAGE);
721 		} while (true);
722 	}
723 }
724 
725 
726 int32
727 BackgroundsView::NotifyThread(void *data)
728 {
729 	BackgroundsView *view = (BackgroundsView*)data;
730 
731 	view->NotifyServer();
732 	return B_OK;
733 }
734 
735 
736 void
737 BackgroundsView::SaveSettings(void)
738 {
739 	BPath path;
740 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
741 		path.Append(SETTINGS_FILE);
742 		BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
743 
744 		BPoint point = Window()->Frame().LeftTop();
745 		if (fSettings.ReplacePoint("pos", point) != B_OK)
746 			fSettings.AddPoint("pos", point);
747 
748 		entry_ref ref;
749 		BEntry entry;
750 		BPath path;
751 
752 		fPanel->GetPanelDirectory(&ref);
753 		entry.SetTo(&ref);
754 		entry.GetPath(&path);
755 		if (fSettings.ReplaceString("paneldir", path.Path()) != B_OK)
756 			fSettings.AddString("paneldir", path.Path());
757 
758 		fFolderPanel->GetPanelDirectory(&ref);
759 		entry.SetTo(&ref);
760 		entry.GetPath(&path);
761 		if (fSettings.ReplaceString("folderpaneldir", path.Path()) != B_OK)
762 			fSettings.AddString("folderpaneldir", path.Path());
763 
764 		fSettings.RemoveName("recentfolder");
765 		for (int32 i = 0; i < fPathList.CountItems(); i++) {
766 			fSettings.AddString("recentfolder", fPathList.ItemAt(i)->Path());
767 		}
768 
769 		fSettings.Flatten(&file);
770 	}
771 }
772 
773 
774 void
775 BackgroundsView::LoadSettings()
776 {
777 	fSettings.MakeEmpty();
778 
779 	BPath path;
780 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
781 		return;
782 
783 	path.Append(SETTINGS_FILE);
784 	BFile file(path.Path(), B_READ_ONLY);
785 	if (file.InitCheck() != B_OK)
786 		return;
787 
788 	if (fSettings.Unflatten(&file) != B_OK) {
789 		printf("Error unflattening settings file %s\n", path.Path());
790 		return;
791 	}
792 
793 	PRINT_OBJECT(fSettings);
794 
795 	BPoint point;
796 	if (fSettings.FindPoint("pos", &point) == B_OK)
797 		Window()->MoveTo(point);
798 
799 	BString string;
800 	if (fSettings.FindString("paneldir", &string) == B_OK)
801 		fPanel->SetPanelDirectory(string.String());
802 
803 	if (fSettings.FindString("folderpaneldir", &string) == B_OK)
804 		fFolderPanel->SetPanelDirectory(string.String());
805 
806 	int32 index = 0;
807 	while (fSettings.FindString("recentfolder", index, &string) == B_OK) {
808 		if (index == 0)
809 			fWorkspaceMenu->AddSeparatorItem();
810 
811 		BPath path(string.String());
812 		int32 i = AddPath(path);
813 		BString s;
814 		s << "Folder: " << path.Leaf();
815 		BMenuItem *item = new BMenuItem(s.String(),
816 			new BMessage(kMsgFolderSelected));
817 		fWorkspaceMenu->AddItem(item, -i - 1 + 6);
818 		index++;
819 	}
820 	fWorkspaceMenu->SetTargetForItems(this);
821 
822 	PRINT(("Settings Loaded\n"));
823 }
824 
825 
826 void
827 BackgroundsView::WorkspaceActivated(uint32 oldWorkspaces, bool active)
828 {
829 	UpdateWithCurrent();
830 }
831 
832 
833 void
834 BackgroundsView::UpdatePreview()
835 {
836 	bool imageEnabled = !(fImageMenu->FindItem(kMsgNoImage)->IsMarked());
837 	if (fPlacementMenu->IsEnabled() ^ imageEnabled)
838 		fPlacementMenu->SetEnabled(imageEnabled);
839 	if (fIconLabelBackground->IsEnabled() ^ imageEnabled)
840 		fIconLabelBackground->SetEnabled(imageEnabled);
841 
842 	bool textEnabled = (fPlacementMenu->FindItem(kMsgManualPlacement)->IsMarked())
843 		&& imageEnabled;
844 	if (fXPlacementText->IsEnabled() ^ textEnabled)
845 		fXPlacementText->SetEnabled(textEnabled);
846 	if (fYPlacementText->IsEnabled() ^ textEnabled)
847 		fYPlacementText->SetEnabled(textEnabled);
848 
849 	if (textEnabled && (strcmp(fXPlacementText->Text(), "") == 0)) {
850 		fXPlacementText->SetText("0");
851 		fYPlacementText->SetText("0");
852 	}
853 	if (!textEnabled) {
854 		fXPlacementText->SetText(NULL);
855 		fYPlacementText->SetText(NULL);
856 	}
857 
858 	fXPlacementText->TextView()->MakeSelectable(textEnabled);
859 	fYPlacementText->TextView()->MakeSelectable(textEnabled);
860 	fXPlacementText->TextView()->MakeEditable(textEnabled);
861 	fYPlacementText->TextView()->MakeEditable(textEnabled);
862 
863 	fPreView->ClearViewBitmap();
864 
865 	int32 index = ((BGImageMenuItem*)fImageMenu->FindMarked())->ImageIndex();
866 	if (index >= 0) {
867 		BBitmap *bitmap = GetImage(index)->GetBitmap();
868 		if (bitmap) {
869 			BackgroundImage::BackgroundImageInfo *info =
870 				new BackgroundImage::BackgroundImageInfo(0, index,
871 					FindPlacementMode(), BPoint(atoi(fXPlacementText->Text()),
872 						atoi(fYPlacementText->Text())),
873 					fIconLabelBackground->Value() == B_CONTROL_ON, 0, 0);
874 			if (info->fMode == BackgroundImage::kAtOffset) {
875 				fPreView->SetEnabled(true);
876 				fPreView->fPoint.x = atoi(fXPlacementText->Text());
877 				fPreView->fPoint.y = atoi(fYPlacementText->Text());
878 			} else
879 				fPreView->SetEnabled(false);
880 
881 			fPreView->fImageBounds = BRect(bitmap->Bounds());
882 			fCurrent->Show(info, fPreView);
883 		}
884 	} else
885 		fPreView->SetEnabled(false);
886 
887 	fPreView->SetViewColor(fPicker->ValueAsColor());
888 	fPreView->Invalidate();
889 }
890 
891 
892 BackgroundImage::Mode
893 BackgroundsView::FindPlacementMode()
894 {
895 	BackgroundImage::Mode mode = BackgroundImage::kAtOffset;
896 
897 	if (fPlacementMenu->FindItem(kMsgCenterPlacement)->IsMarked())
898 		mode = BackgroundImage::kCentered;
899 	if (fPlacementMenu->FindItem(kMsgScalePlacement)->IsMarked())
900 		mode = BackgroundImage::kScaledToFit;
901 	if (fPlacementMenu->FindItem(kMsgManualPlacement)->IsMarked())
902 		mode = BackgroundImage::kAtOffset;
903 	if (fPlacementMenu->FindItem(kMsgTilePlacement)->IsMarked())
904 		mode = BackgroundImage::kTiled;
905 
906 	return mode;
907 }
908 
909 
910 #ifndef __HAIKU__
911 inline bool operator!=(const rgb_color& x, const rgb_color& y)
912 {
913 	return (x.red != y.red || x.blue != y.blue || x.green != y.green);
914 }
915 #endif
916 
917 
918 void
919 BackgroundsView::UpdateButtons()
920 {
921 	bool hasChanged = false;
922 	if (fPicker->IsEnabled()
923 		&& fPicker->ValueAsColor() != BScreen().DesktopColor()) {
924 		hasChanged = true;
925 	} else if (fCurrentInfo) {
926 		if ((fIconLabelBackground->Value() == B_CONTROL_ON) ^
927 			fCurrentInfo->fEraseTextWidgetBackground) {
928 			hasChanged = true;
929 		} else if (FindPlacementMode() != fCurrentInfo->fMode) {
930 			hasChanged = true;
931 		} else if (fCurrentInfo->fImageIndex !=
932 			((BGImageMenuItem*)fImageMenu->FindMarked())->ImageIndex()) {
933 			hasChanged = true;
934 		} else if (fCurrent->IsDesktop()
935 			&& ((fCurrentInfo->fWorkspace != B_ALL_WORKSPACES)
936 				^ (fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()))) {
937 			hasChanged = true;
938 		} else if (fCurrentInfo->fMode == BackgroundImage::kAtOffset) {
939 			BString oldString, newString;
940 			oldString << (int)fCurrentInfo->fOffset.x;
941 			if (oldString != BString(fXPlacementText->Text())) {
942 				hasChanged = true;
943 			}
944 			oldString = "";
945 			oldString << (int)fCurrentInfo->fOffset.y;
946 			if (oldString != BString(fYPlacementText->Text())) {
947 				hasChanged = true;
948 			}
949 		}
950 	} else if (fImageMenu->IndexOf(fImageMenu->FindMarked()) > 0) {
951 		hasChanged = true;
952 	}
953 
954 	fApply->SetEnabled(hasChanged);
955 	fRevert->SetEnabled(hasChanged);
956 }
957 
958 
959 void
960 BackgroundsView::RefsReceived(BMessage *msg)
961 {
962 	entry_ref ref;
963 	int32 i = 0;
964 	BMimeType imageType("image");
965 	BPath desktopPath;
966 	find_directory(B_DESKTOP_DIRECTORY, &desktopPath);
967 
968 	while (msg->FindRef("refs", i++, &ref) == B_OK) {
969 		BPath path;
970 		BEntry entry(&ref, true);
971 		path.SetTo(&entry);
972 		BNode node(&entry);
973 
974 		if (node.IsFile()) {
975 			BMimeType refType;
976 			BMimeType::GuessMimeType(&ref, &refType);
977 			if (!imageType.Contains(&refType))
978 				continue;
979 
980 			BGImageMenuItem *item;
981 			int32 index = AddImage(path);
982 			if (index >= 0) {
983 				item = FindImageItem(index);
984 				fLastImageIndex = index;
985 			} else {
986 				const char* name = GetImage(-index - 1)->GetName();
987 				item = new BGImageMenuItem(name, -index - 1,
988 					new BMessage(kMsgImageSelected));
989 				AddItem(item);
990 				item->SetTarget(this);
991 				fLastImageIndex = -index - 1;
992 			}
993 
994 			item->SetMarked(true);
995 			BMessenger(this).SendMessage(kMsgImageSelected);
996 		} else if (node.IsDirectory()) {
997 			if (desktopPath == path) {
998 				fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->SetMarked(true);
999 				BMessenger(this).SendMessage(kMsgCurrentWorkspace);
1000 				break;
1001 			}
1002 			BMenuItem *item;
1003 			int32 index = AddPath(path);
1004 			if (index >= 0) {
1005 				item = fWorkspaceMenu->ItemAt(index + 6);
1006 				fLastWorkspaceIndex = index + 6;
1007 			} else {
1008 				if (fWorkspaceMenu->CountItems() <= 5)
1009 					fWorkspaceMenu->AddSeparatorItem();
1010 				BString s;
1011 				s << "Folder: " << path.Leaf();
1012 				item = new BMenuItem(s.String(), new BMessage(kMsgFolderSelected));
1013 				fWorkspaceMenu->AddItem(item, -index - 1 + 6);
1014 				item->SetTarget(this);
1015 				fLastWorkspaceIndex = -index - 1 + 6;
1016 			}
1017 
1018 			item->SetMarked(true);
1019 			BMessenger(this).SendMessage(kMsgFolderSelected);
1020 		}
1021 	}
1022 }
1023 
1024 
1025 int32
1026 BackgroundsView::AddPath(BPath path)
1027 {
1028 	int32 count = fPathList.CountItems();
1029 	int32 index = 0;
1030 	for (; index < count; index++) {
1031 		BPath *p = fPathList.ItemAt(index);
1032 		int c = BString(p->Path()).ICompare(path.Path());
1033 		if (c == 0)
1034 			return index;
1035 
1036 		if (c > 0)
1037 			break;
1038 	}
1039 	fPathList.AddItem(new BPath(path), index);
1040 	return -index - 1;
1041 }
1042 
1043 
1044 int32
1045 BackgroundsView::AddImage(BPath path)
1046 {
1047 	int32 count = fImageList.CountItems();
1048 	int32 index = 0;
1049 	for (; index < count; index++) {
1050 		Image *image = fImageList.ItemAt(index);
1051 		if (image->GetPath() == path)
1052 			return index;
1053 	}
1054 
1055 	fImageList.AddItem(new Image(path));
1056 	return -index - 1;
1057 }
1058 
1059 
1060 void
1061 BackgroundsView::ProcessRefs(entry_ref dir, BMessage* refs)
1062 {
1063 	fWorkspaceMenu->FindItem(kMsgDefaultFolder)->SetMarked(true);
1064 	BMessenger messenger(this);
1065 	messenger.SendMessage(kMsgDefaultFolder);
1066 
1067 	if (refs->CountNames(B_REF_TYPE) > 0) {
1068 		messenger.SendMessage(refs);
1069 	} else {
1070 		BMessage message(B_REFS_RECEIVED);
1071 		message.AddRef("refs", &dir);
1072 		messenger.SendMessage(&message);
1073 	}
1074 }
1075 
1076 
1077 Image*
1078 BackgroundsView::GetImage(int32 imageIndex)
1079 {
1080 	return fImageList.ItemAt(imageIndex);
1081 }
1082 
1083 
1084 BGImageMenuItem*
1085 BackgroundsView::FindImageItem(const int32 imageIndex)
1086 {
1087 	if (imageIndex < 0)
1088 		return (BGImageMenuItem *)fImageMenu->ItemAt(0);
1089 
1090 	int32 count = fImageMenu->CountItems() - 2;
1091 	int32 index = 2;
1092 	for (; index < count; index++) {
1093 		BGImageMenuItem *image = (BGImageMenuItem *)fImageMenu->ItemAt(index);
1094 		if (image->ImageIndex() == imageIndex)
1095 			return image;
1096 	}
1097 	return NULL;
1098 }
1099 
1100 
1101 bool
1102 BackgroundsView::AddItem(BGImageMenuItem *item)
1103 {
1104 	int32 count = fImageMenu->CountItems() - 2;
1105 	int32 index = 2;
1106 	if (count < index) {
1107 		fImageMenu->AddItem(new BSeparatorItem(), 1);
1108 		count = fImageMenu->CountItems() - 2;
1109 	}
1110 
1111 	for (; index < count; index++) {
1112 		BGImageMenuItem* image = (BGImageMenuItem *)fImageMenu->ItemAt(index);
1113 		int c = (BString(image->Label()).ICompare(BString(item->Label())));
1114 		if (c > 0)
1115 			break;
1116 	}
1117 	return fImageMenu->AddItem(item, index);
1118 }
1119 
1120 
1121 //	#pragma mark -
1122 
1123 
1124 PreView::PreView(BRect frame, const char *name, int32 resize, int32 flags)
1125 	: BControl(frame, name, NULL, NULL, resize, flags),
1126 	fMoveHandCursor(kHandCursorData)
1127 {
1128 }
1129 
1130 
1131 void
1132 PreView::AttachedToWindow()
1133 {
1134 	rgb_color color = ViewColor();
1135 	BControl::AttachedToWindow();
1136 	SetViewColor(color);
1137 }
1138 
1139 
1140 void
1141 PreView::MouseDown(BPoint point)
1142 {
1143 	if (IsEnabled() && Bounds().Contains(point)) {
1144 		uint32 buttons;
1145 		GetMouse(&point, &buttons);
1146 		if (buttons & B_PRIMARY_MOUSE_BUTTON) {
1147 			fOldPoint = point;
1148 			SetTracking(true);
1149 			BScreen().GetMode(&mode);
1150 			x_ratio = Bounds().Width() / mode.virtual_width;
1151 			y_ratio = Bounds().Height() / mode.virtual_height;
1152 			SetMouseEventMask(B_POINTER_EVENTS,
1153 				B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY);
1154 		}
1155 	}
1156 }
1157 
1158 
1159 void
1160 PreView::MouseUp(BPoint point)
1161 {
1162 	if (IsTracking())
1163 		SetTracking(false);
1164 }
1165 
1166 
1167 void
1168 PreView::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
1169 {
1170 	if (IsEnabled())
1171 		SetViewCursor(&fMoveHandCursor);
1172 	else
1173 		SetViewCursor(B_CURSOR_SYSTEM_DEFAULT);
1174 
1175 	if (IsTracking()) {
1176 		float x, y;
1177 		x = fPoint.x + (point.x - fOldPoint.x) / x_ratio;
1178 		y = fPoint.y + (point.y - fOldPoint.y) / y_ratio;
1179 		bool min, max, mustSend = false;
1180 		min = (x > -fImageBounds.Width());
1181 		max = (x < mode.virtual_width);
1182 		if (min && max) {
1183 			fOldPoint.x = point.x;
1184 			fPoint.x = x;
1185 			mustSend = true;
1186 		} else {
1187 			if (!min && fPoint.x > -fImageBounds.Width()) {
1188 				fPoint.x = -fImageBounds.Width();
1189 				fOldPoint.x = point.x - (x - fPoint.x) * x_ratio;
1190 				mustSend = true;
1191 			}
1192 			if (!max && fPoint.x < mode.virtual_width) {
1193 				fPoint.x = mode.virtual_width;
1194 				fOldPoint.x = point.x - (x - fPoint.x) * x_ratio;
1195 				mustSend = true;
1196 			}
1197 		}
1198 
1199 		min = (y > -fImageBounds.Height());
1200 		max = (y < mode.virtual_height);
1201 		if (min && max) {
1202 			fOldPoint.y = point.y;
1203 			fPoint.y = y;
1204 			mustSend = true;
1205 		} else {
1206 			if (!min && fPoint.y > -fImageBounds.Height()) {
1207 				fPoint.y = -fImageBounds.Height();
1208 				fOldPoint.y = point.y - (y - fPoint.y) * y_ratio;
1209 				mustSend = true;
1210 			}
1211 			if (!max && fPoint.y < mode.virtual_height) {
1212 				fPoint.y = mode.virtual_height;
1213 				fOldPoint.y = point.y - (y - fPoint.y) * y_ratio;
1214 				mustSend = true;
1215 			}
1216 		}
1217 
1218 		if (mustSend) {
1219 			BMessenger messenger(Parent());
1220 			messenger.SendMessage(kMsgUpdatePreviewPlacement);
1221 		}
1222 	}
1223 	BControl::MouseMoved(point, transit, message);
1224 }
1225 
1226 
1227 //	#pragma mark -
1228 
1229 
1230 PreviewBox::PreviewBox(BRect frame, const char *name)
1231 	: BBox(frame, name)
1232 {
1233 	fIsDesktop = true;
1234 }
1235 
1236 
1237 void
1238 PreviewBox::Draw(BRect rect)
1239 {
1240 	// TODO: make view size dependent!
1241 	rgb_color color = HighColor();
1242 
1243 	SetHighColor(LowColor());
1244 	FillRect(BRect(9, 19, 141, 127));
1245 
1246 	if (fIsDesktop) {
1247 		BPoint points[] = {
1248 			BPoint(11, 19), BPoint(139, 19), BPoint(141, 21),
1249 			BPoint(141, 119), BPoint(139, 121), BPoint(118, 121),
1250 			BPoint(118, 126), BPoint(117, 127), BPoint(33, 127),
1251 			BPoint(32, 126), BPoint(32, 121), BPoint(11, 121),
1252 			BPoint(9, 119), BPoint(9, 21), BPoint(11, 19)
1253 		};
1254 		SetHighColor(184, 184, 184);
1255 		FillPolygon(points, 15);
1256 		SetHighColor(96, 96, 96);
1257 		StrokePolygon(points, 15);
1258 		FillRect(BRect(107, 121, 111, 123));
1259 		SetHighColor(0, 0, 0);
1260 		StrokeRect(BRect(14, 24, 136, 116));
1261 		SetHighColor(0, 255, 0);
1262 		FillRect(BRect(101, 122, 103, 123));
1263 	} else {
1264 		SetHighColor(152, 152, 152);
1265 		StrokeLine(BPoint(11, 13), BPoint(67, 13));
1266 		StrokeLine(BPoint(67, 21));
1267 		StrokeLine(BPoint(139, 21));
1268 		StrokeLine(BPoint(139, 119));
1269 		StrokeLine(BPoint(11, 119));
1270 		StrokeLine(BPoint(11, 13));
1271 		StrokeRect(BRect(14, 24, 136, 116));
1272 		SetHighColor(255, 203, 0);
1273 		FillRect(BRect(12, 14, 66, 21));
1274 		SetHighColor(240, 240, 240);
1275 		StrokeRect(BRect(12, 22, 137, 117));
1276 		StrokeLine(BPoint(138, 22), BPoint(138, 22));
1277 		StrokeLine(BPoint(12, 118), BPoint(12, 118));
1278 		SetHighColor(200, 200, 200);
1279 		StrokeRect(BRect(13, 23, 138, 118));
1280 	}
1281 
1282 	SetHighColor(color);
1283 	BBox::Draw(rect);
1284 }
1285 
1286 
1287 void
1288 PreviewBox::SetDesktop(bool isDesktop)
1289 {
1290 	fIsDesktop = isDesktop;
1291 	Invalidate();
1292 }
1293 
1294 
1295 //	#pragma mark -
1296 
1297 
1298 BGImageMenuItem::BGImageMenuItem(const char *label, int32 imageIndex,
1299 	BMessage *message, char shortcut, uint32 modifiers)
1300 	: BMenuItem(label, message, shortcut, modifiers),
1301 	fImageIndex(imageIndex)
1302 {
1303 }
1304