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