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 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 158 LookAndFeelSettingsView::~LookAndFeelSettingsView() 159 { 160 } 161 162 163 void 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 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 284 LookAndFeelSettingsView::_SetDecor(const BString& name) 285 { 286 _SetDecor(fDecorUtility.FindDecorator(name)); 287 } 288 289 290 void 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 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* 329 LookAndFeelSettingsView::_DecorLabel(const BString& name) 330 { 331 BString label(name); 332 return label.RemoveLast("Decorator").Trim().String(); 333 } 334 335 336 void 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 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* 394 LookAndFeelSettingsView::_ControlLookLabel(const char* name) 395 { 396 BString label(name); 397 return label.RemoveLast("ControlLook").Trim().String(); 398 } 399 400 401 bool 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 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 433 LookAndFeelSettingsView::IsDefaultable() 434 { 435 return fCurrentDecor != fDecorUtility.DefaultDecorator()->ShortcutName() 436 || fCurrentControlLook.Length() != 0 437 || _DoubleScrollBarArrows() != false; 438 } 439 440 441 void 442 LookAndFeelSettingsView::SetDefaults() 443 { 444 _SetDecor(fDecorUtility.DefaultDecorator()); 445 _SetControlLook(BString("")); 446 _SetDoubleScrollBarArrows(false); 447 } 448 449 450 bool 451 LookAndFeelSettingsView::IsRevertable() 452 { 453 return fCurrentDecor != fSavedDecor 454 || fCurrentControlLook != fSavedControlLook 455 || _DoubleScrollBarArrows() != fSavedDoubleArrowsValue; 456 } 457 458 459 void 460 LookAndFeelSettingsView::Revert() 461 { 462 if (IsRevertable()) { 463 _SetDecor(fSavedDecor); 464 _SetControlLook(fSavedControlLook); 465 _SetDoubleScrollBarArrows(fSavedDoubleArrowsValue); 466 } 467 } 468