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 if (Window() != NULL) 257 fAttrList->Select(0); 258 } 259 260 261 void 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 280 APRView::_SetUIColors(const BMessage& colors) 281 { 282 set_ui_colors(&colors); 283 fCurrentColors = colors; 284 } 285 286 287 void 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 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 ? B_LIGHTEN_2_TINT : B_DARKEN_2_TINT); 325 _SetOneColor(B_MENU_SELECTED_BACKGROUND_COLOR, menuSelectedBackground); 326 327 const rgb_color controlBackground = tint_color(color, 0.25 /* lighten "> 2" */); 328 _SetOneColor(B_CONTROL_BACKGROUND_COLOR, controlBackground); 329 330 const rgb_color controlBorder 331 = tint_color(color, isDark ? 0.4875 : 1.20 /* lighten/darken "1.5" */); 332 _SetOneColor(B_CONTROL_BORDER_COLOR, controlBorder); 333 334 const rgb_color windowBorder = tint_color(color, 0.75); 335 _SetOneColor(B_WINDOW_BORDER_COLOR, windowBorder); 336 337 const rgb_color inactiveWindowBorder = tint_color(color, B_LIGHTEN_1_TINT); 338 _SetOneColor(B_WINDOW_INACTIVE_TAB_COLOR, inactiveWindowBorder); 339 _SetOneColor(B_WINDOW_INACTIVE_BORDER_COLOR, inactiveWindowBorder); 340 341 const rgb_color listSelectedBackground 342 = tint_color(color, isDark ? 0.77 : 1.12 /* lighten/darken "< 1" */ ); 343 _SetOneColor(B_LIST_SELECTED_BACKGROUND_COLOR, listSelectedBackground); 344 345 const color_which fromDefaults[] = { 346 B_MENU_ITEM_TEXT_COLOR, 347 B_MENU_SELECTED_ITEM_TEXT_COLOR, 348 B_MENU_SELECTED_BORDER_COLOR, 349 B_PANEL_TEXT_COLOR, 350 B_DOCUMENT_BACKGROUND_COLOR, 351 B_DOCUMENT_TEXT_COLOR, 352 B_CONTROL_TEXT_COLOR, 353 B_NAVIGATION_PULSE_COLOR, 354 B_WINDOW_INACTIVE_TEXT_COLOR, 355 B_LIST_BACKGROUND_COLOR, 356 B_LIST_ITEM_TEXT_COLOR, 357 B_LIST_SELECTED_ITEM_TEXT_COLOR, 358 359 B_SHINE_COLOR, 360 B_SHADOW_COLOR, 361 362 B_LINK_TEXT_COLOR, 363 B_LINK_HOVER_COLOR, 364 B_LINK_ACTIVE_COLOR, 365 B_LINK_VISITED_COLOR, 366 }; 367 for (size_t i = 0; i < B_COUNT_OF(fromDefaults); i++) 368 _SetOneColor(fromDefaults[i], BPrivate::GetSystemColor(fromDefaults[i], isDark)); 369 } else if (which == B_STATUS_BAR_COLOR) { 370 const hsl_color statusColorHSL = hsl_color::from_rgb(color); 371 372 hsl_color controlHighlight = statusColorHSL; 373 controlHighlight.saturation = max_c(0.2f, controlHighlight.saturation / 2.f); 374 _SetOneColor(B_CONTROL_HIGHLIGHT_COLOR, controlHighlight.to_rgb()); 375 376 hsl_color controlMark = statusColorHSL; 377 controlMark.saturation = max_c(0.2f, controlMark.saturation * 0.67f); 378 controlMark.lightness = max_c(0.25f, controlMark.lightness * 0.55f); 379 _SetOneColor(B_CONTROL_MARK_COLOR, controlMark.to_rgb()); 380 381 rgb_color keyboardNav; { 382 hsl_color keyboardNavHSL = statusColorHSL; 383 keyboardNavHSL.lightness = max_c(0.2f, keyboardNavHSL.lightness * 0.75f); 384 keyboardNav = keyboardNavHSL.to_rgb(); 385 386 // Use primary color channel only. 387 if (keyboardNav.blue >= max_c(keyboardNav.red, keyboardNav.green)) 388 keyboardNav.red = keyboardNav.green = 0; 389 else if (keyboardNav.red >= max_c(keyboardNav.green, keyboardNav.blue)) 390 keyboardNav.green = keyboardNav.blue = 0; 391 else 392 keyboardNav.red = keyboardNav.blue = 0; 393 } 394 _SetOneColor(B_KEYBOARD_NAVIGATION_COLOR, keyboardNav); 395 } else if (which == B_WINDOW_TAB_COLOR) { 396 const bool isDark = color.IsDark(); 397 const hsl_color tabColorHSL = hsl_color::from_rgb(color); 398 const float tabColorSaturation 399 = tabColorHSL.saturation != 0 ? tabColorHSL.saturation : tabColorHSL.lightness; 400 401 _SetOneColor(B_WINDOW_TEXT_COLOR, 402 BPrivate::GetSystemColor(B_WINDOW_TEXT_COLOR, isDark)); 403 _SetOneColor(B_TOOL_TIP_TEXT_COLOR, 404 BPrivate::GetSystemColor(B_TOOL_TIP_TEXT_COLOR, isDark)); 405 406 const rgb_color toolTipBackground = tint_color(color, isDark ? 1.7 : 0.15); 407 _SetOneColor(B_TOOL_TIP_BACKGROUND_COLOR, toolTipBackground); 408 409 hsl_color success = hsl_color::from_rgb(BPrivate::GetSystemColor(B_SUCCESS_COLOR, isDark)); 410 success.saturation = max_c(0.25f, tabColorSaturation * 0.68f); 411 _SetOneColor(B_SUCCESS_COLOR, success.to_rgb()); 412 413 hsl_color failure = hsl_color::from_rgb(BPrivate::GetSystemColor(B_FAILURE_COLOR, isDark)); 414 failure.saturation = max_c(0.25f, tabColorSaturation); 415 _SetOneColor(B_FAILURE_COLOR, failure.to_rgb()); 416 } 417 } 418 419 420 void 421 APRView::_SetOneColor(color_which which, rgb_color color) 422 { 423 if (ui_color(which) == color) 424 return; 425 426 set_ui_color(which, color); 427 fCurrentColors.SetColor(ui_color_name(which), color); 428 } 429