/* * Copyright 2001-2010, Haiku. * Distributed under the terms of the MIT License. * * Authors: * Mark Hogben * DarkWyrm * Axel Dörfler, axeld@pinc-software.de * Philippe Saint-Pierre, stpere@gmail.com * Stephan Aßmus */ #include "FontSelectionView.h" #include "private/interface/FontPrivate.h" #include #include #include #include #include #include #include #include #include #include #include #include #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "Font Selection view" static const float kMinSize = 8.0; static const float kMaxSize = 18.0; static const int32 kMsgSetFamily = 'fmly'; static const int32 kMsgSetStyle = 'styl'; static const int32 kMsgSetSize = 'size'; // #pragma mark - FontSelectionView::FontSelectionView(const char* name, const char* label, bool separateStyles, const BFont* currentFont) : BHandler(name), fMessage(NULL), fTarget(NULL) { if (currentFont == NULL) fCurrentFont = _DefaultFont(); else fCurrentFont = *currentFont; fSavedFont = fCurrentFont; fSizesMenu = new BPopUpMenu("size menu"); fFontsMenu = new BPopUpMenu("font menu"); // font menu fFontsMenuField = new BMenuField("fonts", label, fFontsMenu, B_WILL_DRAW); fFontsMenuField->SetAlignment(B_ALIGN_RIGHT); // styles menu, if desired if (separateStyles) { fStylesMenu = new BPopUpMenu("styles menu"); fStylesMenuField = new BMenuField("styles", B_TRANSLATE("Style:"), fStylesMenu, B_WILL_DRAW); } else { fStylesMenu = NULL; fStylesMenuField = NULL; } // size menu fSizesMenuField = new BMenuField("size", B_TRANSLATE("Size:"), fSizesMenu, B_WILL_DRAW); fSizesMenuField->SetAlignment(B_ALIGN_RIGHT); // preview fPreviewText = new BStringView("preview text", B_TRANSLATE_COMMENT("The quick brown fox jumps over the lazy dog.", "Don't translate this literally ! Use a phrase showing all " "chars from A to Z.")); fPreviewText->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); fPreviewText->SetHighUIColor(B_PANEL_BACKGROUND_COLOR, 1.65); fPreviewBox = new BBox("preview box", B_WILL_DRAW | B_FRAME_EVENTS); fPreviewBox->AddChild(BGroupLayoutBuilder(B_VERTICAL, B_USE_HALF_ITEM_SPACING) .Add(fPreviewText) .SetInsets(B_USE_HALF_ITEM_SPACING, B_USE_HALF_ITEM_SPACING, B_USE_HALF_ITEM_SPACING, B_USE_HALF_ITEM_SPACING) .TopView() ); _UpdateFontPreview(); } FontSelectionView::~FontSelectionView() { // Some controls may not have been attached... if (!fPreviewText->Window()) delete fPreviewText; if (!fSizesMenuField->Window()) delete fSizesMenuField; if (fStylesMenuField && !fStylesMenuField->Window()) delete fStylesMenuField; if (!fFontsMenuField->Window()) delete fFontsMenuField; delete fMessage; } void FontSelectionView::AttachedToLooper() { _BuildSizesMenu(); UpdateFontsMenu(); } void FontSelectionView::MessageReceived(BMessage* message) { switch (message->what) { case kMsgSetSize: { int32 size; if (message->FindInt32("size", &size) != B_OK || size == fCurrentFont.Size()) break; fCurrentFont.SetSize(size); _UpdateFontPreview(); _Invoke(); break; } case kMsgSetFamily: { const char* family; if (message->FindString("family", &family) != B_OK) break; font_style style; fCurrentFont.GetFamilyAndStyle(NULL, &style); BMenuItem* familyItem = fFontsMenu->FindItem(family); if (familyItem != NULL) { _SelectCurrentFont(false); BMenuItem* styleItem; if (fStylesMenuField != NULL) styleItem = fStylesMenuField->Menu()->FindMarked(); else { styleItem = familyItem->Submenu()->FindItem(style); if (styleItem == NULL) styleItem = familyItem->Submenu()->ItemAt(0); } if (styleItem != NULL) { styleItem->SetMarked(true); fCurrentFont.SetFamilyAndStyle(family, styleItem->Label()); _UpdateFontPreview(); } if (fStylesMenuField != NULL) _AddStylesToMenu(fCurrentFont, fStylesMenuField->Menu()); } _Invoke(); break; } case kMsgSetStyle: { const char* family; const char* style; if (message->FindString("family", &family) != B_OK || message->FindString("style", &style) != B_OK) break; BMenuItem *familyItem = fFontsMenu->FindItem(family); if (!familyItem) break; _SelectCurrentFont(false); familyItem->SetMarked(true); fCurrentFont.SetFamilyAndStyle(family, style); _UpdateFontPreview(); _Invoke(); break; } default: BHandler::MessageReceived(message); } } void FontSelectionView::SetMessage(BMessage* message) { delete fMessage; fMessage = message; } void FontSelectionView::SetTarget(BHandler* target) { fTarget = target; } // #pragma mark - void FontSelectionView::SetFont(const BFont& font, float size) { BFont resizedFont(font); resizedFont.SetSize(size); SetFont(resizedFont); } void FontSelectionView::SetFont(const BFont& font) { if (font == fCurrentFont && font == fSavedFont) return; _SelectCurrentFont(false); fSavedFont = fCurrentFont = font; _UpdateFontPreview(); _SelectCurrentFont(true); _SelectCurrentSize(true); } void FontSelectionView::SetSize(float size) { SetFont(fCurrentFont, size); } const BFont& FontSelectionView::Font() const { return fCurrentFont; } void FontSelectionView::SetDefaults() { BFont defaultFont = _DefaultFont(); if (defaultFont == fCurrentFont) return; _SelectCurrentFont(false); fCurrentFont = defaultFont; _UpdateFontPreview(); _SelectCurrentFont(true); _SelectCurrentSize(true); } void FontSelectionView::Revert() { if (!IsRevertable()) return; _SelectCurrentFont(false); fCurrentFont = fSavedFont; _UpdateFontPreview(); _SelectCurrentFont(true); _SelectCurrentSize(true); } bool FontSelectionView::IsDefaultable() { return fCurrentFont != _DefaultFont(); } bool FontSelectionView::IsRevertable() { return fCurrentFont != fSavedFont; } void FontSelectionView::UpdateFontsMenu() { int32 numFamilies = count_font_families(); fFontsMenu->RemoveItems(0, fFontsMenu->CountItems(), true); BFont font = fCurrentFont; font_family currentFamily; font_style currentStyle; font.GetFamilyAndStyle(¤tFamily, ¤tStyle); for (int32 i = 0; i < numFamilies; i++) { font_family family; uint32 flags; if (get_font_family(i, &family, &flags) != B_OK) continue; // if we're setting the fixed font, we only want to show fixed and // full-and-half-fixed fonts if (strcmp(Name(), "fixed") == 0 && (flags & (B_IS_FIXED | B_PRIVATE_FONT_IS_FULL_AND_HALF_FIXED)) == 0) { continue; } font.SetFamilyAndFace(family, B_REGULAR_FACE); BMessage* message = new BMessage(kMsgSetFamily); message->AddString("family", family); message->AddString("name", Name()); BMenuItem* familyItem; if (fStylesMenuField != NULL) { familyItem = new BMenuItem(family, message); } else { // Each family item has a submenu with all styles for that font. BMenu* stylesMenu = new BMenu(family); _AddStylesToMenu(font, stylesMenu); familyItem = new BMenuItem(stylesMenu, message); } familyItem->SetMarked(strcmp(family, currentFamily) == 0); fFontsMenu->AddItem(familyItem); familyItem->SetTarget(this); } // Separate styles menu for only the current font. if (fStylesMenuField != NULL) _AddStylesToMenu(fCurrentFont, fStylesMenuField->Menu()); } // #pragma mark - private BLayoutItem* FontSelectionView::CreateSizesLabelLayoutItem() { return fSizesMenuField->CreateLabelLayoutItem(); } BLayoutItem* FontSelectionView::CreateSizesMenuBarLayoutItem() { return fSizesMenuField->CreateMenuBarLayoutItem(); } BLayoutItem* FontSelectionView::CreateFontsLabelLayoutItem() { return fFontsMenuField->CreateLabelLayoutItem(); } BLayoutItem* FontSelectionView::CreateFontsMenuBarLayoutItem() { return fFontsMenuField->CreateMenuBarLayoutItem(); } BLayoutItem* FontSelectionView::CreateStylesLabelLayoutItem() { if (fStylesMenuField) return fStylesMenuField->CreateLabelLayoutItem(); return NULL; } BLayoutItem* FontSelectionView::CreateStylesMenuBarLayoutItem() { if (fStylesMenuField) return fStylesMenuField->CreateMenuBarLayoutItem(); return NULL; } BView* FontSelectionView::PreviewBox() const { return fPreviewBox; } // #pragma mark - private void FontSelectionView::_Invoke() { if (fTarget != NULL && fTarget->Looper() != NULL && fMessage != NULL) { BMessage message(*fMessage); fTarget->Looper()->PostMessage(&message, fTarget); } } BFont FontSelectionView::_DefaultFont() const { if (strcmp(Name(), "bold") == 0) return *be_bold_font; if (strcmp(Name(), "fixed") == 0) return *be_fixed_font; else return *be_plain_font; } void FontSelectionView::_SelectCurrentFont(bool select) { font_family family; font_style style; fCurrentFont.GetFamilyAndStyle(&family, &style); BMenuItem *item = fFontsMenu->FindItem(family); if (item != NULL) { item->SetMarked(select); if (item->Submenu() != NULL) { item = item->Submenu()->FindItem(style); if (item != NULL) item->SetMarked(select); } } } void FontSelectionView::_SelectCurrentSize(bool select) { char label[16]; snprintf(label, sizeof(label), "%" B_PRId32, (int32)fCurrentFont.Size()); BMenuItem* item = fSizesMenu->FindItem(label); if (item != NULL) item->SetMarked(select); } void FontSelectionView::_UpdateFontPreview() { fPreviewText->SetFont(&fCurrentFont); } void FontSelectionView::_BuildSizesMenu() { const int32 sizes[] = {7, 8, 9, 10, 11, 12, 13, 14, 18, 21, 24, 0}; // build size menu for (int32 i = 0; sizes[i]; i++) { int32 size = sizes[i]; if (size < kMinSize || size > kMaxSize) continue; char label[32]; snprintf(label, sizeof(label), "%" B_PRId32, size); BMessage* message = new BMessage(kMsgSetSize); message->AddInt32("size", size); message->AddString("name", Name()); BMenuItem* item = new BMenuItem(label, message); if (size == fCurrentFont.Size()) item->SetMarked(true); fSizesMenu->AddItem(item); item->SetTarget(this); } } void FontSelectionView::_AddStylesToMenu(const BFont& font, BMenu* stylesMenu) const { stylesMenu->RemoveItems(0, stylesMenu->CountItems(), true); stylesMenu->SetRadioMode(true); font_family family; font_style style; font.GetFamilyAndStyle(&family, &style); BString currentStyle(style); int32 numStyles = count_font_styles(family); for (int32 j = 0; j < numStyles; j++) { if (get_font_style(family, j, &style) != B_OK) continue; BMessage* message = new BMessage(kMsgSetStyle); message->AddString("family", (char*)family); message->AddString("style", (char*)style); BMenuItem* item = new BMenuItem(style, message); item->SetMarked(currentStyle == style); stylesMenu->AddItem(item); item->SetTarget(this); } }