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