1 /*
2 * Copyright 2002-2015 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * DarkWyrm, darkwyrm@earthlink.net
7 * Rene Gollent, rene@gollent.com
8 * John Scipione, jscipione@gmail.com
9 * Joseph Groover <looncraz@looncraz.net>
10 */
11
12
13 #include "APRView.h"
14
15 #include <stdio.h>
16
17 #include <Alert.h>
18 #include <Catalog.h>
19 #include <DefaultColors.h>
20 #include <Directory.h>
21 #include <Entry.h>
22 #include <File.h>
23 #include <HSL.h>
24 #include <LayoutBuilder.h>
25 #include <Locale.h>
26 #include <Messenger.h>
27 #include <Path.h>
28 #include <SpaceLayoutItem.h>
29
30 #include "APRWindow.h"
31 #include "defs.h"
32 #include "ColorPreview.h"
33 #include "Colors.h"
34 #include "ColorWhichListView.h"
35 #include "ColorWhichItem.h"
36
37
38 #undef B_TRANSLATION_CONTEXT
39 #define B_TRANSLATION_CONTEXT "Colors tab"
40
41 #define COLOR_DROPPED 'cldp'
42 #define AUTO_ADJUST_CHANGED 'madj'
43
44
APRView(const char * name)45 APRView::APRView(const char* name)
46 :
47 BView(name, B_WILL_DRAW)
48 {
49 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
50
51 LoadSettings();
52
53 fAutoSelectCheckBox = new BCheckBox(B_TRANSLATE("Automatically pick secondary colors"),
54 new BMessage(AUTO_ADJUST_CHANGED));
55 fAutoSelectCheckBox->SetValue(true);
56
57 // Set up list of color attributes
58 fAttrList = new ColorWhichListView("AttributeList");
59
60 fScrollView = new BScrollView("ScrollView", fAttrList, 0, false, true);
61 fScrollView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
62
63 _CreateItems();
64
65 fColorPreview = new ColorPreview(new BMessage(COLOR_DROPPED), 0);
66 fColorPreview->SetExplicitAlignment(BAlignment(B_ALIGN_HORIZONTAL_CENTER,
67 B_ALIGN_VERTICAL_CENTER));
68
69 fPicker = new BColorControl(B_ORIGIN, B_CELLS_32x8, 8.0,
70 "picker", new BMessage(UPDATE_COLOR));
71
72 BLayoutBuilder::Group<>(this, B_VERTICAL)
73 .Add(fAutoSelectCheckBox)
74 .Add(fScrollView, 10.0)
75 .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
76 .Add(fColorPreview)
77 .AddGlue()
78 .Add(fPicker)
79 .End()
80 .SetInsets(B_USE_WINDOW_SPACING);
81
82 fColorPreview->Parent()->SetExplicitMaxSize(
83 BSize(B_SIZE_UNSET, fPicker->Bounds().Height()));
84 fAttrList->SetSelectionMessage(new BMessage(ATTRIBUTE_CHOSEN));
85 }
86
87
~APRView()88 APRView::~APRView()
89 {
90 }
91
92
93 void
AttachedToWindow()94 APRView::AttachedToWindow()
95 {
96 fAutoSelectCheckBox->SetTarget(this);
97 fPicker->SetTarget(this);
98 fAttrList->SetTarget(this);
99 fColorPreview->SetTarget(this);
100
101 fAttrList->Select(0);
102 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
103 }
104
105
106 void
MessageReceived(BMessage * msg)107 APRView::MessageReceived(BMessage *msg)
108 {
109 switch (msg->what) {
110 case SET_COLOR:
111 {
112 rgb_color* color;
113 ssize_t size;
114 color_which which;
115
116 if (msg->FindData(kRGBColor, B_RGB_COLOR_TYPE,
117 (const void**)&color, &size) == B_OK
118 && msg->FindUInt32(kWhich, (uint32*)&which) == B_OK) {
119 _SetColor(which, *color);
120 Window()->PostMessage(kMsgUpdate);
121 }
122 break;
123 }
124
125 case SET_CURRENT_COLOR:
126 {
127 rgb_color* color;
128 ssize_t size;
129
130 if (msg->FindData(kRGBColor, B_RGB_COLOR_TYPE,
131 (const void**)&color, &size) == B_OK) {
132 _SetCurrentColor(*color);
133 Window()->PostMessage(kMsgUpdate);
134 }
135 break;
136 }
137
138 case UPDATE_COLOR:
139 {
140 // Received from the color fPicker when its color changes
141 rgb_color color = fPicker->ValueAsColor();
142 _SetCurrentColor(color);
143
144 Window()->PostMessage(kMsgUpdate);
145 break;
146 }
147
148 case ATTRIBUTE_CHOSEN:
149 {
150 // Received when the user chooses a GUI fAttribute from the list
151
152 ColorWhichItem* item = (ColorWhichItem*)
153 fAttrList->ItemAt(fAttrList->CurrentSelection());
154 if (item == NULL)
155 break;
156
157 fWhich = item->ColorWhich();
158 rgb_color color = ui_color(fWhich);
159 _SetCurrentColor(color);
160 break;
161 }
162
163 case AUTO_ADJUST_CHANGED:
164 {
165 _CreateItems();
166 break;
167 }
168
169 default:
170 BView::MessageReceived(msg);
171 break;
172 }
173 }
174
175
176 void
LoadSettings()177 APRView::LoadSettings()
178 {
179 get_default_colors(&fDefaultColors);
180 get_current_colors(&fCurrentColors);
181 fPrevColors = fCurrentColors;
182 }
183
184
185 void
SetDefaults()186 APRView::SetDefaults()
187 {
188 _SetUIColors(fDefaultColors);
189 _UpdatePreviews(fDefaultColors);
190
191 // Use a default color that stands out to show errors clearly
192 rgb_color color = fDefaultColors.GetColor(ui_color_name(fWhich),
193 make_color(255, 0, 255));
194
195 fPicker->SetValue(color);
196 fColorPreview->SetColor(color);
197 fColorPreview->Invalidate();
198
199 Window()->PostMessage(kMsgUpdate);
200 }
201
202
203 void
Revert()204 APRView::Revert()
205 {
206 _SetUIColors(fPrevColors);
207 _UpdatePreviews(fPrevColors);
208
209 rgb_color color = fPrevColors.GetColor(ui_color_name(fWhich),
210 make_color(255, 0, 255));
211 fPicker->SetValue(color);
212 fColorPreview->SetColor(color);
213 fColorPreview->Invalidate();
214
215 Window()->PostMessage(kMsgUpdate);
216 }
217
218
219 bool
IsDefaultable()220 APRView::IsDefaultable()
221 {
222 return !fDefaultColors.HasSameData(fCurrentColors);
223 }
224
225
226 bool
IsRevertable()227 APRView::IsRevertable()
228 {
229 return !fPrevColors.HasSameData(fCurrentColors);
230 }
231
232
233 void
_CreateItems()234 APRView::_CreateItems()
235 {
236 while (fAttrList->CountItems() > 0)
237 delete fAttrList->RemoveItem((int32)0);
238
239 const bool autoSelect = fAutoSelectCheckBox->Value();
240 const int32 count = color_description_count();
241 for (int32 i = 0; i < count; i++) {
242 const ColorDescription& description = *get_color_description(i);
243 const color_which which = description.which;
244 if (autoSelect) {
245 if (which != B_PANEL_BACKGROUND_COLOR
246 && which != B_STATUS_BAR_COLOR
247 && which != B_WINDOW_TAB_COLOR) {
248 continue;
249 }
250 }
251
252 const char* text = B_TRANSLATE_NOCOLLECT(description.text);
253 fAttrList->AddItem(new ColorWhichItem(text, which, ui_color(which)));
254 }
255
256 if (Window() != NULL)
257 fAttrList->Select(0);
258 }
259
260
261 void
_UpdatePreviews(const BMessage & colors)262 APRView::_UpdatePreviews(const BMessage& colors)
263 {
264 rgb_color color;
265 for (int32 i = color_description_count() - 1; i >= 0; i--) {
266 ColorWhichItem* item = static_cast<ColorWhichItem*>(fAttrList->ItemAt(i));
267 if (item == NULL)
268 continue;
269
270 color = colors.GetColor(ui_color_name(item->ColorWhich()),
271 make_color(255, 0, 255));
272
273 item->SetColor(color);
274 fAttrList->InvalidateItem(i);
275 }
276 }
277
278
279 void
_SetUIColors(const BMessage & colors)280 APRView::_SetUIColors(const BMessage& colors)
281 {
282 set_ui_colors(&colors);
283 fCurrentColors = colors;
284 }
285
286
287 void
_SetCurrentColor(rgb_color color)288 APRView::_SetCurrentColor(rgb_color color)
289 {
290 _SetColor(fWhich, color);
291
292 int32 currentIndex = fAttrList->CurrentSelection();
293 ColorWhichItem* item = (ColorWhichItem*)fAttrList->ItemAt(currentIndex);
294 if (item != NULL) {
295 item->SetColor(color);
296 fAttrList->InvalidateItem(currentIndex);
297 }
298
299 fPicker->SetValue(color);
300 fColorPreview->SetColor(color);
301 fColorPreview->Invalidate();
302 }
303
304
305 void
_SetColor(color_which which,rgb_color color)306 APRView::_SetColor(color_which which, rgb_color color)
307 {
308 _SetOneColor(which, color);
309
310 if (!fAutoSelectCheckBox->Value())
311 return;
312
313 // Protect against accidentally overwriting colors.
314 if (ui_color(which) == color)
315 return;
316
317 if (which == B_PANEL_BACKGROUND_COLOR) {
318 const bool isDark = color.IsDark();
319
320 _SetOneColor(B_MENU_BACKGROUND_COLOR, color);
321 _SetOneColor(B_SCROLL_BAR_THUMB_COLOR, color);
322
323 const rgb_color menuSelectedBackground
324 = tint_color(color, isDark ? 0.8 /* lighten "< 1" */ : B_DARKEN_2_TINT);
325 _SetOneColor(B_MENU_SELECTED_BACKGROUND_COLOR, menuSelectedBackground);
326
327 const rgb_color controlBackground = tint_color(color, isDark
328 ? 0.8 /* lighten "< 1" */ : 0.25 /* lighten "> 2" */);
329 _SetOneColor(B_CONTROL_BACKGROUND_COLOR, controlBackground);
330
331 const rgb_color controlBorder
332 = tint_color(color, isDark ? 0.4875 : 1.20 /* lighten/darken "1.5" */);
333 _SetOneColor(B_CONTROL_BORDER_COLOR, controlBorder);
334
335 const rgb_color windowBorder = tint_color(color, 0.75);
336 _SetOneColor(B_WINDOW_BORDER_COLOR, windowBorder);
337
338 const rgb_color inactiveWindowBorder = tint_color(color, B_LIGHTEN_1_TINT);
339 _SetOneColor(B_WINDOW_INACTIVE_TAB_COLOR, inactiveWindowBorder);
340 _SetOneColor(B_WINDOW_INACTIVE_BORDER_COLOR, inactiveWindowBorder);
341
342 const rgb_color listSelectedBackground
343 = tint_color(color, isDark ? 0.77 : 1.12 /* lighten/darken "< 1" */ );
344 _SetOneColor(B_LIST_SELECTED_BACKGROUND_COLOR, listSelectedBackground);
345
346 const color_which fromDefaults[] = {
347 B_MENU_ITEM_TEXT_COLOR,
348 B_MENU_SELECTED_ITEM_TEXT_COLOR,
349 B_MENU_SELECTED_BORDER_COLOR,
350 B_PANEL_TEXT_COLOR,
351 B_DOCUMENT_BACKGROUND_COLOR,
352 B_DOCUMENT_TEXT_COLOR,
353 B_CONTROL_TEXT_COLOR,
354 B_NAVIGATION_PULSE_COLOR,
355 B_WINDOW_INACTIVE_TEXT_COLOR,
356 B_LIST_BACKGROUND_COLOR,
357 B_LIST_ITEM_TEXT_COLOR,
358 B_LIST_SELECTED_ITEM_TEXT_COLOR,
359
360 B_SHINE_COLOR,
361 B_SHADOW_COLOR,
362
363 B_LINK_TEXT_COLOR,
364 B_LINK_HOVER_COLOR,
365 B_LINK_ACTIVE_COLOR,
366 B_LINK_VISITED_COLOR,
367 };
368 for (size_t i = 0; i < B_COUNT_OF(fromDefaults); i++)
369 _SetOneColor(fromDefaults[i], BPrivate::GetSystemColor(fromDefaults[i], isDark));
370 } else if (which == B_STATUS_BAR_COLOR) {
371 const hsl_color statusColorHSL = hsl_color::from_rgb(color);
372
373 hsl_color controlHighlight = statusColorHSL;
374 controlHighlight.saturation = max_c(0.2f, controlHighlight.saturation / 2.f);
375 _SetOneColor(B_CONTROL_HIGHLIGHT_COLOR, controlHighlight.to_rgb());
376
377 hsl_color controlMark = statusColorHSL;
378 controlMark.saturation = max_c(0.2f, controlMark.saturation * 0.67f);
379 controlMark.lightness = max_c(0.25f, controlMark.lightness * 0.55f);
380 _SetOneColor(B_CONTROL_MARK_COLOR, controlMark.to_rgb());
381
382 rgb_color keyboardNav; {
383 hsl_color keyboardNavHSL = statusColorHSL;
384 keyboardNavHSL.lightness = max_c(0.2f, keyboardNavHSL.lightness * 0.75f);
385 keyboardNav = keyboardNavHSL.to_rgb();
386
387 // Use primary color channel only.
388 if (keyboardNav.blue >= max_c(keyboardNav.red, keyboardNav.green))
389 keyboardNav.red = keyboardNav.green = 0;
390 else if (keyboardNav.red >= max_c(keyboardNav.green, keyboardNav.blue))
391 keyboardNav.green = keyboardNav.blue = 0;
392 else
393 keyboardNav.red = keyboardNav.blue = 0;
394 }
395 _SetOneColor(B_KEYBOARD_NAVIGATION_COLOR, keyboardNav);
396 } else if (which == B_WINDOW_TAB_COLOR) {
397 const bool isDark = color.IsDark();
398 const hsl_color tabColorHSL = hsl_color::from_rgb(color);
399 const float tabColorSaturation
400 = tabColorHSL.saturation != 0 ? tabColorHSL.saturation : tabColorHSL.lightness;
401
402 _SetOneColor(B_WINDOW_TEXT_COLOR,
403 BPrivate::GetSystemColor(B_WINDOW_TEXT_COLOR, isDark));
404 _SetOneColor(B_TOOL_TIP_TEXT_COLOR,
405 BPrivate::GetSystemColor(B_TOOL_TIP_TEXT_COLOR, isDark));
406
407 const rgb_color toolTipBackground = tint_color(color, isDark ? 1.7 : 0.15);
408 _SetOneColor(B_TOOL_TIP_BACKGROUND_COLOR, toolTipBackground);
409
410 hsl_color success = hsl_color::from_rgb(BPrivate::GetSystemColor(B_SUCCESS_COLOR, isDark));
411 success.saturation = max_c(0.25f, tabColorSaturation * 0.68f);
412 _SetOneColor(B_SUCCESS_COLOR, success.to_rgb());
413
414 hsl_color failure = hsl_color::from_rgb(BPrivate::GetSystemColor(B_FAILURE_COLOR, isDark));
415 failure.saturation = max_c(0.25f, tabColorSaturation);
416 _SetOneColor(B_FAILURE_COLOR, failure.to_rgb());
417 }
418 }
419
420
421 void
_SetOneColor(color_which which,rgb_color color)422 APRView::_SetOneColor(color_which which, rgb_color color)
423 {
424 if (ui_color(which) == color)
425 return;
426
427 set_ui_color(which, color);
428 fCurrentColors.SetColor(ui_color_name(which), color);
429 }
430