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