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