1 /*
2 * Copyright 2010-2020 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 bool kDefaultDoubleScrollBarArrowsSetting = false;
64
65
66 // #pragma mark - LookAndFeelSettingsView
67
68
LookAndFeelSettingsView(const char * name)69 LookAndFeelSettingsView::LookAndFeelSettingsView(const char* name)
70 :
71 BView(name, 0),
72 fDecorInfoButton(NULL),
73 fDecorMenuField(NULL),
74 fDecorMenu(NULL),
75 fControlLookInfoButton(NULL),
76 fControlLookMenuField(NULL),
77 fControlLookMenu(NULL),
78 fArrowStyleSingle(NULL),
79 fArrowStyleDouble(NULL),
80 fSavedDecor(NULL),
81 fCurrentDecor(NULL),
82 fSavedControlLook(NULL),
83 fCurrentControlLook(NULL),
84 fSavedDoubleArrowsValue(_DoubleScrollBarArrows())
85 {
86 fCurrentDecor = fDecorUtility.CurrentDecorator()->ShortcutName();
87 fSavedDecor = fCurrentDecor;
88
89 // Decorator menu
90 _BuildDecorMenu();
91 fDecorMenuField = new BMenuField("decorator",
92 B_TRANSLATE("Decorator:"), fDecorMenu);
93
94 fDecorInfoButton = new BButton(B_TRANSLATE("About"),
95 new BMessage(kMsgDecorInfo));
96
97 BPrivate::get_control_look(fCurrentControlLook);
98 fSavedControlLook = fCurrentControlLook;
99
100 // ControlLook menu
101 _BuildControlLookMenu();
102 fControlLookMenuField = new BMenuField("controllook",
103 B_TRANSLATE("ControlLook:"), fControlLookMenu);
104 fControlLookMenuField->SetToolTip(
105 B_TRANSLATE("No effect on running applications"));
106
107 fControlLookInfoButton = new BButton(B_TRANSLATE("About"),
108 new BMessage(kMsgControlLookInfo));
109
110 // scroll bar arrow style
111 BBox* arrowStyleBox = new BBox("arrow style");
112 arrowStyleBox->SetLabel(B_TRANSLATE("Arrow style"));
113
114 fArrowStyleSingle = new FakeScrollBar(true, false,
115 new BMessage(kMsgArrowStyleSingle));
116 fArrowStyleDouble = new FakeScrollBar(true, true,
117 new BMessage(kMsgArrowStyleDouble));
118
119 BView* arrowStyleView;
120 arrowStyleView = BLayoutBuilder::Group<>()
121 .AddGroup(B_VERTICAL, 1)
122 .Add(new BStringView("single", B_TRANSLATE("Single:")))
123 .Add(fArrowStyleSingle)
124 .AddStrut(B_USE_DEFAULT_SPACING)
125 .Add(new BStringView("double", B_TRANSLATE("Double:")))
126 .Add(fArrowStyleDouble)
127 .SetInsets(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING,
128 B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING)
129 .End()
130 .View();
131 arrowStyleBox->AddChild(arrowStyleView);
132 arrowStyleBox->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
133 B_ALIGN_VERTICAL_CENTER));
134 arrowStyleBox->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
135
136 BStringView* scrollBarLabel
137 = new BStringView("scroll bar", B_TRANSLATE("Scroll bar:"));
138 scrollBarLabel->SetExplicitAlignment(
139 BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP));
140
141 // control layout
142 BLayoutBuilder::Grid<>(this, B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING)
143 .Add(fDecorMenuField->CreateLabelLayoutItem(), 0, 0)
144 .Add(fDecorMenuField->CreateMenuBarLayoutItem(), 1, 0)
145 .Add(fDecorInfoButton, 2, 0)
146 .Add(fControlLookMenuField->CreateLabelLayoutItem(), 0, 1)
147 .Add(fControlLookMenuField->CreateMenuBarLayoutItem(), 1, 1)
148 .Add(fControlLookInfoButton, 2, 1)
149 .Add(scrollBarLabel, 0, 2)
150 .Add(arrowStyleBox, 1, 2)
151 .AddGlue(0, 3)
152 .SetInsets(B_USE_WINDOW_SPACING);
153
154 // TODO : Decorator Preview Image?
155 }
156
157
~LookAndFeelSettingsView()158 LookAndFeelSettingsView::~LookAndFeelSettingsView()
159 {
160 }
161
162
163 void
AttachedToWindow()164 LookAndFeelSettingsView::AttachedToWindow()
165 {
166 AdoptParentColors();
167
168 if (Parent() == NULL)
169 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
170
171 fDecorMenu->SetTargetForItems(this);
172 fDecorInfoButton->SetTarget(this);
173 fControlLookMenu->SetTargetForItems(this);
174 fControlLookInfoButton->SetTarget(this);
175 fArrowStyleSingle->SetTarget(this);
176 fArrowStyleDouble->SetTarget(this);
177
178 if (fSavedDoubleArrowsValue)
179 fArrowStyleDouble->SetValue(B_CONTROL_ON);
180 else
181 fArrowStyleSingle->SetValue(B_CONTROL_ON);
182 }
183
184
185 void
MessageReceived(BMessage * message)186 LookAndFeelSettingsView::MessageReceived(BMessage* message)
187 {
188 switch (message->what) {
189 case kMsgSetDecor:
190 {
191 BString newDecor;
192 if (message->FindString("decor", &newDecor) == B_OK)
193 _SetDecor(newDecor);
194 break;
195 }
196
197 case kMsgDecorInfo:
198 {
199 DecorInfo* decor = fDecorUtility.FindDecorator(fCurrentDecor);
200 if (decor == NULL)
201 break;
202
203 BString authorsText(decor->Authors().String());
204 authorsText.ReplaceAll(", ", "\n\t");
205
206 BString infoText(B_TRANSLATE("%decorName\n\n"
207 "Authors:\n\t%decorAuthors\n\n"
208 "URL: %decorURL\n"
209 "License: %decorLic\n\n"
210 "%decorDesc\n"));
211
212 infoText.ReplaceFirst("%decorName", decor->Name().String());
213 infoText.ReplaceFirst("%decorAuthors", authorsText.String());
214 infoText.ReplaceFirst("%decorLic", decor->LicenseName().String());
215 infoText.ReplaceFirst("%decorURL", decor->SupportURL().String());
216 infoText.ReplaceFirst("%decorDesc",
217 decor->ShortDescription().String());
218
219 BAlert* infoAlert = new BAlert(B_TRANSLATE("About decorator"),
220 infoText.String(), B_TRANSLATE("OK"));
221 infoAlert->SetFlags(infoAlert->Flags() | B_CLOSE_ON_ESCAPE);
222 infoAlert->Go();
223
224 break;
225 }
226
227 case kMsgSetControlLook:
228 {
229 BString controlLook;
230 if (message->FindString("control_look", &controlLook) == B_OK)
231 _SetControlLook(controlLook);
232 break;
233 }
234
235 case kMsgControlLookInfo:
236 {
237 BString infoText(B_TRANSLATE("Default Haiku ControlLook"));
238 BString path;
239 if (!BPrivate::get_control_look(path))
240 break;
241
242 if (path.Length() > 0) {
243 BFile file(path.String(), B_READ_ONLY);
244 if (file.InitCheck() != B_OK)
245 break;
246
247 BAppFileInfo info(&file);
248 struct version_info version;
249 if (info.InitCheck() != B_OK
250 || info.GetVersionInfo(&version, B_APP_VERSION_KIND) != B_OK)
251 break;
252
253 infoText = version.short_info;
254 infoText << "\n" << version.long_info;
255 }
256
257 BAlert* infoAlert = new BAlert(B_TRANSLATE("About control look"),
258 infoText.String(), B_TRANSLATE("OK"));
259 infoAlert->SetFlags(infoAlert->Flags() | B_CLOSE_ON_ESCAPE);
260 infoAlert->Go();
261
262 break;
263 }
264
265 case kMsgArrowStyleSingle:
266 _SetDoubleScrollBarArrows(false);
267 break;
268
269 case kMsgArrowStyleDouble:
270 _SetDoubleScrollBarArrows(true);
271 break;
272
273 default:
274 BView::MessageReceived(message);
275 break;
276 }
277 }
278
279
280 // #pragma mark - LookAndFeelSettingsView private methods
281
282
283 void
_SetDecor(const BString & name)284 LookAndFeelSettingsView::_SetDecor(const BString& name)
285 {
286 _SetDecor(fDecorUtility.FindDecorator(name));
287 }
288
289
290 void
_SetDecor(DecorInfo * decorInfo)291 LookAndFeelSettingsView::_SetDecor(DecorInfo* decorInfo)
292 {
293 if (fDecorUtility.SetDecorator(decorInfo) == B_OK) {
294 fCurrentDecor = fDecorUtility.CurrentDecorator()->ShortcutName();
295 BString decorName = fDecorUtility.CurrentDecorator()->Name();
296 fDecorMenu->FindItem(_DecorLabel(decorName))->SetMarked(true);
297 Window()->PostMessage(kMsgUpdate);
298 }
299 }
300
301
302 void
_BuildDecorMenu()303 LookAndFeelSettingsView::_BuildDecorMenu()
304 {
305 fDecorMenu = new BPopUpMenu(B_TRANSLATE("Choose Decorator"));
306
307 // collect the current system decor settings
308 int32 count = fDecorUtility.CountDecorators();
309 for (int32 i = 0; i < count; ++i) {
310 DecorInfo* decor = fDecorUtility.DecoratorAt(i);
311 if (decor == NULL) {
312 fprintf(stderr, "Decorator : error NULL entry @ %" B_PRId32
313 " / %" B_PRId32 "\n", i, count);
314 continue;
315 }
316
317 BMessage* message = new BMessage(kMsgSetDecor);
318 message->AddString("decor", decor->ShortcutName());
319
320 BMenuItem* item = new BMenuItem(_DecorLabel(decor->Name()), message);
321 fDecorMenu->AddItem(item);
322 if (decor->ShortcutName() == fCurrentDecor)
323 item->SetMarked(true);
324 }
325 }
326
327
328 const char*
_DecorLabel(const BString & name)329 LookAndFeelSettingsView::_DecorLabel(const BString& name)
330 {
331 BString label(name);
332 return label.RemoveLast("Decorator").Trim().String();
333 }
334
335
336 void
_SetControlLook(const BString & path)337 LookAndFeelSettingsView::_SetControlLook(const BString& path)
338 {
339 fCurrentControlLook = path;
340 BPrivate::set_control_look(path);
341
342 if (path.Length() > 0) {
343 BEntry entry(path.String());
344 const char* label = _ControlLookLabel(entry.Name());
345 fControlLookMenu->FindItem(label)->SetMarked(true);
346 } else
347 fControlLookMenu->FindItem(B_TRANSLATE("Default"))->SetMarked(true);
348
349 Window()->PostMessage(kMsgUpdate);
350 }
351
352
353 void
_BuildControlLookMenu()354 LookAndFeelSettingsView::_BuildControlLookMenu()
355 {
356 BPathFinder pathFinder;
357 BStringList paths;
358 BDirectory dir;
359
360 fControlLookMenu = new BPopUpMenu(B_TRANSLATE("Choose ControlLook"));
361
362 BMessage* message = new BMessage(kMsgSetControlLook);
363 message->AddString("control_look", "");
364
365 BMenuItem* item = new BMenuItem(B_TRANSLATE("Default"), message);
366 if (fCurrentControlLook.Length() == 0)
367 item->SetMarked(true);
368 fControlLookMenu->AddItem(item);
369
370 status_t error = pathFinder.FindPaths(B_FIND_PATH_ADD_ONS_DIRECTORY,
371 "control_look", paths);
372
373 int32 count = paths.CountStrings();
374 for (int32 i = 0; i < count; ++i) {
375 if (error != B_OK || dir.SetTo(paths.StringAt(i)) != B_OK)
376 continue;
377
378 BEntry entry;
379 while (dir.GetNextEntry(&entry) == B_OK) {
380 BPath path(paths.StringAt(i), entry.Name());
381 message = new BMessage(kMsgSetControlLook);
382 message->AddString("control_look", path.Path());
383
384 item = new BMenuItem(_ControlLookLabel(entry.Name()), message);
385 fControlLookMenu->AddItem(item);
386 if (BString(path.Path()) == fCurrentControlLook)
387 item->SetMarked(true);
388 }
389 }
390 }
391
392
393 const char*
_ControlLookLabel(const char * name)394 LookAndFeelSettingsView::_ControlLookLabel(const char* name)
395 {
396 BString label(name);
397 return label.RemoveLast("ControlLook").Trim().String();
398 }
399
400
401 bool
_DoubleScrollBarArrows()402 LookAndFeelSettingsView::_DoubleScrollBarArrows()
403 {
404 scroll_bar_info info;
405 get_scroll_bar_info(&info);
406
407 return info.double_arrows;
408 }
409
410
411 void
_SetDoubleScrollBarArrows(bool doubleArrows)412 LookAndFeelSettingsView::_SetDoubleScrollBarArrows(bool doubleArrows)
413 {
414 scroll_bar_info info;
415 get_scroll_bar_info(&info);
416
417 if (info.double_arrows == doubleArrows)
418 return;
419
420 info.double_arrows = doubleArrows;
421 set_scroll_bar_info(&info);
422
423 if (doubleArrows)
424 fArrowStyleDouble->SetValue(B_CONTROL_ON);
425 else
426 fArrowStyleSingle->SetValue(B_CONTROL_ON);
427
428 Window()->PostMessage(kMsgUpdate);
429 }
430
431
432 bool
IsDefaultable()433 LookAndFeelSettingsView::IsDefaultable()
434 {
435 return fCurrentDecor != fDecorUtility.DefaultDecorator()->ShortcutName()
436 || fCurrentControlLook.Length() != 0
437 || _DoubleScrollBarArrows() != false;
438 }
439
440
441 void
SetDefaults()442 LookAndFeelSettingsView::SetDefaults()
443 {
444 _SetDecor(fDecorUtility.DefaultDecorator());
445 _SetControlLook(BString(""));
446 _SetDoubleScrollBarArrows(false);
447 }
448
449
450 bool
IsRevertable()451 LookAndFeelSettingsView::IsRevertable()
452 {
453 return fCurrentDecor != fSavedDecor
454 || fCurrentControlLook != fSavedControlLook
455 || _DoubleScrollBarArrows() != fSavedDoubleArrowsValue;
456 }
457
458
459 void
Revert()460 LookAndFeelSettingsView::Revert()
461 {
462 if (IsRevertable()) {
463 _SetDecor(fSavedDecor);
464 _SetControlLook(fSavedControlLook);
465 _SetDoubleScrollBarArrows(fSavedDoubleArrowsValue);
466 }
467 }
468