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