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