xref: /haiku/src/preferences/appearance/APRView.cpp (revision 9f3bdf3d039430b5172c424def20ce5d9f7367d4)
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 
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 
88 APRView::~APRView()
89 {
90 }
91 
92 
93 void
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
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
177 APRView::LoadSettings()
178 {
179 	get_default_colors(&fDefaultColors);
180 	get_current_colors(&fCurrentColors);
181 	fPrevColors = fCurrentColors;
182 }
183 
184 
185 void
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
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
220 APRView::IsDefaultable()
221 {
222 	return !fDefaultColors.HasSameData(fCurrentColors);
223 }
224 
225 
226 bool
227 APRView::IsRevertable()
228 {
229 	return !fPrevColors.HasSameData(fCurrentColors);
230 }
231 
232 
233 void
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 	fAttrList->Select(0);
257 }
258 
259 
260 void
261 APRView::_UpdatePreviews(const BMessage& colors)
262 {
263 	rgb_color color;
264 	for (int32 i = color_description_count() - 1; i >= 0; i--) {
265 		ColorWhichItem* item = static_cast<ColorWhichItem*>(fAttrList->ItemAt(i));
266 		if (item == NULL)
267 			continue;
268 
269 		color = colors.GetColor(ui_color_name(item->ColorWhich()),
270 			make_color(255, 0, 255));
271 
272 		item->SetColor(color);
273 		fAttrList->InvalidateItem(i);
274 	}
275 }
276 
277 
278 void
279 APRView::_SetUIColors(const BMessage& colors)
280 {
281 	set_ui_colors(&colors);
282 	fCurrentColors = colors;
283 }
284 
285 
286 void
287 APRView::_SetCurrentColor(rgb_color color)
288 {
289 	_SetColor(fWhich, color);
290 
291 	int32 currentIndex = fAttrList->CurrentSelection();
292 	ColorWhichItem* item = (ColorWhichItem*)fAttrList->ItemAt(currentIndex);
293 	if (item != NULL) {
294 		item->SetColor(color);
295 		fAttrList->InvalidateItem(currentIndex);
296 	}
297 
298 	fPicker->SetValue(color);
299 	fColorPreview->SetColor(color);
300 	fColorPreview->Invalidate();
301 }
302 
303 
304 void
305 APRView::_SetColor(color_which which, rgb_color color)
306 {
307 	_SetOneColor(which, color);
308 
309 	if (!fAutoSelectCheckBox->Value())
310 		return;
311 
312 	// Protect against accidentally overwriting colors.
313 	if (ui_color(which) == color)
314 		return;
315 
316 	if (which == B_PANEL_BACKGROUND_COLOR) {
317 		const bool isDark = color.IsDark();
318 
319 		_SetOneColor(B_MENU_BACKGROUND_COLOR, color);
320 		_SetOneColor(B_SCROLL_BAR_THUMB_COLOR, color);
321 
322 		const rgb_color menuSelectedBackground
323 			= tint_color(color, isDark ? B_LIGHTEN_2_TINT : B_DARKEN_2_TINT);
324 		_SetOneColor(B_MENU_SELECTED_BACKGROUND_COLOR, menuSelectedBackground);
325 
326 		const rgb_color controlBackground = tint_color(color, 0.25 /* lighten "> 2" */);
327 		_SetOneColor(B_CONTROL_BACKGROUND_COLOR, controlBackground);
328 
329 		const rgb_color controlBorder
330 			= tint_color(color, isDark ? 0.4875 : 1.20 /* lighten/darken "1.5" */);
331 		_SetOneColor(B_CONTROL_BORDER_COLOR, controlBorder);
332 
333 		const rgb_color windowBorder = tint_color(color, 0.75);
334 		_SetOneColor(B_WINDOW_BORDER_COLOR, windowBorder);
335 
336 		const rgb_color inactiveWindowBorder = tint_color(color, B_LIGHTEN_1_TINT);
337 		_SetOneColor(B_WINDOW_INACTIVE_TAB_COLOR, inactiveWindowBorder);
338 		_SetOneColor(B_WINDOW_INACTIVE_BORDER_COLOR, inactiveWindowBorder);
339 
340 		const rgb_color listSelectedBackground
341 			= tint_color(color, isDark ? 0.77 : 1.12 /* lighten/darken "< 1" */ );
342 		_SetOneColor(B_LIST_SELECTED_BACKGROUND_COLOR, listSelectedBackground);
343 
344 		const color_which fromDefaults[] = {
345 			B_MENU_ITEM_TEXT_COLOR,
346 			B_MENU_SELECTED_ITEM_TEXT_COLOR,
347 			B_MENU_SELECTED_BORDER_COLOR,
348 			B_PANEL_TEXT_COLOR,
349 			B_DOCUMENT_BACKGROUND_COLOR,
350 			B_DOCUMENT_TEXT_COLOR,
351 			B_CONTROL_TEXT_COLOR,
352 			B_NAVIGATION_PULSE_COLOR,
353 			B_WINDOW_INACTIVE_TEXT_COLOR,
354 			B_LIST_BACKGROUND_COLOR,
355 			B_LIST_ITEM_TEXT_COLOR,
356 			B_LIST_SELECTED_ITEM_TEXT_COLOR,
357 
358 			B_SHINE_COLOR,
359 			B_SHADOW_COLOR,
360 
361 			B_LINK_TEXT_COLOR,
362 			B_LINK_HOVER_COLOR,
363 			B_LINK_ACTIVE_COLOR,
364 			B_LINK_VISITED_COLOR,
365 		};
366 		for (size_t i = 0; i < B_COUNT_OF(fromDefaults); i++)
367 			_SetOneColor(fromDefaults[i], BPrivate::GetSystemColor(fromDefaults[i], isDark));
368 	} else if (which == B_STATUS_BAR_COLOR) {
369 		const hsl_color statusColorHSL = hsl_color::from_rgb(color);
370 
371 		hsl_color controlHighlight = statusColorHSL;
372 		controlHighlight.saturation = max_c(0.2f, controlHighlight.saturation / 2.f);
373 		_SetOneColor(B_CONTROL_HIGHLIGHT_COLOR, controlHighlight.to_rgb());
374 
375 		hsl_color controlMark = statusColorHSL;
376 		controlMark.saturation = max_c(0.2f, controlMark.saturation * 0.67f);
377 		controlMark.lightness = max_c(0.25f, controlMark.lightness * 0.55f);
378 		_SetOneColor(B_CONTROL_MARK_COLOR, controlMark.to_rgb());
379 
380 		rgb_color keyboardNav; {
381 			hsl_color keyboardNavHSL = statusColorHSL;
382 			keyboardNavHSL.lightness = max_c(0.2f, keyboardNavHSL.lightness * 0.75f);
383 			keyboardNav = keyboardNavHSL.to_rgb();
384 
385 			// Use primary color channel only.
386 			if (keyboardNav.blue >= max_c(keyboardNav.red, keyboardNav.green))
387 				keyboardNav.red = keyboardNav.green = 0;
388 			else if (keyboardNav.red >= max_c(keyboardNav.green, keyboardNav.blue))
389 				keyboardNav.green = keyboardNav.blue = 0;
390 			else
391 				keyboardNav.red = keyboardNav.blue = 0;
392 		}
393 		_SetOneColor(B_KEYBOARD_NAVIGATION_COLOR, keyboardNav);
394 	} else if (which == B_WINDOW_TAB_COLOR) {
395 		const bool isDark = color.IsDark();
396 		const hsl_color tabColorHSL = hsl_color::from_rgb(color);
397 		const float tabColorSaturation
398 			= tabColorHSL.saturation != 0 ? tabColorHSL.saturation : tabColorHSL.lightness;
399 
400 		_SetOneColor(B_WINDOW_TEXT_COLOR,
401 			BPrivate::GetSystemColor(B_WINDOW_TEXT_COLOR, isDark));
402 		_SetOneColor(B_TOOL_TIP_TEXT_COLOR,
403 			BPrivate::GetSystemColor(B_TOOL_TIP_TEXT_COLOR, isDark));
404 
405 		const rgb_color toolTipBackground = tint_color(color, isDark ? 1.7 : 0.15);
406 		_SetOneColor(B_TOOL_TIP_BACKGROUND_COLOR, toolTipBackground);
407 
408 		hsl_color success = hsl_color::from_rgb(BPrivate::GetSystemColor(B_SUCCESS_COLOR, isDark));
409 		success.saturation = max_c(0.25f, tabColorSaturation * 0.68f);
410 		_SetOneColor(B_SUCCESS_COLOR, success.to_rgb());
411 
412 		hsl_color failure = hsl_color::from_rgb(BPrivate::GetSystemColor(B_FAILURE_COLOR, isDark));
413 		failure.saturation = max_c(0.25f, tabColorSaturation);
414 		_SetOneColor(B_FAILURE_COLOR, failure.to_rgb());
415 	}
416 }
417 
418 
419 void
420 APRView::_SetOneColor(color_which which, rgb_color color)
421 {
422 	if (ui_color(which) == color)
423 		return;
424 
425 	set_ui_color(which, color);
426 	fCurrentColors.SetColor(ui_color_name(which), color);
427 }
428