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 *		Jonas Sundström, jonas@kirilla.se
9 */
10
11
12#include "BackgroundsView.h"
13
14#include <stdio.h>
15#include <stdlib.h>
16
17#include <Bitmap.h>
18#include <Catalog.h>
19#include <Cursor.h>
20#include <Debug.h>
21#include <File.h>
22#include <FindDirectory.h>
23#include <LayoutBuilder.h>
24#include <Locale.h>
25#include <MenuField.h>
26#include <Messenger.h>
27#include <MimeType.h>
28#include <Point.h>
29#include <PopUpMenu.h>
30
31#include <be_apps/Tracker/Background.h>
32
33#include "ImageFilePanel.h"
34
35
36#undef B_TRANSLATION_CONTEXT
37#define B_TRANSLATION_CONTEXT "Main View"
38
39
40static const uint32 kMsgApplySettings = 'aply';
41static const uint32 kMsgRevertSettings = 'rvrt';
42
43static const uint32 kMsgUpdateColor = 'upcl';
44static const uint32 kMsgAllWorkspaces = 'alwk';
45static const uint32 kMsgCurrentWorkspace = 'crwk';
46static const uint32 kMsgDefaultFolder = 'dffl';
47static const uint32 kMsgOtherFolder = 'otfl';
48static const uint32 kMsgNoImage = 'noim';
49static const uint32 kMsgOtherImage = 'otim';
50static const uint32 kMsgImageSelected = 'imsl';
51static const uint32 kMsgFolderSelected = 'flsl';
52
53static const uint32 kMsgCenterPlacement = 'cnpl';
54static const uint32 kMsgManualPlacement = 'mnpl';
55static const uint32 kMsgScalePlacement = 'scpl';
56static const uint32 kMsgTilePlacement = 'tlpl';
57static const uint32 kMsgIconLabelOutline = 'ilol';
58
59static const uint32 kMsgImagePlacement = 'xypl';
60static const uint32 kMsgUpdatePreviewPlacement = 'pvpl';
61
62
63BackgroundsView::BackgroundsView()
64	:
65	BBox("BackgroundsView"),
66	fCurrent(NULL),
67	fCurrentInfo(NULL),
68	fLastImageIndex(-1),
69	fPathList(1, true),
70	fImageList(1, true),
71	fFoundPositionSetting(false)
72{
73	SetBorder(B_NO_BORDER);
74
75	fPreviewBox = new BBox("preview");
76	fPreviewBox->SetLabel(B_TRANSLATE("Preview"));
77
78	fPreview = new Preview();
79
80	fTopLeft = new FramePart(FRAME_TOP_LEFT);
81	fTop = new FramePart(FRAME_TOP);
82	fTopRight = new FramePart(FRAME_TOP_RIGHT);
83	fLeft = new FramePart(FRAME_LEFT_SIDE);
84	fRight = new FramePart(FRAME_RIGHT_SIDE);
85	fBottomLeft = new FramePart(FRAME_BOTTOM_LEFT);
86	fBottom = new FramePart(FRAME_BOTTOM);
87	fBottomRight = new FramePart(FRAME_BOTTOM_RIGHT);
88
89	fXPlacementText = new BTextControl(B_TRANSLATE("X:"), NULL,
90		new BMessage(kMsgImagePlacement));
91	fYPlacementText = new BTextControl(B_TRANSLATE("Y:"), NULL,
92		new BMessage(kMsgImagePlacement));
93
94	fXPlacementText->TextView()->SetMaxBytes(5);
95	fYPlacementText->TextView()->SetMaxBytes(5);
96
97	for (int32 i = 0; i < 256; i++) {
98		if ((i < '0' || i > '9') && i != '-') {
99			fXPlacementText->TextView()->DisallowChar(i);
100			fYPlacementText->TextView()->DisallowChar(i);
101		}
102	}
103
104	BView* view = BLayoutBuilder::Group<>()
105		.AddGlue()
106		.AddGroup(B_VERTICAL, 20)
107			.AddGroup(B_HORIZONTAL, 0)
108				.AddGlue()
109				.AddGrid(0, 0, 1)
110					.Add(fTopLeft, 0, 0)
111					.Add(fTop, 1, 0)
112					.Add(fTopRight, 2, 0)
113					.Add(fLeft, 0, 1)
114					.Add(fPreview, 1, 1)
115					.Add(fRight, 2, 1)
116					.Add(fBottomLeft, 0, 2)
117					.Add(fBottom, 1, 2)
118					.Add(fBottomRight, 2, 2)
119					.End()
120				.AddGlue()
121				.End()
122			.AddGroup(B_HORIZONTAL, 10)
123				.Add(fXPlacementText)
124				.Add(fYPlacementText)
125				.End()
126			.AddGlue()
127			.SetInsets(10, 10, 10, 10)
128			.End()
129		.AddGlue()
130		.View();
131
132	fPreviewBox->AddChild(view);
133
134	BBox* rightbox = new BBox("rightbox");
135
136	fWorkspaceMenu = new BPopUpMenu(B_TRANSLATE("pick one"));
137	fWorkspaceMenu->AddItem(new BMenuItem(B_TRANSLATE("All workspaces"),
138		new BMessage(kMsgAllWorkspaces)));
139	BMenuItem* menuItem;
140	fWorkspaceMenu->AddItem(menuItem = new BMenuItem(
141		B_TRANSLATE("Current workspace"),
142		new BMessage(kMsgCurrentWorkspace)));
143	menuItem->SetMarked(true);
144	fLastWorkspaceIndex =
145		fWorkspaceMenu->IndexOf(fWorkspaceMenu->FindMarked());
146	fWorkspaceMenu->AddSeparatorItem();
147	fWorkspaceMenu->AddItem(new BMenuItem(B_TRANSLATE("Default folder"),
148		new BMessage(kMsgDefaultFolder)));
149	fWorkspaceMenu->AddItem(new BMenuItem(
150		B_TRANSLATE("Other folder" B_UTF8_ELLIPSIS),
151		new BMessage(kMsgOtherFolder)));
152
153	BMenuField* workspaceMenuField = new BMenuField(BRect(0, 0, 130, 18),
154		"workspaceMenuField", NULL, fWorkspaceMenu, true);
155	workspaceMenuField->ResizeToPreferred();
156	rightbox->SetLabel(workspaceMenuField);
157
158	fImageMenu = new BPopUpMenu(B_TRANSLATE("pick one"));
159	fImageMenu->AddItem(new BGImageMenuItem(B_TRANSLATE("None"), -1,
160		new BMessage(kMsgNoImage)));
161	fImageMenu->AddSeparatorItem();
162	fImageMenu->AddItem(new BMenuItem(B_TRANSLATE("Other" B_UTF8_ELLIPSIS),
163		new BMessage(kMsgOtherImage)));
164
165	BMenuField* imageMenuField = new BMenuField(NULL, fImageMenu);
166	imageMenuField->SetAlignment(B_ALIGN_RIGHT);
167	imageMenuField->ResizeToPreferred();
168
169	fPlacementMenu = new BPopUpMenu(B_TRANSLATE("pick one"));
170	fPlacementMenu->AddItem(new BMenuItem(B_TRANSLATE("Manual"),
171		new BMessage(kMsgManualPlacement)));
172	fPlacementMenu->AddItem(new BMenuItem(B_TRANSLATE("Center"),
173		new BMessage(kMsgCenterPlacement)));
174	fPlacementMenu->AddItem(new BMenuItem(B_TRANSLATE("Scale to fit"),
175		new BMessage(kMsgScalePlacement)));
176	fPlacementMenu->AddItem(new BMenuItem(B_TRANSLATE("Tile"),
177		new BMessage(kMsgTilePlacement)));
178
179	BMenuField* placementMenuField = new BMenuField(NULL, fPlacementMenu);
180	placementMenuField->SetAlignment(B_ALIGN_RIGHT);
181
182	fIconLabelOutline = new BCheckBox(B_TRANSLATE("Icon label outline"),
183		new BMessage(kMsgIconLabelOutline));
184	fIconLabelOutline->SetValue(B_CONTROL_OFF);
185
186	fPicker = new BColorControl(BPoint(0, 0), B_CELLS_32x8, 7.0, "Picker",
187		new BMessage(kMsgUpdateColor));
188
189	BStringView* imageStringView =
190		new BStringView(NULL, B_TRANSLATE("Image:"));
191	BStringView* placementStringView =
192		new BStringView(NULL, B_TRANSLATE("Placement:"));
193
194	imageStringView->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT,
195		B_ALIGN_NO_VERTICAL));
196	placementStringView->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT,
197		B_ALIGN_NO_VERTICAL));
198
199	view = BLayoutBuilder::Group<>()
200		.AddGroup(B_VERTICAL, 10)
201			.AddGroup(B_VERTICAL, 10)
202				.AddGrid(10, 10)
203					.Add(imageStringView, 0, 0)
204					.Add(placementStringView, 0, 1)
205					.Add(imageMenuField, 1, 0)
206					.Add(placementMenuField, 1, 1)
207					.End()
208				.Add(fIconLabelOutline)
209				.End()
210			.Add(fPicker)
211			.SetInsets(10, 10, 10, 10)
212			.End()
213		.View();
214
215	rightbox->AddChild(view);
216
217	fRevert = new BButton(B_TRANSLATE("Revert"),
218		new BMessage(kMsgRevertSettings));
219	fApply = new BButton(B_TRANSLATE("Apply"),
220		new BMessage(kMsgApplySettings));
221
222	fRevert->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
223		B_ALIGN_NO_VERTICAL));
224	fApply->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT,
225		B_ALIGN_NO_VERTICAL));
226
227	view = BLayoutBuilder::Group<>()
228		.AddGroup(B_VERTICAL, 10)
229			.AddGroup(B_HORIZONTAL, 10)
230				.Add(fPreviewBox)
231				.Add(rightbox)
232				.End()
233			.AddGroup(B_HORIZONTAL, 0)
234				.Add(fRevert)
235				.Add(fApply)
236				.End()
237			.SetInsets(10, 10, 10, 10)
238			.End()
239		.View();
240
241	AddChild(view);
242
243	fApply->MakeDefault(true);
244}
245
246
247BackgroundsView::~BackgroundsView()
248{
249	delete fPanel;
250	delete fFolderPanel;
251}
252
253
254void
255BackgroundsView::AllAttached()
256{
257	fPlacementMenu->SetTargetForItems(this);
258	fImageMenu->SetTargetForItems(this);
259	fWorkspaceMenu->SetTargetForItems(this);
260	fXPlacementText->SetTarget(this);
261	fYPlacementText->SetTarget(this);
262	fIconLabelOutline->SetTarget(this);
263	fPicker->SetTarget(this);
264	fApply->SetTarget(this);
265	fRevert->SetTarget(this);
266
267	BPath path;
268	entry_ref ref;
269	if (find_directory(B_SYSTEM_DATA_DIRECTORY, &path) == B_OK) {
270		path.Append("artwork");
271		get_ref_for_path(path.Path(), &ref);
272	}
273
274	BMessenger messenger(this);
275	fPanel = new ImageFilePanel(B_OPEN_PANEL, &messenger, &ref,
276		B_FILE_NODE, false, NULL, new CustomRefFilter(true));
277	fPanel->SetButtonLabel(B_DEFAULT_BUTTON, B_TRANSLATE("Select"));
278
279	fFolderPanel = new BFilePanel(B_OPEN_PANEL, &messenger, NULL,
280		B_DIRECTORY_NODE, false, NULL, new CustomRefFilter(false));
281	fFolderPanel->SetButtonLabel(B_DEFAULT_BUTTON, B_TRANSLATE("Select"));
282
283	_LoadSettings();
284	_LoadDesktopFolder();
285
286	BPoint point;
287	if (fSettings.FindPoint("pos", &point) == B_OK) {
288		fFoundPositionSetting = true;
289		Window()->MoveTo(point);
290	}
291
292	fApply->SetEnabled(false);
293	fRevert->SetEnabled(false);
294}
295
296
297void
298BackgroundsView::MessageReceived(BMessage* msg)
299{
300	switch (msg->what) {
301		case B_SIMPLE_DATA:
302		case B_REFS_RECEIVED:
303			RefsReceived(msg);
304			break;
305
306		case kMsgUpdatePreviewPlacement:
307		{
308			BString xstring, ystring;
309			xstring << (int)fPreview->fPoint.x;
310			ystring << (int)fPreview->fPoint.y;
311			fXPlacementText->SetText(xstring.String());
312			fYPlacementText->SetText(ystring.String());
313			_UpdatePreview();
314			_UpdateButtons();
315			break;
316		}
317
318		case kMsgManualPlacement:
319			_UpdatePreview();
320			_UpdateButtons();
321			break;
322
323		case kMsgTilePlacement:
324		case kMsgScalePlacement:
325		case kMsgCenterPlacement:
326			_UpdatePreview();
327			_UpdateButtons();
328			break;
329
330		case kMsgIconLabelOutline:
331			_UpdateButtons();
332			break;
333
334		case kMsgUpdateColor:
335		case kMsgImagePlacement:
336			_UpdatePreview();
337			_UpdateButtons();
338			break;
339
340		case kMsgCurrentWorkspace:
341		case kMsgAllWorkspaces:
342			fImageMenu->FindItem(kMsgNoImage)->SetLabel(B_TRANSLATE("None"));
343			fLastWorkspaceIndex = fWorkspaceMenu->IndexOf(
344				fWorkspaceMenu->FindMarked());
345			if (fCurrent && fCurrent->IsDesktop()) {
346				_UpdateButtons();
347			} else {
348				_SetDesktop(true);
349				_LoadDesktopFolder();
350			}
351			break;
352
353		case kMsgDefaultFolder:
354			fImageMenu->FindItem(kMsgNoImage)->SetLabel(B_TRANSLATE("None"));
355			fLastWorkspaceIndex = fWorkspaceMenu->IndexOf(
356				fWorkspaceMenu->FindMarked());
357			_SetDesktop(false);
358			_LoadDefaultFolder();
359			break;
360
361		case kMsgOtherFolder:
362			fFolderPanel->Show();
363			break;
364
365		case kMsgOtherImage:
366			fPanel->Show();
367			break;
368
369		case B_CANCEL:
370		{
371			PRINT(("cancel received\n"));
372			void* pointer;
373			msg->FindPointer("source", &pointer);
374			if (pointer == fPanel) {
375				if (fLastImageIndex >= 0)
376					_FindImageItem(fLastImageIndex)->SetMarked(true);
377				else
378					fImageMenu->ItemAt(0)->SetMarked(true);
379			} else if (pointer == fFolderPanel) {
380				if (fLastWorkspaceIndex >= 0)
381					fWorkspaceMenu->ItemAt(fLastWorkspaceIndex)
382						->SetMarked(true);
383			}
384			break;
385		}
386
387		case kMsgImageSelected:
388		case kMsgNoImage:
389			fLastImageIndex = ((BGImageMenuItem*)fImageMenu->FindMarked())
390				->ImageIndex();
391			_UpdatePreview();
392			_UpdateButtons();
393			break;
394
395		case kMsgFolderSelected:
396			fImageMenu->FindItem(kMsgNoImage)->SetLabel(B_TRANSLATE("Default"));
397			fLastWorkspaceIndex = fWorkspaceMenu->IndexOf(
398				fWorkspaceMenu->FindMarked());
399			_SetDesktop(false);
400
401			_LoadRecentFolder(*fPathList.ItemAt(fWorkspaceMenu->IndexOf(
402				fWorkspaceMenu->FindMarked()) - 6));
403			break;
404
405		case kMsgApplySettings:
406		{
407			_Save();
408
409			//_NotifyServer();
410			thread_id notify_thread;
411			notify_thread = spawn_thread(BackgroundsView::_NotifyThread,
412				"notifyServer", B_NORMAL_PRIORITY, this);
413			resume_thread(notify_thread);
414			_UpdateButtons();
415			break;
416		}
417		case kMsgRevertSettings:
418			_UpdateWithCurrent();
419			break;
420
421		default:
422			BView::MessageReceived(msg);
423			break;
424	}
425}
426
427
428void
429BackgroundsView::_LoadDesktopFolder()
430{
431	BPath path;
432	if (find_directory(B_DESKTOP_DIRECTORY, &path) == B_OK) {
433		status_t err;
434		err = get_ref_for_path(path.Path(), &fCurrentRef);
435		if (err != B_OK)
436			printf("error in LoadDesktopSettings\n");
437		_LoadFolder(true);
438	}
439}
440
441
442void
443BackgroundsView::_LoadDefaultFolder()
444{
445	BPath path;
446	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
447		BString pathString = path.Path();
448		pathString << "/Tracker/DefaultFolderTemplate";
449		status_t err;
450		err = get_ref_for_path(pathString.String(), &fCurrentRef);
451		if (err != B_OK)
452			printf("error in LoadDefaultFolderSettings\n");
453		_LoadFolder(false);
454	}
455}
456
457
458void
459BackgroundsView::_LoadRecentFolder(BPath path)
460{
461	status_t err;
462	err = get_ref_for_path(path.Path(), &fCurrentRef);
463	if (err != B_OK)
464		printf("error in LoadRecentFolder\n");
465	_LoadFolder(false);
466}
467
468
469void
470BackgroundsView::_LoadFolder(bool isDesktop)
471{
472	if (fCurrent) {
473		delete fCurrent;
474		fCurrent = NULL;
475	}
476
477	BNode node(&fCurrentRef);
478	if (node.InitCheck() == B_OK)
479		fCurrent = BackgroundImage::GetBackgroundImage(&node, isDesktop, this);
480
481	_UpdateWithCurrent();
482}
483
484
485void
486BackgroundsView::_UpdateWithCurrent(void)
487{
488	if (fCurrent == NULL)
489		return;
490
491	fPlacementMenu->FindItem(kMsgScalePlacement)
492		->SetEnabled(fCurrent->IsDesktop());
493	fPlacementMenu->FindItem(kMsgCenterPlacement)
494		->SetEnabled(fCurrent->IsDesktop());
495
496	if (fWorkspaceMenu->IndexOf(fWorkspaceMenu->FindMarked()) > 5)
497		fImageMenu->FindItem(kMsgNoImage)->SetLabel(B_TRANSLATE("Default"));
498	else
499		fImageMenu->FindItem(kMsgNoImage)->SetLabel(B_TRANSLATE("None"));
500
501	for (int32 i = fImageMenu->CountItems() - 5; i >= 0; i--) {
502		fImageMenu->RemoveItem(2);
503	}
504
505	for (int32 i = fImageList.CountItems() - 1; i >= 0; i--) {
506		BMessage* message = new BMessage(kMsgImageSelected);
507		_AddItem(new BGImageMenuItem(GetImage(i)->GetName(), i, message));
508	}
509
510	fImageMenu->SetTargetForItems(this);
511
512	fCurrentInfo = fCurrent->ImageInfoForWorkspace(current_workspace());
513
514	if (!fCurrentInfo) {
515		fImageMenu->FindItem(kMsgNoImage)->SetMarked(true);
516		fPlacementMenu->FindItem(kMsgManualPlacement)->SetMarked(true);
517		fIconLabelOutline->SetValue(B_CONTROL_ON);
518	} else {
519		fIconLabelOutline->SetValue(fCurrentInfo->fTextWidgetLabelOutline
520			? B_CONTROL_ON : B_CONTROL_OFF);
521
522		fLastImageIndex = fCurrentInfo->fImageIndex;
523		_FindImageItem(fLastImageIndex)->SetMarked(true);
524
525		if (fLastImageIndex > -1) {
526
527			BString xtext, ytext;
528			int32 cmd = 0;
529			switch (fCurrentInfo->fMode) {
530				case BackgroundImage::kCentered:
531					cmd = kMsgCenterPlacement;
532					break;
533				case BackgroundImage::kScaledToFit:
534					cmd = kMsgScalePlacement;
535					break;
536				case BackgroundImage::kAtOffset:
537					cmd = kMsgManualPlacement;
538					xtext << (int)fCurrentInfo->fOffset.x;
539					ytext << (int)fCurrentInfo->fOffset.y;
540					break;
541				case BackgroundImage::kTiled:
542					cmd = kMsgTilePlacement;
543					break;
544			}
545
546			if (cmd != 0)
547				fPlacementMenu->FindItem(cmd)->SetMarked(true);
548
549			fXPlacementText->SetText(xtext.String());
550			fYPlacementText->SetText(ytext.String());
551		} else {
552			fPlacementMenu->FindItem(kMsgManualPlacement)->SetMarked(true);
553		}
554	}
555
556	rgb_color color = {255, 255, 255, 255};
557	if (fCurrent->IsDesktop()) {
558		color = BScreen().DesktopColor();
559		fPicker->SetEnabled(true);
560	} else
561		fPicker->SetEnabled(false);
562
563	fPicker->SetValue(color);
564
565	_UpdatePreview();
566	_UpdateButtons();
567}
568
569
570void
571BackgroundsView::_Save()
572{
573	bool textWidgetLabelOutline
574		= fIconLabelOutline->Value() == B_CONTROL_ON;
575
576	BackgroundImage::Mode mode = _FindPlacementMode();
577	BPoint offset(atoi(fXPlacementText->Text()), atoi(fYPlacementText->Text()));
578
579	if (!fCurrent->IsDesktop()) {
580		if (fCurrentInfo == NULL) {
581			fCurrentInfo = new BackgroundImage::BackgroundImageInfo(
582				B_ALL_WORKSPACES, fLastImageIndex, mode, offset,
583				textWidgetLabelOutline, 0, 0);
584			fCurrent->Add(fCurrentInfo);
585		} else {
586			fCurrentInfo->fTextWidgetLabelOutline = textWidgetLabelOutline;
587			fCurrentInfo->fMode = mode;
588			if (fCurrentInfo->fMode == BackgroundImage::kAtOffset)
589				fCurrentInfo->fOffset = offset;
590			fCurrentInfo->fImageIndex = fLastImageIndex;
591		}
592	} else {
593		uint32 workspaceMask = 1;
594		int32 workspace = current_workspace();
595		for (; workspace; workspace--)
596			workspaceMask *= 2;
597
598		if (fCurrentInfo != NULL) {
599			if (fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()) {
600				if (fCurrentInfo->fWorkspace & workspaceMask
601					&& fCurrentInfo->fWorkspace != workspaceMask) {
602					fCurrentInfo->fWorkspace = fCurrentInfo->fWorkspace
603						^ workspaceMask;
604					fCurrentInfo = new BackgroundImage::BackgroundImageInfo(
605						workspaceMask, fLastImageIndex, mode, offset,
606						textWidgetLabelOutline, fCurrentInfo->fImageSet,
607						fCurrentInfo->fCacheMode);
608					fCurrent->Add(fCurrentInfo);
609				} else if (fCurrentInfo->fWorkspace == workspaceMask) {
610					fCurrentInfo->fTextWidgetLabelOutline
611						= textWidgetLabelOutline;
612					fCurrentInfo->fMode = mode;
613					if (fCurrentInfo->fMode == BackgroundImage::kAtOffset)
614						fCurrentInfo->fOffset = offset;
615
616					fCurrentInfo->fImageIndex = fLastImageIndex;
617				}
618			} else {
619				fCurrent->RemoveAll();
620
621				fCurrentInfo = new BackgroundImage::BackgroundImageInfo(
622					B_ALL_WORKSPACES, fLastImageIndex, mode, offset,
623					textWidgetLabelOutline, fCurrent->GetShowingImageSet(),
624					fCurrentInfo->fCacheMode);
625				fCurrent->Add(fCurrentInfo);
626			}
627		} else {
628			if (fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()) {
629				fCurrentInfo = new BackgroundImage::BackgroundImageInfo(
630					workspaceMask, fLastImageIndex, mode, offset,
631					textWidgetLabelOutline, fCurrent->GetShowingImageSet(), 0);
632			} else {
633				fCurrent->RemoveAll();
634				fCurrentInfo = new BackgroundImage::BackgroundImageInfo(
635					B_ALL_WORKSPACES, fLastImageIndex, mode, offset,
636					textWidgetLabelOutline, fCurrent->GetShowingImageSet(), 0);
637			}
638			fCurrent->Add(fCurrentInfo);
639		}
640
641		if (!fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked()) {
642			for (int32 i = 0; i < count_workspaces(); i++) {
643				BScreen().SetDesktopColor(fPicker->ValueAsColor(), i, true);
644			}
645		} else
646			BScreen().SetDesktopColor(fPicker->ValueAsColor(), true);
647	}
648
649	BNode node(&fCurrentRef);
650
651	status_t status = fCurrent->SetBackgroundImage(&node);
652	if (status != B_OK) {
653		// TODO: this should be a BAlert!
654		printf("setting background image failed: %s\n", strerror(status));
655	}
656}
657
658
659void
660BackgroundsView::_NotifyServer()
661{
662	BMessenger tracker("application/x-vnd.Be-TRAK");
663
664	if (fCurrent->IsDesktop()) {
665		tracker.SendMessage(new BMessage(B_RESTORE_BACKGROUND_IMAGE));
666	} else {
667		int32 i = -1;
668		BMessage reply;
669		int32 err;
670		BEntry currentEntry(&fCurrentRef);
671		BPath currentPath(&currentEntry);
672		bool isCustomFolder
673			= !fWorkspaceMenu->FindItem(kMsgDefaultFolder)->IsMarked();
674
675		do {
676			BMessage msg(B_GET_PROPERTY);
677			i++;
678
679			// look at the "Poses" in every Tracker window
680			msg.AddSpecifier("Poses");
681			msg.AddSpecifier("Window", i);
682
683			reply.MakeEmpty();
684			tracker.SendMessage(&msg, &reply);
685
686			// break out of the loop when we're at the end of
687			// the windows
688			if (reply.what == B_MESSAGE_NOT_UNDERSTOOD
689				&& reply.FindInt32("error", &err) == B_OK
690				&& err == B_BAD_INDEX)
691				break;
692
693			// don't stop for windows that don't understand
694			// a request for "Poses"; they're not displaying
695			// folders
696			if (reply.what == B_MESSAGE_NOT_UNDERSTOOD
697				&& reply.FindInt32("error", &err) == B_OK
698				&& err != B_BAD_SCRIPT_SYNTAX)
699				continue;
700
701			BMessenger trackerWindow;
702			if (reply.FindMessenger("result", &trackerWindow) != B_OK)
703				continue;
704
705			if (isCustomFolder) {
706				// found a window with poses, ask for its path
707				msg.MakeEmpty();
708				msg.what = B_GET_PROPERTY;
709				msg.AddSpecifier("Path");
710				msg.AddSpecifier("Poses");
711				msg.AddSpecifier("Window", i);
712
713				reply.MakeEmpty();
714				tracker.SendMessage(&msg, &reply);
715
716				// go on with the next if this din't have a path
717				if (reply.what == B_MESSAGE_NOT_UNDERSTOOD)
718					continue;
719
720				entry_ref ref;
721				if (reply.FindRef("result", &ref) == B_OK) {
722					BEntry entry(&ref);
723					BPath path(&entry);
724
725					// these are not the paths you're looking for
726					if (currentPath != path)
727						continue;
728				}
729			}
730
731			trackerWindow.SendMessage(B_RESTORE_BACKGROUND_IMAGE);
732		} while (true);
733	}
734}
735
736
737int32
738BackgroundsView::_NotifyThread(void* data)
739{
740	BackgroundsView* view = (BackgroundsView*)data;
741
742	view->_NotifyServer();
743	return B_OK;
744}
745
746
747void
748BackgroundsView::SaveSettings(void)
749{
750	BPath path;
751	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
752		path.Append(SETTINGS_FILE);
753		BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
754
755		BPoint point = Window()->Frame().LeftTop();
756		if (fSettings.ReplacePoint("pos", point) != B_OK)
757			fSettings.AddPoint("pos", point);
758
759		entry_ref ref;
760		BEntry entry;
761
762		fPanel->GetPanelDirectory(&ref);
763		entry.SetTo(&ref);
764		entry.GetPath(&path);
765		if (fSettings.ReplaceString("paneldir", path.Path()) != B_OK)
766			fSettings.AddString("paneldir", path.Path());
767
768		fFolderPanel->GetPanelDirectory(&ref);
769		entry.SetTo(&ref);
770		entry.GetPath(&path);
771		if (fSettings.ReplaceString("folderpaneldir", path.Path()) != B_OK)
772			fSettings.AddString("folderpaneldir", path.Path());
773
774		fSettings.RemoveName("recentfolder");
775		for (int32 i = 0; i < fPathList.CountItems(); i++) {
776			fSettings.AddString("recentfolder", fPathList.ItemAt(i)->Path());
777		}
778
779		fSettings.Flatten(&file);
780	}
781}
782
783
784void
785BackgroundsView::_LoadSettings()
786{
787	fSettings.MakeEmpty();
788
789	BPath path;
790	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
791		return;
792
793	path.Append(SETTINGS_FILE);
794	BFile file(path.Path(), B_READ_ONLY);
795	if (file.InitCheck() != B_OK)
796		return;
797
798	if (fSettings.Unflatten(&file) != B_OK) {
799		printf("Error unflattening settings file %s\n", path.Path());
800		return;
801	}
802
803	PRINT_OBJECT(fSettings);
804
805	BString string;
806	if (fSettings.FindString("paneldir", &string) == B_OK)
807		fPanel->SetPanelDirectory(string.String());
808
809	if (fSettings.FindString("folderpaneldir", &string) == B_OK)
810		fFolderPanel->SetPanelDirectory(string.String());
811
812	int32 index = 0;
813	while (fSettings.FindString("recentfolder", index, &string) == B_OK) {
814		if (index == 0)
815			fWorkspaceMenu->AddSeparatorItem();
816
817		path.SetTo(string.String());
818		int32 i = _AddPath(path);
819		BString s;
820		s << B_TRANSLATE("Folder: ") << path.Leaf();
821		BMenuItem* item = new BMenuItem(s.String(),
822			new BMessage(kMsgFolderSelected));
823		fWorkspaceMenu->AddItem(item, -i - 1 + 6);
824		index++;
825	}
826	fWorkspaceMenu->SetTargetForItems(this);
827
828	PRINT(("Settings Loaded\n"));
829}
830
831
832void
833BackgroundsView::WorkspaceActivated(uint32 oldWorkspaces, bool active)
834{
835	_UpdateWithCurrent();
836}
837
838
839void
840BackgroundsView::_UpdatePreview()
841{
842	bool imageEnabled = !(fImageMenu->FindItem(kMsgNoImage)->IsMarked());
843	if (fPlacementMenu->IsEnabled() ^ imageEnabled)
844		fPlacementMenu->SetEnabled(imageEnabled);
845
846	bool textEnabled
847		= (fPlacementMenu->FindItem(kMsgManualPlacement)->IsMarked())
848		&& imageEnabled;
849	if (fXPlacementText->IsEnabled() ^ textEnabled)
850		fXPlacementText->SetEnabled(textEnabled);
851	if (fYPlacementText->IsEnabled() ^ textEnabled)
852		fYPlacementText->SetEnabled(textEnabled);
853
854	if (textEnabled && (strcmp(fXPlacementText->Text(), "") == 0)) {
855		fXPlacementText->SetText("0");
856		fYPlacementText->SetText("0");
857	}
858	if (!textEnabled) {
859		fXPlacementText->SetText(NULL);
860		fYPlacementText->SetText(NULL);
861	}
862
863	fXPlacementText->TextView()->MakeSelectable(textEnabled);
864	fYPlacementText->TextView()->MakeSelectable(textEnabled);
865	fXPlacementText->TextView()->MakeEditable(textEnabled);
866	fYPlacementText->TextView()->MakeEditable(textEnabled);
867
868	fPreview->ClearViewBitmap();
869
870	int32 index = ((BGImageMenuItem*)fImageMenu->FindMarked())->ImageIndex();
871	if (index >= 0) {
872		BBitmap* bitmap = GetImage(index)->GetBitmap();
873		if (bitmap) {
874			BackgroundImage::BackgroundImageInfo* info
875				= new BackgroundImage::BackgroundImageInfo(0, index,
876					_FindPlacementMode(), BPoint(atoi(fXPlacementText->Text()),
877						atoi(fYPlacementText->Text())),
878					fIconLabelOutline->Value() == B_CONTROL_ON, 0, 0);
879			if (info->fMode == BackgroundImage::kAtOffset) {
880				fPreview->SetEnabled(true);
881				fPreview->fPoint.x = atoi(fXPlacementText->Text());
882				fPreview->fPoint.y = atoi(fYPlacementText->Text());
883			} else
884				fPreview->SetEnabled(false);
885
886			fPreview->fImageBounds = BRect(bitmap->Bounds());
887			fCurrent->Show(info, fPreview);
888
889			delete info;
890		}
891	} else
892		fPreview->SetEnabled(false);
893
894	fPreview->SetViewColor(fPicker->ValueAsColor());
895	fPreview->Invalidate();
896}
897
898
899BackgroundImage::Mode
900BackgroundsView::_FindPlacementMode()
901{
902	BackgroundImage::Mode mode = BackgroundImage::kAtOffset;
903
904	if (fPlacementMenu->FindItem(kMsgCenterPlacement)->IsMarked())
905		mode = BackgroundImage::kCentered;
906	if (fPlacementMenu->FindItem(kMsgScalePlacement)->IsMarked())
907		mode = BackgroundImage::kScaledToFit;
908	if (fPlacementMenu->FindItem(kMsgManualPlacement)->IsMarked())
909		mode = BackgroundImage::kAtOffset;
910	if (fPlacementMenu->FindItem(kMsgTilePlacement)->IsMarked())
911		mode = BackgroundImage::kTiled;
912
913	return mode;
914}
915
916
917void
918BackgroundsView::_UpdateButtons()
919{
920	bool hasChanged = false;
921	if (fPicker->IsEnabled()
922		&& fPicker->ValueAsColor() != BScreen().DesktopColor()) {
923		hasChanged = true;
924	} else if (fCurrentInfo) {
925		if ((fIconLabelOutline->Value() == B_CONTROL_ON)
926			^ fCurrentInfo->fTextWidgetLabelOutline) {
927			hasChanged = true;
928		} else if (_FindPlacementMode() != fCurrentInfo->fMode) {
929			hasChanged = true;
930		} else if (fCurrentInfo->fImageIndex
931			!= ((BGImageMenuItem*)fImageMenu->FindMarked())->ImageIndex()) {
932			hasChanged = true;
933		} else if (fCurrent->IsDesktop()
934			&& ((fCurrentInfo->fWorkspace != B_ALL_WORKSPACES)
935				^ (fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->IsMarked())))
936		{
937			hasChanged = true;
938		} else if (fCurrentInfo->fImageIndex > -1
939			&& fCurrentInfo->fMode == BackgroundImage::kAtOffset) {
940			BString oldString, newString;
941			oldString << (int)fCurrentInfo->fOffset.x;
942			if (oldString != BString(fXPlacementText->Text())) {
943				hasChanged = true;
944			}
945			oldString = "";
946			oldString << (int)fCurrentInfo->fOffset.y;
947			if (oldString != BString(fYPlacementText->Text())) {
948				hasChanged = true;
949			}
950		}
951	} else if (fImageMenu->IndexOf(fImageMenu->FindMarked()) > 0) {
952		hasChanged = true;
953	} else if (fIconLabelOutline->Value() == B_CONTROL_OFF) {
954		hasChanged = true;
955	}
956
957	fApply->SetEnabled(hasChanged);
958	fRevert->SetEnabled(hasChanged);
959}
960
961
962void
963BackgroundsView::RefsReceived(BMessage* msg)
964{
965	if (!msg->HasRef("refs") && msg->HasRef("dir_ref")) {
966		entry_ref dirRef;
967		if (msg->FindRef("dir_ref", &dirRef) == B_OK)
968			msg->AddRef("refs", &dirRef);
969	}
970
971	entry_ref ref;
972	int32 i = 0;
973	BMimeType imageType("image");
974	BPath desktopPath;
975	find_directory(B_DESKTOP_DIRECTORY, &desktopPath);
976
977	while (msg->FindRef("refs", i++, &ref) == B_OK) {
978		BPath path;
979		BEntry entry(&ref, true);
980		path.SetTo(&entry);
981		BNode node(&entry);
982
983		if (node.IsFile()) {
984			BMimeType refType;
985			BMimeType::GuessMimeType(&ref, &refType);
986			if (!imageType.Contains(&refType))
987				continue;
988
989			BGImageMenuItem* item;
990			int32 index = AddImage(path);
991			if (index >= 0) {
992				item = _FindImageItem(index);
993				fLastImageIndex = index;
994			} else {
995				const char* name = GetImage(-index - 1)->GetName();
996				item = new BGImageMenuItem(name, -index - 1,
997					new BMessage(kMsgImageSelected));
998				_AddItem(item);
999				item->SetTarget(this);
1000				fLastImageIndex = -index - 1;
1001			}
1002
1003			// An optional placement may have been sent
1004			int32 placement = 0;
1005			if (msg->FindInt32("placement", &placement) == B_OK) {
1006				BMenuItem* item = fPlacementMenu->FindItem(placement);
1007				if (item)
1008					item->SetMarked(true);
1009			}
1010			item->SetMarked(true);
1011			BMessenger(this).SendMessage(kMsgImageSelected);
1012		} else if (node.IsDirectory()) {
1013			if (desktopPath == path) {
1014				fWorkspaceMenu->FindItem(kMsgCurrentWorkspace)->SetMarked(true);
1015				BMessenger(this).SendMessage(kMsgCurrentWorkspace);
1016				break;
1017			}
1018			BMenuItem* item;
1019			int32 index = _AddPath(path);
1020			if (index >= 0) {
1021				item = fWorkspaceMenu->ItemAt(index + 6);
1022				fLastWorkspaceIndex = index + 6;
1023			} else {
1024				if (fWorkspaceMenu->CountItems() <= 5)
1025					fWorkspaceMenu->AddSeparatorItem();
1026				BString s;
1027				s << B_TRANSLATE("Folder: ") << path.Leaf();
1028				item = new BMenuItem(s.String(),
1029					new BMessage(kMsgFolderSelected));
1030				fWorkspaceMenu->AddItem(item, -index - 1 + 6);
1031				item->SetTarget(this);
1032				fLastWorkspaceIndex = -index - 1 + 6;
1033			}
1034
1035			item->SetMarked(true);
1036			BMessenger(this).SendMessage(kMsgFolderSelected);
1037		}
1038	}
1039}
1040
1041
1042int32
1043BackgroundsView::_AddPath(BPath path)
1044{
1045	int32 count = fPathList.CountItems();
1046	int32 index = 0;
1047	for (; index < count; index++) {
1048		BPath* p = fPathList.ItemAt(index);
1049		int c = BString(p->Path()).ICompare(path.Path());
1050		if (c == 0)
1051			return index;
1052
1053		if (c > 0)
1054			break;
1055	}
1056	fPathList.AddItem(new BPath(path), index);
1057	return -index - 1;
1058}
1059
1060
1061int32
1062BackgroundsView::AddImage(BPath path)
1063{
1064	int32 count = fImageList.CountItems();
1065	int32 index = 0;
1066	for (; index < count; index++) {
1067		Image* image = fImageList.ItemAt(index);
1068		if (image->GetPath() == path)
1069			return index;
1070	}
1071
1072	fImageList.AddItem(new Image(path));
1073	return -index - 1;
1074}
1075
1076
1077Image*
1078BackgroundsView::GetImage(int32 imageIndex)
1079{
1080	return fImageList.ItemAt(imageIndex);
1081}
1082
1083
1084BGImageMenuItem*
1085BackgroundsView::_FindImageItem(const int32 imageIndex)
1086{
1087	if (imageIndex < 0)
1088		return (BGImageMenuItem*)fImageMenu->ItemAt(0);
1089
1090	int32 count = fImageMenu->CountItems() - 2;
1091	int32 index = 2;
1092	for (; index < count; index++) {
1093		BGImageMenuItem* image = (BGImageMenuItem*)fImageMenu->ItemAt(index);
1094		if (image->ImageIndex() == imageIndex)
1095			return image;
1096	}
1097	return NULL;
1098}
1099
1100
1101bool
1102BackgroundsView::_AddItem(BGImageMenuItem* item)
1103{
1104	int32 count = fImageMenu->CountItems() - 2;
1105	int32 index = 2;
1106	if (count < index) {
1107		fImageMenu->AddItem(new BSeparatorItem(), 1);
1108		count = fImageMenu->CountItems() - 2;
1109	}
1110
1111	for (; index < count; index++) {
1112		BGImageMenuItem* image = (BGImageMenuItem*)fImageMenu->ItemAt(index);
1113		int c = (BString(image->Label()).ICompare(BString(item->Label())));
1114		if (c > 0)
1115			break;
1116	}
1117	return fImageMenu->AddItem(item, index);
1118}
1119
1120
1121void
1122BackgroundsView::_SetDesktop(bool isDesktop)
1123{
1124	fTopLeft->SetDesktop(isDesktop);
1125	fTop->SetDesktop(isDesktop);
1126	fTopRight->SetDesktop(isDesktop);
1127	fLeft->SetDesktop(isDesktop);
1128	fRight->SetDesktop(isDesktop);
1129	fBottomLeft->SetDesktop(isDesktop);
1130	fBottom->SetDesktop(isDesktop);
1131	fBottomRight->SetDesktop(isDesktop);
1132
1133	Invalidate();
1134}
1135
1136
1137bool
1138BackgroundsView::FoundPositionSetting()
1139{
1140	return fFoundPositionSetting;
1141}
1142
1143
1144//	#pragma mark -
1145
1146
1147Preview::Preview()
1148	:
1149	BControl("PreView", NULL, NULL, B_WILL_DRAW | B_SUBPIXEL_PRECISE)
1150{
1151	float aspectRatio = BScreen().Frame().Width() / BScreen().Frame().Height();
1152	float previewWidth = 120.0f;
1153	float previewHeight = ceil(previewWidth / aspectRatio);
1154
1155	ResizeTo(previewWidth, previewHeight);
1156	SetExplicitMinSize(BSize(previewWidth, previewHeight));
1157	SetExplicitMaxSize(BSize(previewWidth, previewHeight));
1158}
1159
1160
1161void
1162Preview::AttachedToWindow()
1163{
1164	rgb_color color = ViewColor();
1165	BControl::AttachedToWindow();
1166	SetViewColor(color);
1167}
1168
1169
1170void
1171Preview::MouseDown(BPoint point)
1172{
1173	if (IsEnabled() && Bounds().Contains(point)) {
1174		uint32 buttons;
1175		GetMouse(&point, &buttons);
1176		if (buttons & B_PRIMARY_MOUSE_BUTTON) {
1177			fOldPoint = point;
1178			SetTracking(true);
1179			BScreen().GetMode(&fMode);
1180			fXRatio = Bounds().Width() / fMode.virtual_width;
1181			fYRatio = Bounds().Height() / fMode.virtual_height;
1182			SetMouseEventMask(B_POINTER_EVENTS,
1183				B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY);
1184
1185			BCursor grabbingCursor(B_CURSOR_ID_GRABBING);
1186			SetViewCursor(&grabbingCursor);
1187		}
1188	}
1189}
1190
1191
1192void
1193Preview::MouseUp(BPoint point)
1194{
1195	if (IsTracking()) {
1196		SetTracking(false);
1197		BCursor grabCursor(B_CURSOR_ID_GRAB);
1198		SetViewCursor(&grabCursor);
1199	}
1200}
1201
1202
1203void
1204Preview::MouseMoved(BPoint point, uint32 transit, const BMessage* message)
1205{
1206	if (!IsTracking()) {
1207		BCursor cursor(IsEnabled()
1208			? B_CURSOR_ID_GRAB : B_CURSOR_ID_SYSTEM_DEFAULT);
1209		SetViewCursor(&cursor);
1210	} else {
1211		float x, y;
1212		x = fPoint.x + (point.x - fOldPoint.x) / fXRatio;
1213		y = fPoint.y + (point.y - fOldPoint.y) / fYRatio;
1214		bool min, max, mustSend = false;
1215		min = (x > -fImageBounds.Width());
1216		max = (x < fMode.virtual_width);
1217		if (min && max) {
1218			fOldPoint.x = point.x;
1219			fPoint.x = x;
1220			mustSend = true;
1221		} else {
1222			if (!min && fPoint.x > -fImageBounds.Width()) {
1223				fPoint.x = -fImageBounds.Width();
1224				fOldPoint.x = point.x - (x - fPoint.x) * fXRatio;
1225				mustSend = true;
1226			}
1227			if (!max && fPoint.x < fMode.virtual_width) {
1228				fPoint.x = fMode.virtual_width;
1229				fOldPoint.x = point.x - (x - fPoint.x) * fXRatio;
1230				mustSend = true;
1231			}
1232		}
1233
1234		min = (y > -fImageBounds.Height());
1235		max = (y < fMode.virtual_height);
1236		if (min && max) {
1237			fOldPoint.y = point.y;
1238			fPoint.y = y;
1239			mustSend = true;
1240		} else {
1241			if (!min && fPoint.y > -fImageBounds.Height()) {
1242				fPoint.y = -fImageBounds.Height();
1243				fOldPoint.y = point.y - (y - fPoint.y) * fYRatio;
1244				mustSend = true;
1245			}
1246			if (!max && fPoint.y < fMode.virtual_height) {
1247				fPoint.y = fMode.virtual_height;
1248				fOldPoint.y = point.y - (y - fPoint.y) * fYRatio;
1249				mustSend = true;
1250			}
1251		}
1252
1253		if (mustSend) {
1254			BMessenger messenger(Parent());
1255			messenger.SendMessage(kMsgUpdatePreviewPlacement);
1256		}
1257	}
1258
1259	BControl::MouseMoved(point, transit, message);
1260}
1261
1262
1263//	#pragma mark -
1264
1265
1266BGImageMenuItem::BGImageMenuItem(const char* label, int32 imageIndex,
1267	BMessage* message, char shortcut, uint32 modifiers)
1268	: BMenuItem(label, message, shortcut, modifiers),
1269	fImageIndex(imageIndex)
1270{
1271}
1272
1273
1274//	#pragma mark -
1275
1276
1277FramePart::FramePart(int32 part)
1278	:
1279	BView(NULL, B_WILL_DRAW | B_FRAME_EVENTS),
1280	fFramePart(part),
1281	fIsDesktop(true)
1282{
1283	_SetSizeAndAlignment();
1284}
1285
1286
1287void
1288FramePart::Draw(BRect rect)
1289{
1290	rgb_color color = HighColor();
1291	SetDrawingMode(B_OP_COPY);
1292	SetHighColor(Parent()->ViewColor());
1293
1294	if (fIsDesktop) {
1295		switch (fFramePart) {
1296			case FRAME_TOP_LEFT:
1297				FillRect(rect);
1298				SetHighColor(160, 160, 160);
1299				FillRoundRect(BRect(0, 0, 8, 8), 3, 3);
1300				SetHighColor(96, 96, 96);
1301				StrokeRoundRect(BRect(0, 0, 8, 8), 3, 3);
1302				break;
1303
1304			case FRAME_TOP:
1305				SetHighColor(160, 160, 160);
1306				FillRect(BRect(0, 1, rect.right, 3));
1307				SetHighColor(96, 96, 96);
1308				StrokeLine(BPoint(0, 0), BPoint(rect.right, 0));
1309				SetHighColor(0, 0, 0);
1310				StrokeLine(BPoint(0, 4), BPoint(rect.right, 4));
1311				break;
1312
1313			case FRAME_TOP_RIGHT:
1314				FillRect(rect);
1315				SetHighColor(160, 160, 160);
1316				FillRoundRect(BRect(-4, 0, 4, 8), 3, 3);
1317				SetHighColor(96, 96, 96);
1318				StrokeRoundRect(BRect(-4, 0, 4, 8), 3, 3);
1319				break;
1320
1321			case FRAME_LEFT_SIDE:
1322				SetHighColor(160, 160, 160);
1323				FillRect(BRect(1, 0, 3, rect.bottom));
1324				SetHighColor(96, 96, 96);
1325				StrokeLine(BPoint(0, 0), BPoint(0, rect.bottom));
1326				SetHighColor(0, 0, 0);
1327				StrokeLine(BPoint(4, 0), BPoint(4, rect.bottom));
1328				break;
1329
1330			case FRAME_RIGHT_SIDE:
1331				SetHighColor(160, 160, 160);
1332				FillRect(BRect(1, 0, 3, rect.bottom));
1333				SetHighColor(0, 0, 0);
1334				StrokeLine(BPoint(0, 0), BPoint(0, rect.bottom));
1335				SetHighColor(96, 96, 96);
1336				StrokeLine(BPoint(4, 0), BPoint(4, rect.bottom));
1337				break;
1338
1339			case FRAME_BOTTOM_LEFT:
1340				FillRect(rect);
1341				SetHighColor(160, 160, 160);
1342				FillRoundRect(BRect(0, -4, 8, 4), 3, 3);
1343				SetHighColor(96, 96, 96);
1344				StrokeRoundRect(BRect(0, -4, 8, 4), 3, 3);
1345				break;
1346
1347			case FRAME_BOTTOM:
1348				SetHighColor(160, 160, 160);
1349				FillRect(BRect(0, 1, rect.right, 3));
1350				SetHighColor(0, 0, 0);
1351				StrokeLine(BPoint(0, 0), BPoint(rect.right, 0));
1352				SetHighColor(96, 96, 96);
1353				StrokeLine(BPoint(0, 4), BPoint(rect.right, 4));
1354				SetHighColor(228, 0, 0);
1355				StrokeLine(BPoint(5, 2), BPoint(7, 2));
1356				break;
1357
1358			case FRAME_BOTTOM_RIGHT:
1359				FillRect(rect);
1360				SetHighColor(160, 160, 160);
1361				FillRoundRect(BRect(-4, -4, 4, 4), 3, 3);
1362				SetHighColor(96, 96, 96);
1363				StrokeRoundRect(BRect(-4, -4, 4, 4), 3, 3);
1364				break;
1365
1366			default:
1367				break;
1368		}
1369	} else {
1370		switch (fFramePart) {
1371			case FRAME_TOP_LEFT:
1372				SetHighColor(152, 152, 152);
1373				StrokeLine(BPoint(0, 0), BPoint(0, 12));
1374				StrokeLine(BPoint(0, 0), BPoint(4, 0));
1375				StrokeLine(BPoint(3, 12), BPoint(3, 12));
1376				SetHighColor(255, 203, 0);
1377				FillRect(BRect(1, 1, 3, 9));
1378				SetHighColor(240, 240, 240);
1379				StrokeLine(BPoint(1, 12), BPoint(1, 10));
1380				StrokeLine(BPoint(2, 10), BPoint(3, 10));
1381				SetHighColor(200, 200, 200);
1382				StrokeLine(BPoint(2, 12), BPoint(2, 11));
1383				StrokeLine(BPoint(3, 11), BPoint(3, 11));
1384				break;
1385
1386			case FRAME_TOP:
1387				FillRect(BRect(54, 0, rect.right, 8));
1388				SetHighColor(255, 203, 0);
1389				FillRect(BRect(0, 1, 52, 9));
1390				SetHighColor(152, 152, 152);
1391				StrokeLine(BPoint(0, 0), BPoint(53, 0));
1392				StrokeLine(BPoint(53, 1), BPoint(53, 9));
1393				StrokeLine(BPoint(54, 9), BPoint(rect.right, 9));
1394				SetHighColor(240, 240, 240);
1395				StrokeLine(BPoint(0, 10), BPoint(rect.right, 10));
1396				SetHighColor(200, 200, 200);
1397				StrokeLine(BPoint(0, 11), BPoint(rect.right, 11));
1398				SetHighColor(152, 152, 152);
1399				StrokeLine(BPoint(0, 12), BPoint(rect.right, 12));
1400				break;
1401
1402			case FRAME_TOP_RIGHT:
1403				FillRect(BRect(0, 0, 3, 8));
1404				SetHighColor(152, 152, 152);
1405				StrokeLine(BPoint(0, 12), BPoint(0, 12));
1406				StrokeLine(BPoint(0, 9), BPoint(3, 9));
1407				StrokeLine(BPoint(3, 12), BPoint(3, 9));
1408				SetHighColor(240, 240, 240);
1409				StrokeLine(BPoint(0, 10), BPoint(2, 10));
1410				StrokeLine(BPoint(1, 12), BPoint(1, 12));
1411				SetHighColor(200, 200, 200);
1412				StrokeLine(BPoint(2, 12), BPoint(2, 12));
1413				StrokeLine(BPoint(0, 11), BPoint(2, 11));
1414				break;
1415
1416			case FRAME_LEFT_SIDE:
1417			case FRAME_RIGHT_SIDE:
1418				SetHighColor(152, 152, 152);
1419				StrokeLine(BPoint(0, 0), BPoint(0, rect.bottom));
1420				SetHighColor(240, 240, 240);
1421				StrokeLine(BPoint(1, 0), BPoint(1, rect.bottom));
1422				SetHighColor(200, 200, 200);
1423				StrokeLine(BPoint(2, 0), BPoint(2, rect.bottom));
1424				SetHighColor(152, 152, 152);
1425				StrokeLine(BPoint(3, 0), BPoint(3, rect.bottom));
1426				break;
1427
1428			case FRAME_BOTTOM_LEFT:
1429				SetHighColor(152, 152, 152);
1430				StrokeLine(BPoint(0, 0), BPoint(0, 3));
1431				StrokeLine(BPoint(0, 3), BPoint(3, 3));
1432				StrokeLine(BPoint(3, 0), BPoint(3, 0));
1433				SetHighColor(240, 240, 240);
1434				StrokeLine(BPoint(1, 0), BPoint(1, 2));
1435				StrokeLine(BPoint(3, 1), BPoint(3, 1));
1436				SetHighColor(200, 200, 200);
1437				StrokeLine(BPoint(2, 0), BPoint(2, 2));
1438				StrokeLine(BPoint(3, 2), BPoint(3, 2));
1439				break;
1440
1441			case FRAME_BOTTOM:
1442				SetHighColor(152, 152, 152);
1443				StrokeLine(BPoint(0, 0), BPoint(rect.right, 0));
1444				SetHighColor(240, 240, 240);
1445				StrokeLine(BPoint(0, 1), BPoint(rect.right, 1));
1446				SetHighColor(200, 200, 200);
1447				StrokeLine(BPoint(0, 2), BPoint(rect.right, 2));
1448				SetHighColor(152, 152, 152);
1449				StrokeLine(BPoint(0, 3), BPoint(rect.right, 3));
1450				break;
1451
1452			case FRAME_BOTTOM_RIGHT:
1453				SetHighColor(152, 152, 152);
1454				StrokeLine(BPoint(0, 0), BPoint(0, 0));
1455				SetHighColor(240, 240, 240);
1456				StrokeLine(BPoint(1, 0), BPoint(1, 1));
1457				StrokeLine(BPoint(0, 1), BPoint(0, 1));
1458				SetHighColor(200, 200, 200);
1459				StrokeLine(BPoint(2, 0), BPoint(2, 2));
1460				StrokeLine(BPoint(0, 2), BPoint(1, 2));
1461				SetHighColor(152, 152, 152);
1462				StrokeLine(BPoint(3, 0), BPoint(3, 3));
1463				StrokeLine(BPoint(0, 3), BPoint(2, 3));
1464				break;
1465
1466			default:
1467				break;
1468		}
1469	}
1470
1471	SetHighColor(color);
1472}
1473
1474
1475void
1476FramePart::SetDesktop(bool isDesktop)
1477{
1478	fIsDesktop = isDesktop;
1479
1480	_SetSizeAndAlignment();
1481	Invalidate();
1482}
1483
1484
1485void
1486FramePart::_SetSizeAndAlignment()
1487{
1488	if (fIsDesktop) {
1489		switch (fFramePart) {
1490			case FRAME_TOP_LEFT:
1491				SetExplicitMinSize(BSize(4, 4));
1492				SetExplicitMaxSize(BSize(4, 4));
1493				break;
1494
1495			case FRAME_TOP:
1496				SetExplicitMinSize(BSize(1, 4));
1497				SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 4));
1498				break;
1499
1500			case FRAME_TOP_RIGHT:
1501				SetExplicitMinSize(BSize(4, 4));
1502				SetExplicitMaxSize(BSize(4, 4));
1503				break;
1504
1505			case FRAME_LEFT_SIDE:
1506				SetExplicitMinSize(BSize(4, 1));
1507				SetExplicitMaxSize(BSize(4, B_SIZE_UNLIMITED));
1508				break;
1509
1510			case FRAME_RIGHT_SIDE:
1511				SetExplicitMinSize(BSize(4, 1));
1512				SetExplicitMaxSize(BSize(4, B_SIZE_UNLIMITED));
1513				break;
1514
1515			case FRAME_BOTTOM_LEFT:
1516				SetExplicitMinSize(BSize(4, 4));
1517				SetExplicitMaxSize(BSize(4, 4));
1518				break;
1519
1520			case FRAME_BOTTOM:
1521				SetExplicitMinSize(BSize(1, 4));
1522				SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 4));
1523				break;
1524
1525			case FRAME_BOTTOM_RIGHT:
1526				SetExplicitMaxSize(BSize(4, 4));
1527				SetExplicitMinSize(BSize(4, 4));
1528				break;
1529
1530			default:
1531				break;
1532		}
1533	} else {
1534		switch (fFramePart) {
1535			case FRAME_TOP_LEFT:
1536				SetExplicitMinSize(BSize(3, 12));
1537				SetExplicitMaxSize(BSize(3, 12));
1538				break;
1539
1540			case FRAME_TOP:
1541				SetExplicitMinSize(BSize(1, 12));
1542				SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 12));
1543				break;
1544
1545			case FRAME_TOP_RIGHT:
1546				SetExplicitMinSize(BSize(3, 12));
1547				SetExplicitMaxSize(BSize(3, 12));
1548				break;
1549
1550			case FRAME_LEFT_SIDE:
1551				SetExplicitMinSize(BSize(3, 1));
1552				SetExplicitMaxSize(BSize(3, B_SIZE_UNLIMITED));
1553				break;
1554
1555			case FRAME_RIGHT_SIDE:
1556				SetExplicitMinSize(BSize(3, 1));
1557				SetExplicitMaxSize(BSize(3, B_SIZE_UNLIMITED));
1558				break;
1559
1560			case FRAME_BOTTOM_LEFT:
1561				SetExplicitMinSize(BSize(3, 3));
1562				SetExplicitMaxSize(BSize(3, 3));
1563				break;
1564
1565			case FRAME_BOTTOM:
1566				SetExplicitMinSize(BSize(1, 3));
1567				SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 3));
1568				break;
1569
1570			case FRAME_BOTTOM_RIGHT:
1571				SetExplicitMaxSize(BSize(3, 3));
1572				SetExplicitMinSize(BSize(3, 3));
1573				break;
1574
1575			default:
1576				break;
1577		}
1578	}
1579
1580	switch (fFramePart) {
1581		case FRAME_TOP_LEFT:
1582			SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT, B_ALIGN_BOTTOM));
1583			break;
1584
1585		case FRAME_TOP:
1586			SetExplicitAlignment(BAlignment(B_ALIGN_CENTER, B_ALIGN_BOTTOM));
1587			break;
1588
1589		case FRAME_TOP_RIGHT:
1590			SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_BOTTOM));
1591			break;
1592
1593		case FRAME_LEFT_SIDE:
1594			SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT, B_ALIGN_MIDDLE));
1595			break;
1596
1597		case FRAME_RIGHT_SIDE:
1598			SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_MIDDLE));
1599			break;
1600
1601		case FRAME_BOTTOM_LEFT:
1602			SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT, B_ALIGN_TOP));
1603			break;
1604
1605		case FRAME_BOTTOM:
1606			SetExplicitAlignment(BAlignment(B_ALIGN_CENTER, B_ALIGN_TOP));
1607			break;
1608
1609		case FRAME_BOTTOM_RIGHT:
1610			SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP));
1611			break;
1612
1613		default:
1614			break;
1615	}
1616}
1617
1618