xref: /haiku/src/preferences/backgrounds/BackgroundsView.cpp (revision d9cebac2b77547b7064f22497514eecd2d047160)
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 kMsgIconLabelOutline = 'ilol';
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 	fIconLabelOutline = new BCheckBox(rect, "iconLabelOutline",
211 		"Icon label outline", new BMessage(kMsgIconLabelOutline));
212 	fIconLabelOutline->SetValue(B_CONTROL_OFF);
213 	fIconLabelOutline->ResizeToPreferred();
214 	rightbox->AddChild(fIconLabelOutline);
215 
216 	rect.top += fIconLabelOutline->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(fIconLabelOutline->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 	fIconLabelOutline->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 kMsgIconLabelOutline:
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 		fIconLabelOutline->SetValue(B_CONTROL_OFF);
511 	} else {
512 		fIconLabelOutline->SetValue(fCurrentInfo->fTextWidgetLabelOutline
513 			? B_CONTROL_ON : B_CONTROL_OFF);
514 
515 		BString xtext, ytext;
516 		int32 cmd = 0;
517 		switch (fCurrentInfo->fMode) {
518 			case BackgroundImage::kCentered:
519 				cmd = kMsgCenterPlacement;
520 				break;
521 			case BackgroundImage::kScaledToFit:
522 				cmd = kMsgScalePlacement;
523 				break;
524 			case BackgroundImage::kAtOffset:
525 				cmd = kMsgManualPlacement;
526 				xtext << (int)fCurrentInfo->fOffset.x;
527 				ytext << (int)fCurrentInfo->fOffset.y;
528 				break;
529 			case BackgroundImage::kTiled:
530 				cmd = kMsgTilePlacement;
531 				break;
532 		}
533 
534 		if (cmd != 0)
535 			fPlacementMenu->FindItem(cmd)->SetMarked(true);
536 
537 		fXPlacementText->SetText(xtext.String());
538 		fYPlacementText->SetText(ytext.String());
539 
540 		fLastImageIndex = fCurrentInfo->fImageIndex;
541 		FindImageItem(fLastImageIndex)->SetMarked(true);
542 	}
543 
544 	rgb_color color = {255, 255, 255, 255};
545 	if (fCurrent->IsDesktop()) {
546 		color = BScreen().DesktopColor();
547 		fPicker->SetEnabled(true);
548 	} else
549 		fPicker->SetEnabled(false);
550 
551 	fPicker->SetValue(color);
552 
553 	UpdatePreview();
554 	UpdateButtons();
555 }
556 
557 
558 void
559 BackgroundsView::Save()
560 {
561 	bool textWidgetLabelOutline =
562 		fIconLabelOutline->Value() == B_CONTROL_ON;
563 	BackgroundImage::Mode mode = FindPlacementMode();
564 	BPoint offset(atoi(fXPlacementText->Text()), atoi(fYPlacementText->Text()));
565 
566 	if (!fCurrent->IsDesktop()) {
567 		if (fCurrentInfo == NULL) {
568 			fCurrentInfo = new BackgroundImage::BackgroundImageInfo(B_ALL_WORKSPACES,
569 				fLastImageIndex, mode, offset, textWidgetLabelOutline, 0, 0);
570 			fCurrent->Add(fCurrentInfo);
571 		} else {
572 			fCurrentInfo->fTextWidgetLabelOutline = textWidgetLabelOutline;
573 			fCurrentInfo->fMode = mode;
574 			if (fCurrentInfo->fMode == BackgroundImage::kAtOffset)
575 				fCurrentInfo->fOffset = offset;
576 			fCurrentInfo->fImageIndex = fLastImageIndex;
577 		}
578 	} else {
579 		uint32 workspaceMask = 1;
580 		int32 workspace = current_workspace();
581 		for (; workspace; workspace--)
582 			workspaceMask *= 2;
583 
584 		if (fCurrentInfo != NULL) {
585 			if (fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()) {
586 				if (fCurrentInfo->fWorkspace != workspaceMask) {
587 					fCurrentInfo->fWorkspace = fCurrentInfo->fWorkspace
588 						^ workspaceMask;
589 					if (fLastImageIndex > -1) {
590 						fCurrentInfo = new BackgroundImage::BackgroundImageInfo(
591 							workspaceMask, fLastImageIndex, mode, offset,
592 							textWidgetLabelOutline, fCurrentInfo->fImageSet,
593 							fCurrentInfo->fCacheMode);
594 						fCurrent->Add(fCurrentInfo);
595 					}
596 				} else {
597 					if (fLastImageIndex > -1) {
598 						fCurrentInfo->fTextWidgetLabelOutline =
599 							textWidgetLabelOutline;
600 						fCurrentInfo->fMode = mode;
601 						if (fCurrentInfo->fMode == BackgroundImage::kAtOffset)
602 							fCurrentInfo->fOffset = offset;
603 
604 						fCurrentInfo->fImageIndex = fLastImageIndex;
605 					} else {
606 						fCurrent->Remove(fCurrentInfo);
607 						fCurrentInfo = NULL;
608 					}
609 				}
610 			} else if (fLastImageIndex > -1) {
611 				fCurrent->RemoveAll();
612 				fCurrentInfo = new BackgroundImage::BackgroundImageInfo(
613 					B_ALL_WORKSPACES, fLastImageIndex, mode, offset,
614 					textWidgetLabelOutline, fCurrent->GetShowingImageSet(),
615 					fCurrentInfo->fCacheMode);
616 				fCurrent->Add(fCurrentInfo);
617 			}
618 		} else if (fLastImageIndex > -1) {
619 			if (fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()) {
620 				fCurrentInfo = new BackgroundImage::BackgroundImageInfo(
621 					workspaceMask, fLastImageIndex, mode, offset,
622 					textWidgetLabelOutline, fCurrent->GetShowingImageSet(), 0);
623 			} else {
624 				fCurrent->RemoveAll();
625 				fCurrentInfo = new BackgroundImage::BackgroundImageInfo(
626 					B_ALL_WORKSPACES, fLastImageIndex, mode, offset,
627 					textWidgetLabelOutline, fCurrent->GetShowingImageSet(), 0);
628 			}
629 			fCurrent->Add(fCurrentInfo);
630 		}
631 
632 		if (!fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()) {
633 			for (int32 i = 0; i < count_workspaces(); i++) {
634 				BScreen().SetDesktopColor(fPicker->ValueAsColor(), i, true);
635 			}
636 		} else
637 			BScreen().SetDesktopColor(fPicker->ValueAsColor(), true);
638 	}
639 
640 	BNode node(&fCurrentRef);
641 
642 	status_t status = fCurrent->SetBackgroundImage(&node);
643 	if (status != B_OK) {
644 		// TODO: this should be a BAlert!
645 		printf("setting background image failed: %s\n", strerror(status));
646 	}
647 }
648 
649 
650 void
651 BackgroundsView::NotifyServer()
652 {
653 	BMessenger tracker("application/x-vnd.Be-TRAK");
654 
655 	if (fCurrent->IsDesktop()) {
656 		tracker.SendMessage(new BMessage(B_RESTORE_BACKGROUND_IMAGE));
657 	} else {
658 		int32 i = -1;
659 		BMessage reply;
660 		int32 err;
661 		BEntry currentEntry(&fCurrentRef);
662 		BPath currentPath(&currentEntry);
663 		bool isCustomFolder = !fWorkspaceMenu->FindItem(kMsgDefaultFolder)->IsMarked();
664 
665 		do {
666 			BMessage msg(B_GET_PROPERTY);
667 			i++;
668 
669 			// look at the "Poses" in every Tracker window
670 			msg.AddSpecifier("Poses");
671 			msg.AddSpecifier("Window", i);
672 
673 			reply.MakeEmpty();
674 			tracker.SendMessage(&msg, &reply);
675 
676 			// break out of the loop when we're at the end of
677 			// the windows
678 			if (reply.what == B_MESSAGE_NOT_UNDERSTOOD
679 				&& reply.FindInt32("error", &err) == B_OK
680 				&& err == B_BAD_INDEX)
681 				break;
682 
683 			// don't stop for windows that don't understand
684 			// a request for "Poses"; they're not displaying
685 			// folders
686 			if (reply.what == B_MESSAGE_NOT_UNDERSTOOD
687 				&& reply.FindInt32("error", &err) == B_OK
688 				&& err != B_BAD_SCRIPT_SYNTAX)
689 				continue;
690 
691 			BMessenger trackerWindow;
692 			if (reply.FindMessenger("result", &trackerWindow) != B_OK)
693 				continue;
694 
695 			if (isCustomFolder) {
696 				// found a window with poses, ask for its path
697 				msg.MakeEmpty();
698 				msg.what = B_GET_PROPERTY;
699 				msg.AddSpecifier("Path");
700 				msg.AddSpecifier("Poses");
701 				msg.AddSpecifier("Window", i);
702 
703 				reply.MakeEmpty();
704 				tracker.SendMessage(&msg, &reply);
705 
706 				// go on with the next if this din't have a path
707 				if (reply.what == B_MESSAGE_NOT_UNDERSTOOD)
708 					continue;
709 
710 				entry_ref ref;
711 				if (reply.FindRef("result", &ref) == B_OK) {
712 					BEntry entry(&ref);
713 					BPath path(&entry);
714 
715 					// these are not the paths you're looking for
716 					if (currentPath != path)
717 						continue;
718 				}
719 			}
720 
721 			trackerWindow.SendMessage(B_RESTORE_BACKGROUND_IMAGE);
722 		} while (true);
723 	}
724 }
725 
726 
727 int32
728 BackgroundsView::NotifyThread(void *data)
729 {
730 	BackgroundsView *view = (BackgroundsView*)data;
731 
732 	view->NotifyServer();
733 	return B_OK;
734 }
735 
736 
737 void
738 BackgroundsView::SaveSettings(void)
739 {
740 	BPath path;
741 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
742 		path.Append(SETTINGS_FILE);
743 		BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
744 
745 		BPoint point = Window()->Frame().LeftTop();
746 		if (fSettings.ReplacePoint("pos", point) != B_OK)
747 			fSettings.AddPoint("pos", point);
748 
749 		entry_ref ref;
750 		BEntry entry;
751 		BPath path;
752 
753 		fPanel->GetPanelDirectory(&ref);
754 		entry.SetTo(&ref);
755 		entry.GetPath(&path);
756 		if (fSettings.ReplaceString("paneldir", path.Path()) != B_OK)
757 			fSettings.AddString("paneldir", path.Path());
758 
759 		fFolderPanel->GetPanelDirectory(&ref);
760 		entry.SetTo(&ref);
761 		entry.GetPath(&path);
762 		if (fSettings.ReplaceString("folderpaneldir", path.Path()) != B_OK)
763 			fSettings.AddString("folderpaneldir", path.Path());
764 
765 		fSettings.RemoveName("recentfolder");
766 		for (int32 i = 0; i < fPathList.CountItems(); i++) {
767 			fSettings.AddString("recentfolder", fPathList.ItemAt(i)->Path());
768 		}
769 
770 		fSettings.Flatten(&file);
771 	}
772 }
773 
774 
775 void
776 BackgroundsView::LoadSettings()
777 {
778 	fSettings.MakeEmpty();
779 
780 	BPath path;
781 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
782 		return;
783 
784 	path.Append(SETTINGS_FILE);
785 	BFile file(path.Path(), B_READ_ONLY);
786 	if (file.InitCheck() != B_OK)
787 		return;
788 
789 	if (fSettings.Unflatten(&file) != B_OK) {
790 		printf("Error unflattening settings file %s\n", path.Path());
791 		return;
792 	}
793 
794 	PRINT_OBJECT(fSettings);
795 
796 	BPoint point;
797 	if (fSettings.FindPoint("pos", &point) == B_OK)
798 		Window()->MoveTo(point);
799 
800 	BString string;
801 	if (fSettings.FindString("paneldir", &string) == B_OK)
802 		fPanel->SetPanelDirectory(string.String());
803 
804 	if (fSettings.FindString("folderpaneldir", &string) == B_OK)
805 		fFolderPanel->SetPanelDirectory(string.String());
806 
807 	int32 index = 0;
808 	while (fSettings.FindString("recentfolder", index, &string) == B_OK) {
809 		if (index == 0)
810 			fWorkspaceMenu->AddSeparatorItem();
811 
812 		BPath path(string.String());
813 		int32 i = AddPath(path);
814 		BString s;
815 		s << "Folder: " << path.Leaf();
816 		BMenuItem *item = new BMenuItem(s.String(),
817 			new BMessage(kMsgFolderSelected));
818 		fWorkspaceMenu->AddItem(item, -i - 1 + 6);
819 		index++;
820 	}
821 	fWorkspaceMenu->SetTargetForItems(this);
822 
823 	PRINT(("Settings Loaded\n"));
824 }
825 
826 
827 void
828 BackgroundsView::WorkspaceActivated(uint32 oldWorkspaces, bool active)
829 {
830 	UpdateWithCurrent();
831 }
832 
833 
834 void
835 BackgroundsView::UpdatePreview()
836 {
837 	bool imageEnabled = !(fImageMenu->FindItem(kMsgNoImage)->IsMarked());
838 	if (fPlacementMenu->IsEnabled() ^ imageEnabled)
839 		fPlacementMenu->SetEnabled(imageEnabled);
840 	if (fIconLabelOutline->IsEnabled() ^ imageEnabled)
841 		fIconLabelOutline->SetEnabled(imageEnabled);
842 
843 	bool textEnabled = (fPlacementMenu->FindItem(kMsgManualPlacement)->IsMarked())
844 		&& imageEnabled;
845 	if (fXPlacementText->IsEnabled() ^ textEnabled)
846 		fXPlacementText->SetEnabled(textEnabled);
847 	if (fYPlacementText->IsEnabled() ^ textEnabled)
848 		fYPlacementText->SetEnabled(textEnabled);
849 
850 	if (textEnabled && (strcmp(fXPlacementText->Text(), "") == 0)) {
851 		fXPlacementText->SetText("0");
852 		fYPlacementText->SetText("0");
853 	}
854 	if (!textEnabled) {
855 		fXPlacementText->SetText(NULL);
856 		fYPlacementText->SetText(NULL);
857 	}
858 
859 	fXPlacementText->TextView()->MakeSelectable(textEnabled);
860 	fYPlacementText->TextView()->MakeSelectable(textEnabled);
861 	fXPlacementText->TextView()->MakeEditable(textEnabled);
862 	fYPlacementText->TextView()->MakeEditable(textEnabled);
863 
864 	fPreView->ClearViewBitmap();
865 
866 	int32 index = ((BGImageMenuItem*)fImageMenu->FindMarked())->ImageIndex();
867 	if (index >= 0) {
868 		BBitmap *bitmap = GetImage(index)->GetBitmap();
869 		if (bitmap) {
870 			BackgroundImage::BackgroundImageInfo *info =
871 				new BackgroundImage::BackgroundImageInfo(0, index,
872 					FindPlacementMode(), BPoint(atoi(fXPlacementText->Text()),
873 						atoi(fYPlacementText->Text())),
874 					fIconLabelOutline->Value() == B_CONTROL_ON, 0, 0);
875 			if (info->fMode == BackgroundImage::kAtOffset) {
876 				fPreView->SetEnabled(true);
877 				fPreView->fPoint.x = atoi(fXPlacementText->Text());
878 				fPreView->fPoint.y = atoi(fYPlacementText->Text());
879 			} else
880 				fPreView->SetEnabled(false);
881 
882 			fPreView->fImageBounds = BRect(bitmap->Bounds());
883 			fCurrent->Show(info, fPreView);
884 		}
885 	} else
886 		fPreView->SetEnabled(false);
887 
888 	fPreView->SetViewColor(fPicker->ValueAsColor());
889 	fPreView->Invalidate();
890 }
891 
892 
893 BackgroundImage::Mode
894 BackgroundsView::FindPlacementMode()
895 {
896 	BackgroundImage::Mode mode = BackgroundImage::kAtOffset;
897 
898 	if (fPlacementMenu->FindItem(kMsgCenterPlacement)->IsMarked())
899 		mode = BackgroundImage::kCentered;
900 	if (fPlacementMenu->FindItem(kMsgScalePlacement)->IsMarked())
901 		mode = BackgroundImage::kScaledToFit;
902 	if (fPlacementMenu->FindItem(kMsgManualPlacement)->IsMarked())
903 		mode = BackgroundImage::kAtOffset;
904 	if (fPlacementMenu->FindItem(kMsgTilePlacement)->IsMarked())
905 		mode = BackgroundImage::kTiled;
906 
907 	return mode;
908 }
909 
910 
911 #ifndef __HAIKU__
912 inline bool operator!=(const rgb_color& x, const rgb_color& y)
913 {
914 	return (x.red != y.red || x.blue != y.blue || x.green != y.green);
915 }
916 #endif
917 
918 
919 void
920 BackgroundsView::UpdateButtons()
921 {
922 	bool hasChanged = false;
923 	if (fPicker->IsEnabled()
924 		&& fPicker->ValueAsColor() != BScreen().DesktopColor()) {
925 		hasChanged = true;
926 	} else if (fCurrentInfo) {
927 		if ((fIconLabelOutline->Value() == B_CONTROL_ON) ^
928 			fCurrentInfo->fTextWidgetLabelOutline) {
929 			hasChanged = true;
930 		} else if (FindPlacementMode() != fCurrentInfo->fMode) {
931 			hasChanged = true;
932 		} else if (fCurrentInfo->fImageIndex !=
933 			((BGImageMenuItem*)fImageMenu->FindMarked())->ImageIndex()) {
934 			hasChanged = true;
935 		} else if (fCurrent->IsDesktop()
936 			&& ((fCurrentInfo->fWorkspace != B_ALL_WORKSPACES)
937 				^ (fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()))) {
938 			hasChanged = true;
939 		} else if (fCurrentInfo->fMode == BackgroundImage::kAtOffset) {
940 			BString oldString, newString;
941 			oldString << (int)fCurrentInfo->fOffset.x;
942 			if (oldString != BString(fXPlacementText->Text())) {
943 				hasChanged = true;
944 			}
945 			oldString = "";
946 			oldString << (int)fCurrentInfo->fOffset.y;
947 			if (oldString != BString(fYPlacementText->Text())) {
948 				hasChanged = true;
949 			}
950 		}
951 	} else if (fImageMenu->IndexOf(fImageMenu->FindMarked()) > 0) {
952 		hasChanged = true;
953 	}
954 
955 	fApply->SetEnabled(hasChanged);
956 	fRevert->SetEnabled(hasChanged);
957 }
958 
959 
960 void
961 BackgroundsView::RefsReceived(BMessage *msg)
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 (msg->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 			item->SetMarked(true);
996 			BMessenger(this).SendMessage(kMsgImageSelected);
997 		} else if (node.IsDirectory()) {
998 			if (desktopPath == path) {
999 				fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->SetMarked(true);
1000 				BMessenger(this).SendMessage(kMsgCurrentWorkspace);
1001 				break;
1002 			}
1003 			BMenuItem *item;
1004 			int32 index = AddPath(path);
1005 			if (index >= 0) {
1006 				item = fWorkspaceMenu->ItemAt(index + 6);
1007 				fLastWorkspaceIndex = index + 6;
1008 			} else {
1009 				if (fWorkspaceMenu->CountItems() <= 5)
1010 					fWorkspaceMenu->AddSeparatorItem();
1011 				BString s;
1012 				s << "Folder: " << path.Leaf();
1013 				item = new BMenuItem(s.String(), new BMessage(kMsgFolderSelected));
1014 				fWorkspaceMenu->AddItem(item, -index - 1 + 6);
1015 				item->SetTarget(this);
1016 				fLastWorkspaceIndex = -index - 1 + 6;
1017 			}
1018 
1019 			item->SetMarked(true);
1020 			BMessenger(this).SendMessage(kMsgFolderSelected);
1021 		}
1022 	}
1023 }
1024 
1025 
1026 int32
1027 BackgroundsView::AddPath(BPath path)
1028 {
1029 	int32 count = fPathList.CountItems();
1030 	int32 index = 0;
1031 	for (; index < count; index++) {
1032 		BPath *p = fPathList.ItemAt(index);
1033 		int c = BString(p->Path()).ICompare(path.Path());
1034 		if (c == 0)
1035 			return index;
1036 
1037 		if (c > 0)
1038 			break;
1039 	}
1040 	fPathList.AddItem(new BPath(path), index);
1041 	return -index - 1;
1042 }
1043 
1044 
1045 int32
1046 BackgroundsView::AddImage(BPath path)
1047 {
1048 	int32 count = fImageList.CountItems();
1049 	int32 index = 0;
1050 	for (; index < count; index++) {
1051 		Image *image = fImageList.ItemAt(index);
1052 		if (image->GetPath() == path)
1053 			return index;
1054 	}
1055 
1056 	fImageList.AddItem(new Image(path));
1057 	return -index - 1;
1058 }
1059 
1060 
1061 void
1062 BackgroundsView::ProcessRefs(entry_ref dir, BMessage* refs)
1063 {
1064 	fWorkspaceMenu->FindItem(kMsgDefaultFolder)->SetMarked(true);
1065 	BMessenger messenger(this);
1066 	messenger.SendMessage(kMsgDefaultFolder);
1067 
1068 	if (refs->CountNames(B_REF_TYPE) > 0) {
1069 		messenger.SendMessage(refs);
1070 	} else {
1071 		BMessage message(B_REFS_RECEIVED);
1072 		message.AddRef("refs", &dir);
1073 		messenger.SendMessage(&message);
1074 	}
1075 }
1076 
1077 
1078 Image*
1079 BackgroundsView::GetImage(int32 imageIndex)
1080 {
1081 	return fImageList.ItemAt(imageIndex);
1082 }
1083 
1084 
1085 BGImageMenuItem*
1086 BackgroundsView::FindImageItem(const int32 imageIndex)
1087 {
1088 	if (imageIndex < 0)
1089 		return (BGImageMenuItem *)fImageMenu->ItemAt(0);
1090 
1091 	int32 count = fImageMenu->CountItems() - 2;
1092 	int32 index = 2;
1093 	for (; index < count; index++) {
1094 		BGImageMenuItem *image = (BGImageMenuItem *)fImageMenu->ItemAt(index);
1095 		if (image->ImageIndex() == imageIndex)
1096 			return image;
1097 	}
1098 	return NULL;
1099 }
1100 
1101 
1102 bool
1103 BackgroundsView::AddItem(BGImageMenuItem *item)
1104 {
1105 	int32 count = fImageMenu->CountItems() - 2;
1106 	int32 index = 2;
1107 	if (count < index) {
1108 		fImageMenu->AddItem(new BSeparatorItem(), 1);
1109 		count = fImageMenu->CountItems() - 2;
1110 	}
1111 
1112 	for (; index < count; index++) {
1113 		BGImageMenuItem* image = (BGImageMenuItem *)fImageMenu->ItemAt(index);
1114 		int c = (BString(image->Label()).ICompare(BString(item->Label())));
1115 		if (c > 0)
1116 			break;
1117 	}
1118 	return fImageMenu->AddItem(item, index);
1119 }
1120 
1121 
1122 //	#pragma mark -
1123 
1124 
1125 PreView::PreView(BRect frame, const char *name, int32 resize, int32 flags)
1126 	: BControl(frame, name, NULL, NULL, resize, flags),
1127 	fMoveHandCursor(kHandCursorData)
1128 {
1129 }
1130 
1131 
1132 void
1133 PreView::AttachedToWindow()
1134 {
1135 	rgb_color color = ViewColor();
1136 	BControl::AttachedToWindow();
1137 	SetViewColor(color);
1138 }
1139 
1140 
1141 void
1142 PreView::MouseDown(BPoint point)
1143 {
1144 	if (IsEnabled() && Bounds().Contains(point)) {
1145 		uint32 buttons;
1146 		GetMouse(&point, &buttons);
1147 		if (buttons & B_PRIMARY_MOUSE_BUTTON) {
1148 			fOldPoint = point;
1149 			SetTracking(true);
1150 			BScreen().GetMode(&mode);
1151 			x_ratio = Bounds().Width() / mode.virtual_width;
1152 			y_ratio = Bounds().Height() / mode.virtual_height;
1153 			SetMouseEventMask(B_POINTER_EVENTS,
1154 				B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY);
1155 		}
1156 	}
1157 }
1158 
1159 
1160 void
1161 PreView::MouseUp(BPoint point)
1162 {
1163 	if (IsTracking())
1164 		SetTracking(false);
1165 }
1166 
1167 
1168 void
1169 PreView::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
1170 {
1171 	if (IsEnabled())
1172 		SetViewCursor(&fMoveHandCursor);
1173 	else
1174 		SetViewCursor(B_CURSOR_SYSTEM_DEFAULT);
1175 
1176 	if (IsTracking()) {
1177 		float x, y;
1178 		x = fPoint.x + (point.x - fOldPoint.x) / x_ratio;
1179 		y = fPoint.y + (point.y - fOldPoint.y) / y_ratio;
1180 		bool min, max, mustSend = false;
1181 		min = (x > -fImageBounds.Width());
1182 		max = (x < mode.virtual_width);
1183 		if (min && max) {
1184 			fOldPoint.x = point.x;
1185 			fPoint.x = x;
1186 			mustSend = true;
1187 		} else {
1188 			if (!min && fPoint.x > -fImageBounds.Width()) {
1189 				fPoint.x = -fImageBounds.Width();
1190 				fOldPoint.x = point.x - (x - fPoint.x) * x_ratio;
1191 				mustSend = true;
1192 			}
1193 			if (!max && fPoint.x < mode.virtual_width) {
1194 				fPoint.x = mode.virtual_width;
1195 				fOldPoint.x = point.x - (x - fPoint.x) * x_ratio;
1196 				mustSend = true;
1197 			}
1198 		}
1199 
1200 		min = (y > -fImageBounds.Height());
1201 		max = (y < mode.virtual_height);
1202 		if (min && max) {
1203 			fOldPoint.y = point.y;
1204 			fPoint.y = y;
1205 			mustSend = true;
1206 		} else {
1207 			if (!min && fPoint.y > -fImageBounds.Height()) {
1208 				fPoint.y = -fImageBounds.Height();
1209 				fOldPoint.y = point.y - (y - fPoint.y) * y_ratio;
1210 				mustSend = true;
1211 			}
1212 			if (!max && fPoint.y < mode.virtual_height) {
1213 				fPoint.y = mode.virtual_height;
1214 				fOldPoint.y = point.y - (y - fPoint.y) * y_ratio;
1215 				mustSend = true;
1216 			}
1217 		}
1218 
1219 		if (mustSend) {
1220 			BMessenger messenger(Parent());
1221 			messenger.SendMessage(kMsgUpdatePreviewPlacement);
1222 		}
1223 	}
1224 	BControl::MouseMoved(point, transit, message);
1225 }
1226 
1227 
1228 //	#pragma mark -
1229 
1230 
1231 PreviewBox::PreviewBox(BRect frame, const char *name)
1232 	: BBox(frame, name)
1233 {
1234 	fIsDesktop = true;
1235 }
1236 
1237 
1238 void
1239 PreviewBox::Draw(BRect rect)
1240 {
1241 	// TODO: make view size dependent!
1242 	rgb_color color = HighColor();
1243 
1244 	SetHighColor(LowColor());
1245 	FillRect(BRect(9, 19, 141, 127));
1246 
1247 	if (fIsDesktop) {
1248 		BPoint points[] = {
1249 			BPoint(11, 19), BPoint(139, 19), BPoint(141, 21),
1250 			BPoint(141, 119), BPoint(139, 121), BPoint(118, 121),
1251 			BPoint(118, 126), BPoint(117, 127), BPoint(33, 127),
1252 			BPoint(32, 126), BPoint(32, 121), BPoint(11, 121),
1253 			BPoint(9, 119), BPoint(9, 21), BPoint(11, 19)
1254 		};
1255 		SetHighColor(184, 184, 184);
1256 		FillPolygon(points, 15);
1257 		SetHighColor(96, 96, 96);
1258 		StrokePolygon(points, 15);
1259 		FillRect(BRect(107, 121, 111, 123));
1260 		SetHighColor(0, 0, 0);
1261 		StrokeRect(BRect(14, 24, 136, 116));
1262 		SetHighColor(0, 255, 0);
1263 		FillRect(BRect(101, 122, 103, 123));
1264 	} else {
1265 		SetHighColor(152, 152, 152);
1266 		StrokeLine(BPoint(11, 13), BPoint(67, 13));
1267 		StrokeLine(BPoint(67, 21));
1268 		StrokeLine(BPoint(139, 21));
1269 		StrokeLine(BPoint(139, 119));
1270 		StrokeLine(BPoint(11, 119));
1271 		StrokeLine(BPoint(11, 13));
1272 		StrokeRect(BRect(14, 24, 136, 116));
1273 		SetHighColor(255, 203, 0);
1274 		FillRect(BRect(12, 14, 66, 21));
1275 		SetHighColor(240, 240, 240);
1276 		StrokeRect(BRect(12, 22, 137, 117));
1277 		StrokeLine(BPoint(138, 22), BPoint(138, 22));
1278 		StrokeLine(BPoint(12, 118), BPoint(12, 118));
1279 		SetHighColor(200, 200, 200);
1280 		StrokeRect(BRect(13, 23, 138, 118));
1281 	}
1282 
1283 	SetHighColor(color);
1284 	BBox::Draw(rect);
1285 }
1286 
1287 
1288 void
1289 PreviewBox::SetDesktop(bool isDesktop)
1290 {
1291 	fIsDesktop = isDesktop;
1292 	Invalidate();
1293 }
1294 
1295 
1296 //	#pragma mark -
1297 
1298 
1299 BGImageMenuItem::BGImageMenuItem(const char *label, int32 imageIndex,
1300 	BMessage *message, char shortcut, uint32 modifiers)
1301 	: BMenuItem(label, message, shortcut, modifiers),
1302 	fImageIndex(imageIndex)
1303 {
1304 }
1305