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