1 /* 2 * Copyright 2001-2011, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Mark Hogben 7 * DarkWyrm <bpmagic@columbus.rr.com> 8 * Axel Dörfler, axeld@pinc-software.de 9 * Philippe Saint-Pierre, stpere@gmail.com 10 * Stephan Aßmus <superstippi@gmx.de> 11 */ 12 13 14 #include "FontSelectionView.h" 15 16 #include <Box.h> 17 #include <Catalog.h> 18 #include <Locale.h> 19 #include <MenuField.h> 20 #include <MenuItem.h> 21 #include <PopUpMenu.h> 22 #include <String.h> 23 #include <StringView.h> 24 #include <LayoutItem.h> 25 #include <GroupLayoutBuilder.h> 26 27 #include <stdio.h> 28 29 30 #undef B_TRANSLATION_CONTEXT 31 #define B_TRANSLATION_CONTEXT "Font Selection view" 32 33 34 #define INSTANT_UPDATE 35 // if defined, the system font will be updated immediately, and not 36 // only on exit 37 38 static const float kMinSize = 8.0; 39 static const float kMaxSize = 24.0; 40 41 42 // private font API 43 extern void _set_system_font_(const char *which, font_family family, 44 font_style style, float size); 45 extern status_t _get_system_default_font_(const char* which, 46 font_family family, font_style style, float* _size); 47 48 49 #ifdef B_BEOS_VERSION_DANO 50 // this call only exists under R5 51 void 52 _set_system_font_(const char *which, font_family family, 53 font_style style, float size) 54 { 55 puts("you don't have _set_system_font_()"); 56 } 57 #endif 58 59 #if !defined(HAIKU_TARGET_PLATFORM_HAIKU) && !defined(HAIKU_TARGET_PLATFORM_LIBBE_TEST) 60 // this call only exists under Haiku (and the test environment) 61 status_t 62 _get_system_default_font_(const char* which, font_family family, 63 font_style style, float* _size) 64 { 65 puts("you don't have _get_system_default_font_()"); 66 return B_ERROR; 67 } 68 #endif 69 70 71 // #pragma mark - 72 73 74 FontSelectionView::FontSelectionView(const char* name, 75 const char* label, const BFont* currentFont) 76 : 77 BView(name, B_WILL_DRAW), 78 fMessageTarget(this) 79 { 80 if (currentFont == NULL) { 81 if (!strcmp(Name(), "plain")) 82 fCurrentFont = *be_plain_font; 83 else if (!strcmp(Name(), "bold")) 84 fCurrentFont = *be_bold_font; 85 else if (!strcmp(Name(), "fixed")) 86 fCurrentFont = *be_fixed_font; 87 else if (!strcmp(Name(), "menu")) { 88 menu_info info; 89 get_menu_info(&info); 90 91 fCurrentFont.SetFamilyAndStyle(info.f_family, info.f_style); 92 fCurrentFont.SetSize(info.font_size); 93 } 94 } else 95 fCurrentFont = *currentFont; 96 97 fSavedFont = fCurrentFont; 98 99 fSizesMenu = new BPopUpMenu("size menu"); 100 _BuildSizesMenu(); 101 102 fFontsMenu = new BPopUpMenu("font menu"); 103 104 // font menu 105 fFontsMenuField = new BMenuField("fonts", label, fFontsMenu); 106 fFontsMenuField->SetAlignment(B_ALIGN_RIGHT); 107 108 // size menu 109 fSizesMenuField = new BMenuField("size", B_TRANSLATE("Size:"), fSizesMenu); 110 fSizesMenuField->SetAlignment(B_ALIGN_RIGHT); 111 112 // preview 113 fPreviewText = new BStringView("preview text", 114 B_TRANSLATE_COMMENT("The quick brown fox jumps over the lazy dog.", 115 "Don't translate this literally ! Use a phrase showing all chars " 116 "from A to Z.")); 117 118 fPreviewText->SetFont(&fCurrentFont); 119 fPreviewText->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 120 121 // box around preview 122 fPreviewBox = new BBox("preview box", B_WILL_DRAW | B_FRAME_EVENTS); 123 fPreviewBox->AddChild(BGroupLayoutBuilder(B_HORIZONTAL) 124 .Add(fPreviewText) 125 .SetInsets(B_USE_SMALL_SPACING, B_USE_SMALL_SPACING, 126 B_USE_SMALL_SPACING, B_USE_SMALL_SPACING) 127 .TopView() 128 ); 129 } 130 131 132 FontSelectionView::~FontSelectionView() 133 { 134 #ifndef INSTANT_UPDATE 135 _UpdateSystemFont(); 136 #endif 137 } 138 139 140 void 141 FontSelectionView::SetTarget(BHandler* messageTarget) 142 { 143 fMessageTarget = messageTarget; 144 fSizesMenu->SetTargetForItems(fMessageTarget); 145 } 146 147 148 BView* 149 FontSelectionView::GetPreviewBox() 150 { 151 return fPreviewBox; 152 } 153 154 155 void 156 FontSelectionView::MessageReceived(BMessage *msg) 157 { 158 switch (msg->what) { 159 case kMsgSetSize: 160 { 161 int32 size; 162 if (msg->FindInt32("size", &size) != B_OK 163 || size == fCurrentFont.Size()) 164 break; 165 166 fCurrentFont.SetSize(size); 167 _UpdateFontPreview(); 168 break; 169 } 170 171 case kMsgSetFamily: 172 { 173 const char* family; 174 if (msg->FindString("family", &family) != B_OK) 175 break; 176 177 font_style style; 178 fCurrentFont.GetFamilyAndStyle(NULL, &style); 179 180 BMenuItem *familyItem = fFontsMenu->FindItem(family); 181 if (familyItem != NULL) { 182 _SelectCurrentFont(false); 183 184 BMenuItem *item = familyItem->Submenu()->FindItem(style); 185 if (item == NULL) 186 item = familyItem->Submenu()->ItemAt(0); 187 188 if (item != NULL) { 189 item->SetMarked(true); 190 fCurrentFont.SetFamilyAndStyle(family, item->Label()); 191 _UpdateFontPreview(); 192 } 193 } 194 break; 195 } 196 197 case kMsgSetStyle: 198 { 199 const char* family; 200 const char* style; 201 if (msg->FindString("family", &family) != B_OK 202 || msg->FindString("style", &style) != B_OK) 203 break; 204 205 BMenuItem *familyItem = fFontsMenu->FindItem(family); 206 if (!familyItem) 207 break; 208 209 _SelectCurrentFont(false); 210 familyItem->SetMarked(true); 211 212 fCurrentFont.SetFamilyAndStyle(family, style); 213 _UpdateFontPreview(); 214 break; 215 } 216 217 default: 218 BView::MessageReceived(msg); 219 } 220 } 221 222 223 BLayoutItem* 224 FontSelectionView::CreateSizesLabelLayoutItem() 225 { 226 return fSizesMenuField->CreateLabelLayoutItem(); 227 } 228 229 230 BLayoutItem* 231 FontSelectionView::CreateSizesMenuBarLayoutItem() 232 { 233 return fSizesMenuField->CreateMenuBarLayoutItem(); 234 } 235 236 237 BLayoutItem* 238 FontSelectionView::CreateFontsLabelLayoutItem() 239 { 240 return fFontsMenuField->CreateLabelLayoutItem(); 241 } 242 243 244 BLayoutItem* 245 FontSelectionView::CreateFontsMenuBarLayoutItem() 246 { 247 return fFontsMenuField->CreateMenuBarLayoutItem(); 248 } 249 250 251 void 252 FontSelectionView::_BuildSizesMenu() 253 { 254 const int32 sizes[] = {7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 21, 24, 0}; 255 256 // build size menu 257 for (int32 i = 0; sizes[i]; i++) { 258 int32 size = sizes[i]; 259 if (size < kMinSize || size > kMaxSize) 260 continue; 261 262 char label[32]; 263 snprintf(label, sizeof(label), "%" B_PRId32, size); 264 265 BMessage* message = new BMessage(kMsgSetSize); 266 message->AddInt32("size", size); 267 message->AddString("name", Name()); 268 269 BMenuItem* item = new BMenuItem(label, message); 270 if (size == fCurrentFont.Size()) 271 item->SetMarked(true); 272 273 fSizesMenu->AddItem(item); 274 } 275 } 276 277 278 void 279 FontSelectionView::_SelectCurrentFont(bool select) 280 { 281 font_family family; 282 font_style style; 283 fCurrentFont.GetFamilyAndStyle(&family, &style); 284 285 BMenuItem *item = fFontsMenu->FindItem(family); 286 if (item != NULL) { 287 item->SetMarked(select); 288 289 if (item->Submenu() != NULL) { 290 item = item->Submenu()->FindItem(style); 291 if (item != NULL) 292 item->SetMarked(select); 293 } 294 } 295 } 296 297 298 void 299 FontSelectionView::_SelectCurrentSize(bool select) 300 { 301 char label[16]; 302 snprintf(label, sizeof(label), "%" B_PRId32, (int32)fCurrentFont.Size()); 303 304 BMenuItem* item = fSizesMenu->FindItem(label); 305 if (item != NULL) 306 item->SetMarked(select); 307 } 308 309 310 void 311 FontSelectionView::_UpdateFontPreview() 312 { 313 fPreviewText->SetFont(&fCurrentFont); 314 315 #ifdef INSTANT_UPDATE 316 _UpdateSystemFont(); 317 #endif 318 } 319 320 321 void 322 FontSelectionView::_UpdateSystemFont() 323 { 324 font_family family; 325 font_style style; 326 fCurrentFont.GetFamilyAndStyle(&family, &style); 327 328 if (strcmp(Name(), "menu") == 0) { 329 // The menu font is not handled as a system font 330 menu_info info; 331 get_menu_info(&info); 332 333 strlcpy(info.f_family, (const char*)family, B_FONT_FAMILY_LENGTH); 334 strlcpy(info.f_style, (const char*)style, B_FONT_STYLE_LENGTH); 335 info.font_size = fCurrentFont.Size(); 336 337 set_menu_info(&info); 338 } else 339 _set_system_font_(Name(), family, style, fCurrentFont.Size()); 340 } 341 342 343 void 344 FontSelectionView::SetDefaults() 345 { 346 font_family family; 347 font_style style; 348 float size; 349 const char* fontName; 350 351 if (strcmp(Name(), "menu") == 0) 352 fontName = "plain"; 353 else 354 fontName = Name(); 355 356 if (_get_system_default_font_(fontName, family, style, &size) != B_OK) { 357 Revert(); 358 return; 359 } 360 361 BFont defaultFont; 362 defaultFont.SetFamilyAndStyle(family, style); 363 defaultFont.SetSize(size); 364 365 if (defaultFont == fCurrentFont) 366 return; 367 368 _SelectCurrentFont(false); 369 370 fCurrentFont = defaultFont; 371 _UpdateFontPreview(); 372 373 _SelectCurrentFont(true); 374 _SelectCurrentSize(true); 375 } 376 377 378 void 379 FontSelectionView::Revert() 380 { 381 if (!IsRevertable()) 382 return; 383 384 _SelectCurrentFont(false); 385 386 fCurrentFont = fSavedFont; 387 _UpdateFontPreview(); 388 389 _SelectCurrentFont(true); 390 _SelectCurrentSize(true); 391 } 392 393 394 bool 395 FontSelectionView::IsDefaultable() 396 { 397 font_family defaultFamily; 398 font_style defaultStyle; 399 float defaultSize; 400 const char* fontName; 401 402 if (strcmp(Name(), "menu") == 0) 403 fontName = "plain"; 404 else 405 fontName = Name(); 406 407 if (_get_system_default_font_(fontName, defaultFamily, defaultStyle, 408 &defaultSize) != B_OK) { 409 return false; 410 } 411 412 font_family currentFamily; 413 font_style currentStyle; 414 float currentSize; 415 416 fCurrentFont.GetFamilyAndStyle(¤tFamily, ¤tStyle); 417 currentSize = fCurrentFont.Size(); 418 419 return strcmp(currentFamily, defaultFamily) != 0 420 || strcmp(currentStyle, defaultStyle) != 0 421 || currentSize != defaultSize; 422 } 423 424 425 bool 426 FontSelectionView::IsRevertable() 427 { 428 return fCurrentFont != fSavedFont; 429 } 430 431 432 void 433 FontSelectionView::UpdateFontsMenu() 434 { 435 int32 numFamilies = count_font_families(); 436 437 fFontsMenu->RemoveItems(0, fFontsMenu->CountItems(), true); 438 BFont font; 439 fFontsMenu->GetFont(&font); 440 441 font_family currentFamily; 442 font_style currentStyle; 443 fCurrentFont.GetFamilyAndStyle(¤tFamily, ¤tStyle); 444 445 for (int32 i = 0; i < numFamilies; i++) { 446 font_family family; 447 uint32 flags; 448 if (get_font_family(i, &family, &flags) != B_OK) 449 continue; 450 451 // if we're setting the fixed font, we only want to show fixed fonts 452 if (!strcmp(Name(), "fixed") && (flags & B_IS_FIXED) == 0) 453 continue; 454 455 float width = font.StringWidth(family); 456 if (width > fMaxFontNameWidth) 457 fMaxFontNameWidth = width; 458 459 BMenu* stylesMenu = new BMenu(family); 460 stylesMenu->SetRadioMode(true); 461 stylesMenu->SetFont(&font); 462 463 BMessage* message = new BMessage(kMsgSetFamily); 464 message->AddString("family", family); 465 message->AddString("name", Name()); 466 467 BMenuItem* familyItem = new BMenuItem(stylesMenu, message); 468 fFontsMenu->AddItem(familyItem); 469 470 int32 numStyles = count_font_styles(family); 471 472 for (int32 j = 0; j < numStyles; j++) { 473 font_style style; 474 if (get_font_style(family, j, &style, &flags) != B_OK) 475 continue; 476 477 message = new BMessage(kMsgSetStyle); 478 message->AddString("family", (char*)family); 479 message->AddString("style", (char*)style); 480 message->AddString("name", Name()); 481 482 BMenuItem *item = new BMenuItem(style, message); 483 484 if (!strcmp(style, currentStyle) 485 && !strcmp(family, currentFamily)) { 486 item->SetMarked(true); 487 familyItem->SetMarked(true); 488 } 489 stylesMenu->AddItem(item); 490 } 491 492 stylesMenu->SetTargetForItems(fMessageTarget); 493 } 494 495 fFontsMenu->SetTargetForItems(fMessageTarget); 496 } 497