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()->Name(); 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(B_TRANSLATE("No effect on running applications")); 105 106 fControlLookInfoButton = new BButton(B_TRANSLATE("About"), 107 new BMessage(kMsgControlLookInfo)); 108 109 // scroll bar arrow style 110 BBox* arrowStyleBox = new BBox("arrow style"); 111 arrowStyleBox->SetLabel(B_TRANSLATE("Arrow style")); 112 113 fArrowStyleSingle = new FakeScrollBar(true, false, 114 new BMessage(kMsgArrowStyleSingle)); 115 fArrowStyleDouble = new FakeScrollBar(true, true, 116 new BMessage(kMsgArrowStyleDouble)); 117 118 BView* arrowStyleView; 119 arrowStyleView = BLayoutBuilder::Group<>() 120 .AddGroup(B_VERTICAL, 1) 121 .Add(new BStringView("single", B_TRANSLATE("Single:"))) 122 .Add(fArrowStyleSingle) 123 .AddStrut(B_USE_DEFAULT_SPACING) 124 .Add(new BStringView("double", B_TRANSLATE("Double:"))) 125 .Add(fArrowStyleDouble) 126 .SetInsets(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, 127 B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING) 128 .End() 129 .View(); 130 arrowStyleBox->AddChild(arrowStyleView); 131 arrowStyleBox->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, 132 B_ALIGN_VERTICAL_CENTER)); 133 arrowStyleBox->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 134 135 BStringView* scrollBarLabel 136 = new BStringView("scroll bar", B_TRANSLATE("Scroll bar:")); 137 scrollBarLabel->SetExplicitAlignment( 138 BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP)); 139 140 // control layout 141 BLayoutBuilder::Grid<>(this, B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING) 142 .Add(fDecorMenuField->CreateLabelLayoutItem(), 0, 0) 143 .Add(fDecorMenuField->CreateMenuBarLayoutItem(), 1, 0) 144 .Add(fDecorInfoButton, 2, 0) 145 .Add(fControlLookMenuField->CreateLabelLayoutItem(), 0, 1) 146 .Add(fControlLookMenuField->CreateMenuBarLayoutItem(), 1, 1) 147 .Add(fControlLookInfoButton, 2, 1) 148 .Add(scrollBarLabel, 0, 2) 149 .Add(arrowStyleBox, 1, 2) 150 .AddGlue(0, 3) 151 .SetInsets(B_USE_WINDOW_SPACING); 152 153 // TODO : Decorator Preview Image? 154 } 155 156 157 LookAndFeelSettingsView::~LookAndFeelSettingsView() 158 { 159 } 160 161 162 void 163 LookAndFeelSettingsView::AttachedToWindow() 164 { 165 AdoptParentColors(); 166 167 if (Parent() == NULL) 168 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 169 170 fDecorMenu->SetTargetForItems(this); 171 fDecorInfoButton->SetTarget(this); 172 fControlLookMenu->SetTargetForItems(this); 173 fControlLookInfoButton->SetTarget(this); 174 fArrowStyleSingle->SetTarget(this); 175 fArrowStyleDouble->SetTarget(this); 176 177 if (fSavedDoubleArrowsValue) 178 fArrowStyleDouble->SetValue(B_CONTROL_ON); 179 else 180 fArrowStyleSingle->SetValue(B_CONTROL_ON); 181 } 182 183 184 void 185 LookAndFeelSettingsView::MessageReceived(BMessage* message) 186 { 187 switch (message->what) { 188 case kMsgSetDecor: 189 { 190 BString newDecor; 191 if (message->FindString("decor", &newDecor) == B_OK) 192 _SetDecor(newDecor); 193 break; 194 } 195 196 case kMsgDecorInfo: 197 { 198 DecorInfo* decor = fDecorUtility.FindDecorator(fCurrentDecor); 199 if (decor == NULL) 200 break; 201 202 BString authorsText(decor->Authors().String()); 203 authorsText.ReplaceAll(", ", "\n\t"); 204 205 BString infoText(B_TRANSLATE("%decorName\n\n" 206 "Authors:\n\t%decorAuthors\n\n" 207 "URL: %decorURL\n" 208 "License: %decorLic\n\n" 209 "%decorDesc\n")); 210 211 infoText.ReplaceFirst("%decorName", decor->Name().String()); 212 infoText.ReplaceFirst("%decorAuthors", authorsText.String()); 213 infoText.ReplaceFirst("%decorLic", decor->LicenseName().String()); 214 infoText.ReplaceFirst("%decorURL", decor->SupportURL().String()); 215 infoText.ReplaceFirst("%decorDesc", 216 decor->ShortDescription().String()); 217 218 BAlert* infoAlert = new BAlert(B_TRANSLATE("About decorator"), 219 infoText.String(), B_TRANSLATE("OK")); 220 infoAlert->SetFlags(infoAlert->Flags() | B_CLOSE_ON_ESCAPE); 221 infoAlert->Go(); 222 223 break; 224 } 225 226 case kMsgSetControlLook: 227 { 228 BString controlLook; 229 if (message->FindString("control_look", &controlLook) == B_OK) 230 _SetControlLook(controlLook); 231 break; 232 } 233 234 case kMsgControlLookInfo: 235 { 236 BString infoText(B_TRANSLATE("Default Haiku ControlLook")); 237 BString path; 238 if (!BPrivate::get_control_look(path)) 239 break; 240 241 if (path.Length() > 0) { 242 BFile file(path.String(), B_READ_ONLY); 243 if (file.InitCheck() != B_OK) 244 break; 245 246 BAppFileInfo info(&file); 247 struct version_info version; 248 if (info.InitCheck() != B_OK 249 || info.GetVersionInfo(&version, B_APP_VERSION_KIND) != B_OK) 250 break; 251 252 infoText = version.short_info; 253 infoText << "\n" << version.long_info; 254 } 255 256 BAlert* infoAlert = new BAlert(B_TRANSLATE("About control look"), 257 infoText.String(), B_TRANSLATE("OK")); 258 infoAlert->SetFlags(infoAlert->Flags() | B_CLOSE_ON_ESCAPE); 259 infoAlert->Go(); 260 261 break; 262 } 263 264 case kMsgArrowStyleSingle: 265 _SetDoubleScrollBarArrows(false); 266 break; 267 268 case kMsgArrowStyleDouble: 269 _SetDoubleScrollBarArrows(true); 270 break; 271 272 default: 273 BView::MessageReceived(message); 274 break; 275 } 276 } 277 278 279 // #pragma mark - LookAndFeelSettingsView private methods 280 281 282 void 283 LookAndFeelSettingsView::_SetDecor(const BString& name) 284 { 285 _SetDecor(fDecorUtility.FindDecorator(name)); 286 } 287 288 289 void 290 LookAndFeelSettingsView::_SetDecor(DecorInfo* decorInfo) 291 { 292 if (fDecorUtility.SetDecorator(decorInfo) == B_OK) { 293 fCurrentDecor = fDecorUtility.CurrentDecorator()->Name(); 294 fDecorMenu->FindItem(_DecorLabel(fCurrentDecor))->SetMarked(true); 295 Window()->PostMessage(kMsgUpdate); 296 } 297 } 298 299 300 void 301 LookAndFeelSettingsView::_BuildDecorMenu() 302 { 303 fDecorMenu = new BPopUpMenu(B_TRANSLATE("Choose Decorator")); 304 305 // collect the current system decor settings 306 int32 count = fDecorUtility.CountDecorators(); 307 for (int32 i = 0; i < count; ++i) { 308 DecorInfo* decorator = fDecorUtility.DecoratorAt(i); 309 if (decorator == NULL) { 310 fprintf(stderr, "Decorator : error NULL entry @ %" B_PRId32 311 " / %" B_PRId32 "\n", i, count); 312 continue; 313 } 314 315 BString decorName = decorator->Name(); 316 BMessage* message = new BMessage(kMsgSetDecor); 317 message->AddString("decor", decorName); 318 319 BMenuItem* item = new BMenuItem(_DecorLabel(decorName), message); 320 fDecorMenu->AddItem(item); 321 if (decorName == fCurrentDecor) 322 item->SetMarked(true); 323 } 324 } 325 326 327 const char* 328 LookAndFeelSettingsView::_DecorLabel(const BString& name) 329 { 330 BString label(name); 331 return label.RemoveLast("Decorator").Trim().String(); 332 } 333 334 335 void 336 LookAndFeelSettingsView::_SetControlLook(const BString& path) 337 { 338 fCurrentControlLook = path; 339 BPrivate::set_control_look(path); 340 341 if (path.Length() > 0) { 342 BEntry entry(path.String()); 343 const char* label = _ControlLookLabel(entry.Name()); 344 fControlLookMenu->FindItem(label)->SetMarked(true); 345 } else 346 fControlLookMenu->FindItem(B_TRANSLATE("Default"))->SetMarked(true); 347 348 Window()->PostMessage(kMsgUpdate); 349 } 350 351 352 void 353 LookAndFeelSettingsView::_BuildControlLookMenu() 354 { 355 BPathFinder pathFinder; 356 BStringList paths; 357 BDirectory dir; 358 359 fControlLookMenu = new BPopUpMenu(B_TRANSLATE("Choose ControlLook")); 360 361 BMessage* message = new BMessage(kMsgSetControlLook); 362 message->AddString("control_look", ""); 363 364 BMenuItem* item = new BMenuItem(B_TRANSLATE("Default"), message); 365 if (fCurrentControlLook.Length() == 0) 366 item->SetMarked(true); 367 fControlLookMenu->AddItem(item); 368 369 status_t error = pathFinder.FindPaths(B_FIND_PATH_ADD_ONS_DIRECTORY, 370 "control_look", paths); 371 372 int32 count = paths.CountStrings(); 373 for (int32 i = 0; i < count; ++i) { 374 if (error != B_OK || dir.SetTo(paths.StringAt(i)) != B_OK) 375 continue; 376 377 BEntry entry; 378 while (dir.GetNextEntry(&entry) == B_OK) { 379 BPath path(paths.StringAt(i), entry.Name()); 380 message = new BMessage(kMsgSetControlLook); 381 message->AddString("control_look", path.Path()); 382 383 item = new BMenuItem(_ControlLookLabel(entry.Name()), message); 384 fControlLookMenu->AddItem(item); 385 if (BString(path.Path()) == fCurrentControlLook) 386 item->SetMarked(true); 387 } 388 } 389 } 390 391 392 const char* 393 LookAndFeelSettingsView::_ControlLookLabel(const char* name) 394 { 395 BString label(name); 396 return label.RemoveLast("ControlLook").Trim().String(); 397 } 398 399 400 bool 401 LookAndFeelSettingsView::_DoubleScrollBarArrows() 402 { 403 scroll_bar_info info; 404 get_scroll_bar_info(&info); 405 406 return info.double_arrows; 407 } 408 409 410 void 411 LookAndFeelSettingsView::_SetDoubleScrollBarArrows(bool doubleArrows) 412 { 413 scroll_bar_info info; 414 get_scroll_bar_info(&info); 415 416 if (info.double_arrows == doubleArrows) 417 return; 418 419 info.double_arrows = doubleArrows; 420 set_scroll_bar_info(&info); 421 422 if (doubleArrows) 423 fArrowStyleDouble->SetValue(B_CONTROL_ON); 424 else 425 fArrowStyleSingle->SetValue(B_CONTROL_ON); 426 427 Window()->PostMessage(kMsgUpdate); 428 } 429 430 431 bool 432 LookAndFeelSettingsView::IsDefaultable() 433 { 434 return fCurrentDecor != fDecorUtility.DefaultDecorator()->Name() 435 || fCurrentControlLook.Length() != 0 436 || _DoubleScrollBarArrows() != false; 437 } 438 439 440 void 441 LookAndFeelSettingsView::SetDefaults() 442 { 443 _SetDecor(fDecorUtility.DefaultDecorator()); 444 _SetControlLook(BString("")); 445 _SetDoubleScrollBarArrows(false); 446 } 447 448 449 bool 450 LookAndFeelSettingsView::IsRevertable() 451 { 452 return fCurrentDecor != fSavedDecor 453 || fCurrentControlLook != fSavedControlLook 454 || _DoubleScrollBarArrows() != fSavedDoubleArrowsValue; 455 } 456 457 458 void 459 LookAndFeelSettingsView::Revert() 460 { 461 if (IsRevertable()) { 462 _SetDecor(fSavedDecor); 463 _SetControlLook(fSavedControlLook); 464 _SetDoubleScrollBarArrows(fSavedDoubleArrowsValue); 465 } 466 } 467