xref: /haiku/src/preferences/appearance/LookAndFeelSettingsView.cpp (revision 9e54316c528c34ee76f4d0d21150ceadd031c4de)
1 /*
2  *  Copyright 2010-2012 Haiku, Inc. All rights reserved.
3  *  Distributed under the terms of the MIT license.
4  *
5  *	Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  *		Alexander von Gluck <kallisti5@unixzen.com>
8  *		John Scipione <jscipione@gmail.com>
9  *		Ryan Leavengood <leavengood@gmail.com>
10  */
11 
12 
13 #include "LookAndFeelSettingsView.h"
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 
18 #include <Alert.h>
19 #include <Alignment.h>
20 #include <AppFileInfo.h>
21 #include <Box.h>
22 #include <Button.h>
23 #include <Catalog.h>
24 #include <CheckBox.h>
25 #include <File.h>
26 #include <InterfaceDefs.h>
27 #include <InterfacePrivate.h>
28 #include <LayoutBuilder.h>
29 #include <Locale.h>
30 #include <MenuField.h>
31 #include <MenuItem.h>
32 #include <Path.h>
33 #include <PathFinder.h>
34 #include <PopUpMenu.h>
35 #include <ScrollBar.h>
36 #include <StringView.h>
37 #include <Size.h>
38 #include <Slider.h>
39 #include <SpaceLayoutItem.h>
40 #include <StringView.h>
41 #include <TextView.h>
42 
43 #include "APRWindow.h"
44 #include "FakeScrollBar.h"
45 
46 
47 #undef B_TRANSLATION_CONTEXT
48 #define B_TRANSLATION_CONTEXT "DecorSettingsView"
49 	// This was not renamed to keep from breaking translations
50 
51 
52 static const int32 kMsgSetDecor = 'deco';
53 static const int32 kMsgDecorInfo = 'idec';
54 
55 static const int32 kMsgSetControlLook = 'ctlk';
56 static const int32 kMsgControlLookInfo = 'iclk';
57 
58 static const int32 kMsgDoubleScrollBarArrows = 'dsba';
59 
60 static const int32 kMsgArrowStyleSingle = 'mass';
61 static const int32 kMsgArrowStyleDouble = 'masd';
62 
63 static const int32 kMsgKnobStyleNone = 'mksn';
64 static const int32 kMsgKnobStyleDots = 'mksd';
65 static const int32 kMsgKnobStyleLines = 'mksl';
66 
67 static const bool kDefaultDoubleScrollBarArrowsSetting = false;
68 
69 
70 //	#pragma mark -
71 
72 
73 LookAndFeelSettingsView::LookAndFeelSettingsView(const char* name)
74 	:
75 	BView(name, 0),
76 	fDecorInfoButton(NULL),
77 	fDecorMenuField(NULL),
78 	fDecorMenu(NULL),
79 	fControlLookInfoButton(NULL),
80 	fControlLookMenuField(NULL),
81 	fControlLookMenu(NULL)
82 {
83 	// Decorator menu
84 	_BuildDecorMenu();
85 	fDecorMenuField = new BMenuField("decorator",
86 		B_TRANSLATE("Decorator:"), fDecorMenu);
87 
88 	fDecorInfoButton = new BButton(B_TRANSLATE("About"),
89 		new BMessage(kMsgDecorInfo));
90 
91 	// ControlLook menu
92 	_BuildControlLookMenu();
93 	fControlLookMenuField = new BMenuField("controllook",
94 		B_TRANSLATE("ControlLook:"), fControlLookMenu);
95 	fControlLookMenuField->SetToolTip(B_TRANSLATE("No effect on running applications"));
96 
97 	fControlLookInfoButton = new BButton(B_TRANSLATE("About"),
98 		new BMessage(kMsgControlLookInfo));
99 
100 	// scroll bar arrow style
101 	BBox* arrowStyleBox = new BBox("arrow style");
102 	arrowStyleBox->SetLabel(B_TRANSLATE("Arrow style"));
103 
104 	fSavedDoubleArrowsValue = _DoubleScrollBarArrows();
105 
106 	fArrowStyleSingle = new FakeScrollBar(true, false,
107 		new BMessage(kMsgArrowStyleSingle));
108 	fArrowStyleDouble = new FakeScrollBar(true, true,
109 		new BMessage(kMsgArrowStyleDouble));
110 
111 	BView* arrowStyleView;
112 	arrowStyleView = BLayoutBuilder::Group<>()
113 		.AddGroup(B_VERTICAL, 1)
114 			.Add(new BStringView("single", B_TRANSLATE("Single:")))
115 			.Add(fArrowStyleSingle)
116 			.AddStrut(B_USE_DEFAULT_SPACING)
117 			.Add(new BStringView("double", B_TRANSLATE("Double:")))
118 			.Add(fArrowStyleDouble)
119 			.SetInsets(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING,
120 				B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING)
121 			.End()
122 		.View();
123 	arrowStyleBox->AddChild(arrowStyleView);
124 	arrowStyleBox->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
125 		B_ALIGN_VERTICAL_CENTER));
126 	arrowStyleBox->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
127 
128 	BStringView* scrollBarLabel
129 		= new BStringView("scroll bar", B_TRANSLATE("Scroll bar:"));
130 	scrollBarLabel->SetExplicitAlignment(
131 		BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP));
132 
133 	// control layout
134 	BLayoutBuilder::Grid<>(this, B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING)
135 		.Add(fDecorMenuField->CreateLabelLayoutItem(), 0, 0)
136 		.Add(fDecorMenuField->CreateMenuBarLayoutItem(), 1, 0)
137 		.Add(fDecorInfoButton, 2, 0)
138 		.Add(fControlLookMenuField->CreateLabelLayoutItem(), 0, 1)
139 		.Add(fControlLookMenuField->CreateMenuBarLayoutItem(), 1, 1)
140 		.Add(fControlLookInfoButton, 2, 1)
141 		.Add(scrollBarLabel, 0, 2)
142 		.Add(arrowStyleBox, 1, 2)
143 		.AddGlue(0, 3)
144 		.SetInsets(B_USE_WINDOW_SPACING);
145 
146 	// TODO : Decorator Preview Image?
147 }
148 
149 
150 LookAndFeelSettingsView::~LookAndFeelSettingsView()
151 {
152 }
153 
154 
155 void
156 LookAndFeelSettingsView::AttachedToWindow()
157 {
158 	AdoptParentColors();
159 
160 	if (Parent() == NULL)
161 		SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
162 
163 	fDecorMenu->SetTargetForItems(this);
164 	fDecorInfoButton->SetTarget(this);
165 	fControlLookMenu->SetTargetForItems(this);
166 	fControlLookInfoButton->SetTarget(this);
167 	fArrowStyleSingle->SetTarget(this);
168 	fArrowStyleDouble->SetTarget(this);
169 
170 	if (fSavedDoubleArrowsValue)
171 		fArrowStyleDouble->SetValue(B_CONTROL_ON);
172 	else
173 		fArrowStyleSingle->SetValue(B_CONTROL_ON);
174 }
175 
176 
177 void
178 LookAndFeelSettingsView::MessageReceived(BMessage *msg)
179 {
180 	switch (msg->what) {
181 		case kMsgSetDecor:
182 		{
183 			BString newDecor;
184 			if (msg->FindString("decor", &newDecor) == B_OK)
185 				_SetDecor(newDecor);
186 			break;
187 		}
188 
189 		case kMsgDecorInfo:
190 		{
191 			DecorInfo* decor = fDecorUtility.FindDecorator(fCurrentDecor);
192 			if (decor == NULL)
193 				break;
194 
195 			BString authorsText(decor->Authors().String());
196 			authorsText.ReplaceAll(", ", "\n\t");
197 
198 			BString infoText(B_TRANSLATE("%decorName\n\n"
199 				"Authors:\n\t%decorAuthors\n\n"
200 				"URL: %decorURL\n"
201 				"License: %decorLic\n\n"
202 				"%decorDesc\n"));
203 
204 
205 			infoText.ReplaceFirst("%decorName", decor->Name().String());
206 			infoText.ReplaceFirst("%decorAuthors", authorsText.String());
207 			infoText.ReplaceFirst("%decorLic", decor->LicenseName().String());
208 			infoText.ReplaceFirst("%decorURL", decor->SupportURL().String());
209 			infoText.ReplaceFirst("%decorDesc", decor->ShortDescription().String());
210 
211 			BAlert *infoAlert = new BAlert(B_TRANSLATE("About decorator"),
212 				infoText.String(), B_TRANSLATE("OK"));
213 			infoAlert->SetFlags(infoAlert->Flags() | B_CLOSE_ON_ESCAPE);
214 			infoAlert->Go();
215 
216 			break;
217 		}
218 
219 		case kMsgSetControlLook:
220 		{
221 			BString newControlLook;
222 			if (msg->FindString("control_look", &newControlLook) == B_OK) {
223 				BPrivate::set_control_look(newControlLook);
224 			}
225 			break;
226 		}
227 
228 		case kMsgControlLookInfo:
229 		{
230 			BString infoText(B_TRANSLATE("Default Haiku ControlLook"));
231 			BString path;
232 			if (!BPrivate::get_control_look(path))
233 				break;
234 
235 			if (path.Length()) {
236 				BFile file(path.String(), B_READ_ONLY);
237 				if (file.InitCheck() != B_OK)
238 					break;
239 
240 				BAppFileInfo info(&file);
241 				struct version_info version;
242 				if (info.InitCheck() != B_OK
243 					|| info.GetVersionInfo(&version, B_APP_VERSION_KIND) != B_OK)
244 					break;
245 
246 				infoText = version.short_info;
247 				infoText << "\n" << version.long_info;
248 			}
249 
250 			BAlert *infoAlert = new BAlert(B_TRANSLATE("About control look"),
251 				infoText.String(), B_TRANSLATE("OK"));
252 			infoAlert->SetFlags(infoAlert->Flags() | B_CLOSE_ON_ESCAPE);
253 			infoAlert->Go();
254 
255 			break;
256 		}
257 
258 		case kMsgArrowStyleSingle:
259 			_SetDoubleScrollBarArrows(false);
260 			break;
261 
262 		case kMsgArrowStyleDouble:
263 			_SetDoubleScrollBarArrows(true);
264 			break;
265 
266 		default:
267 			BView::MessageReceived(msg);
268 			break;
269 	}
270 }
271 
272 
273 void
274 LookAndFeelSettingsView::_BuildDecorMenu()
275 {
276 	fDecorMenu = new BPopUpMenu(B_TRANSLATE("Choose Decorator"));
277 
278 	// collect the current system decor settings
279 	int32 count = fDecorUtility.CountDecorators();
280 	for (int32 i = 0; i < count; ++i) {
281 		DecorInfo* decorator = fDecorUtility.DecoratorAt(i);
282 		if (decorator == NULL) {
283 			fprintf(stderr, "Decorator : error NULL entry @ %" B_PRId32
284 				" / %" B_PRId32 "\n", i, count);
285 			continue;
286 		}
287 
288 		BString decorName = decorator->Name();
289 
290 		BMessage* message = new BMessage(kMsgSetDecor);
291 		message->AddString("decor", decorName);
292 
293 		BMenuItem* item = new BMenuItem(decorName, message);
294 
295 		fDecorMenu->AddItem(item);
296 	}
297 
298 	_AdoptToCurrentDecor();
299 }
300 
301 
302 void
303 LookAndFeelSettingsView::_BuildControlLookMenu()
304 {
305 	BPathFinder pathFinder;
306 	BStringList paths;
307 	BDirectory dir;
308 	BString currentLook;
309 
310 	BPrivate::get_control_look(currentLook);
311 
312 	fControlLookMenu = new BPopUpMenu(B_TRANSLATE("Choose ControlLook"));
313 
314 	BMessage* message = new BMessage(kMsgSetControlLook);
315 	message->AddString("control_look", "");
316 
317 	BMenuItem* item = new BMenuItem(B_TRANSLATE("Default"), message);
318 	if (currentLook == "")
319 		item->SetMarked(true);
320 	fControlLookMenu->AddItem(item);
321 
322 	status_t error = pathFinder.FindPaths(B_FIND_PATH_ADD_ONS_DIRECTORY,
323 		"control_look", paths);
324 
325 	for (int i = 0; i < paths.CountStrings(); ++i) {
326 		if (error != B_OK || dir.SetTo(paths.StringAt(i)) != B_OK)
327 			continue;
328 
329 		BEntry entry;
330 		for (; dir.GetNextEntry(&entry) == B_OK;) {
331 			BPath path(paths.StringAt(i), entry.Name());
332 			BString name(entry.Name());
333 			name.RemoveLast("ControlLook");
334 			name.Trim();
335 
336 			message = new BMessage(kMsgSetControlLook);
337 			message->AddString("control_look", path.Path());
338 
339 			item = new BMenuItem(name.String(), message);
340 			if (currentLook == path.Path())
341 				item->SetMarked(true);
342 			fControlLookMenu->AddItem(item);
343 		}
344 	}
345 }
346 
347 
348 void
349 LookAndFeelSettingsView::_SetDecor(const BString& name)
350 {
351 	_SetDecor(fDecorUtility.FindDecorator(name));
352 }
353 
354 
355 void
356 LookAndFeelSettingsView::_SetDecor(DecorInfo* decorInfo)
357 {
358 	if (fDecorUtility.SetDecorator(decorInfo) == B_OK) {
359 		_AdoptToCurrentDecor();
360 		Window()->PostMessage(kMsgUpdate);
361 	}
362 }
363 
364 
365 void
366 LookAndFeelSettingsView::_AdoptToCurrentDecor()
367 {
368 	fCurrentDecor = fDecorUtility.CurrentDecorator()->Name();
369 	if (fSavedDecor.Length() == 0)
370 		fSavedDecor = fCurrentDecor;
371 	_AdoptInterfaceToCurrentDecor();
372 }
373 
374 void
375 LookAndFeelSettingsView::_AdoptInterfaceToCurrentDecor()
376 {
377 	BMenuItem* item = fDecorMenu->FindItem(fCurrentDecor);
378 	if (item != NULL)
379 		item->SetMarked(true);
380 }
381 
382 
383 bool
384 LookAndFeelSettingsView::_DoubleScrollBarArrows()
385 {
386 	scroll_bar_info info;
387 	get_scroll_bar_info(&info);
388 
389 	return info.double_arrows;
390 }
391 
392 
393 void
394 LookAndFeelSettingsView::_SetDoubleScrollBarArrows(bool doubleArrows)
395 {
396 	scroll_bar_info info;
397 	get_scroll_bar_info(&info);
398 
399 	info.double_arrows = doubleArrows;
400 	set_scroll_bar_info(&info);
401 
402 	if (doubleArrows)
403 		fArrowStyleDouble->SetValue(B_CONTROL_ON);
404 	else
405 		fArrowStyleSingle->SetValue(B_CONTROL_ON);
406 
407 	Window()->PostMessage(kMsgUpdate);
408 }
409 
410 
411 bool
412 LookAndFeelSettingsView::IsDefaultable()
413 {
414 	return fCurrentDecor != fDecorUtility.DefaultDecorator()->Name()
415 		|| _DoubleScrollBarArrows() != false;
416 }
417 
418 
419 void
420 LookAndFeelSettingsView::SetDefaults()
421 {
422 	_SetDecor(fDecorUtility.DefaultDecorator());
423 	BPrivate::set_control_look(BString(""));
424 	_SetDoubleScrollBarArrows(false);
425 }
426 
427 
428 bool
429 LookAndFeelSettingsView::IsRevertable()
430 {
431 	return fCurrentDecor != fSavedDecor
432 		|| _DoubleScrollBarArrows() != fSavedDoubleArrowsValue;
433 }
434 
435 
436 void
437 LookAndFeelSettingsView::Revert()
438 {
439 	if (IsRevertable()) {
440 		_SetDecor(fSavedDecor);
441 		_SetDoubleScrollBarArrows(fSavedDoubleArrowsValue);
442 	}
443 }
444