From b5086559b816f68506d33362566377443a1ff1d8 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 23 Jul 2008 16:38:39 +0000 Subject: Font rendering overhaul. Work in progress. svn-id: r33247 --- graphics/VectorRenderer.cpp | 9 ---- graphics/VectorRenderer.h | 21 -------- gui/ThemeDefaultXML.cpp | 30 ++++++----- gui/ThemeParser.cpp | 48 ++++------------- gui/ThemeRenderer.cpp | 125 +++++++++++++++++++++++++++----------------- gui/ThemeRenderer.h | 91 +++++++++++++++++--------------- 6 files changed, 154 insertions(+), 170 deletions(-) diff --git a/graphics/VectorRenderer.cpp b/graphics/VectorRenderer.cpp index 639039fe28..adcd299811 100644 --- a/graphics/VectorRenderer.cpp +++ b/graphics/VectorRenderer.cpp @@ -75,15 +75,6 @@ void VectorRenderer::drawStep(const Common::Rect &area, const DrawStep &step, ui (this->*(step.drawingCall))(area, step); } -void VectorRenderer::textStep(const Common::String &text, const Common::Rect &area, const TextStep &step, GUI::Theme::TextAlign alignH) { - if (step.color.set) - setFgColor(step.color.r, step.color.g, step.color.b); - - drawString(step.font, text.c_str(), area, - !step.hasAlign ? alignH : step.alignHorizontal, - !step.hasAlign ? GUI::Theme::kTextAlignVTop : step.alignVertical); -} - int VectorRenderer::stepGetRadius(const DrawStep &step, const Common::Rect &area) { int radius = 0; diff --git a/graphics/VectorRenderer.h b/graphics/VectorRenderer.h index a5e80164be..8a020ebfad 100644 --- a/graphics/VectorRenderer.h +++ b/graphics/VectorRenderer.h @@ -39,20 +39,6 @@ namespace Graphics { class VectorRenderer; struct DrawStep; -struct TextStep { - struct { - uint8 r, g, b; - bool set; - } - color; /** text color */ - - GUI::Theme::TextAlign alignHorizontal; - GUI::Theme::TextAlignVertical alignVertical; - bool hasAlign; - char *text; - const Graphics::Font *font; -}; - struct DrawStep { struct { uint8 r, g, b; @@ -404,7 +390,6 @@ public: * @param step Pointer to a DrawStep struct. */ virtual void drawStep(const Common::Rect &area, const DrawStep &step, uint32 extra = 0); - virtual void textStep(const Common::String &text, const Common::Rect &area, const TextStep &step, GUI::Theme::TextAlign alignH = GUI::Theme::kTextAlignLeft); /** * Copies the current surface to the system overlay @@ -422,8 +407,6 @@ public: */ virtual void blitSurface(Graphics::Surface *source, const Common::Rect &r) = 0; - virtual uint32 buildColor(uint8 r, uint8 g, uint8 b) = 0; - virtual void drawString(const Graphics::Font *font, const Common::String &text, const Common::Rect &area, GUI::Theme::TextAlign alignH, GUI::Theme::TextAlignVertical alignV) = 0; virtual void disableShadows() { _disableShadows = true; } @@ -595,10 +578,6 @@ public: src_ptr += src_pitch; } } - - virtual uint32 buildColor(uint8 r, uint8 g, uint8 b) { - return RGBToColor(r, g, b); - } protected: diff --git a/gui/ThemeDefaultXML.cpp b/gui/ThemeDefaultXML.cpp index 77a65cfdc6..d294f6b708 100644 --- a/gui/ThemeDefaultXML.cpp +++ b/gui/ThemeDefaultXML.cpp @@ -42,18 +42,20 @@ bool ThemeRenderer::loadDefaultXML() { "" "" "" - "" - "" - "" "" "" - "" - "" - "" + "" + "" + "" + "" "" "" + + "" + "" + "" "" "" @@ -68,12 +70,12 @@ bool ThemeRenderer::loadDefaultXML() { "" "" - "" + "" "" "" "" - "" + "" "" "" @@ -95,7 +97,7 @@ bool ThemeRenderer::loadDefaultXML() { "" "" "" - "" + "" "" "" @@ -103,27 +105,27 @@ bool ThemeRenderer::loadDefaultXML() { "" "" - "" + "" "" "" "" - "" + "" "" "" "" - "" + "" "" "" "" - "" + "" "" "" "" - "" + "" "" "" "" diff --git a/gui/ThemeParser.cpp b/gui/ThemeParser.cpp index 5a5a6e8af8..89f0595c67 100644 --- a/gui/ThemeParser.cpp +++ b/gui/ThemeParser.cpp @@ -160,10 +160,6 @@ bool ThemeParser::parserCallback_font() { if (!tNode->values.contains("type")) return parserError("Font definitions need a valid typename."); - - // TODO: set typename on the drawstep. - - Graphics::TextStep step; if (tNode->values.contains("horizontal_align") || tNode->values.contains("vertical_align")) return parserError("Font definitions cannot contain alignments."); @@ -181,13 +177,7 @@ bool ThemeParser::parserCallback_font() { return parserError("Cannot assign color in font definition."); } - step.color.r = red; - step.color.g = green; - step.color.b = blue; - step.color.set = true; - step.hasAlign = false; - - if (!_theme->addTextStep(tNode->values["id"], step)) + if (!_theme->addFont(tNode->values["id"], red, green, blue)) return parserError("Error when loading Font in theme engine."); return true; @@ -209,47 +199,29 @@ bool ThemeParser::parserCallback_text() { if (parentNode == 0 || parentNode->name != "drawdata") return parserError("Text Steps must be contained inside keys."); - Graphics::TextStep step; + GUI::Theme::TextAlign alignH; + GUI::Theme::TextAlignVertical alignV; if (tNode->values.contains("horizontal_align") == false || tNode->values.contains("vertical_align") == false) return parserError("Text inside widgets requires proper alignment keys."); if (tNode->values["horizontal_align"] == "left") - step.alignHorizontal = GUI::Theme::kTextAlignLeft; + alignH = GUI::Theme::kTextAlignLeft; else if (tNode->values["horizontal_align"] == "right") - step.alignHorizontal = GUI::Theme::kTextAlignRight; + alignH = GUI::Theme::kTextAlignRight; else if (tNode->values["horizontal_align"] == "center") - step.alignHorizontal = GUI::Theme::kTextAlignCenter; + alignH = GUI::Theme::kTextAlignCenter; else return parserError("Invalid value for text alignment."); if (tNode->values["vertical_align"] == "top") - step.alignVertical = GUI::Theme::kTextAlignVTop; + alignV = GUI::Theme::kTextAlignVTop; else if (tNode->values["vertical_align"] == "center") - step.alignVertical = GUI::Theme::kTextAlignVCenter; + alignV = GUI::Theme::kTextAlignVCenter; else if (tNode->values["vertical_align"] == "bottom") - step.alignVertical = GUI::Theme::kTextAlignVBottom; + alignV = GUI::Theme::kTextAlignVBottom; else return parserError("Invalid value for text alignment."); - int red, green, blue; - - if (tNode->values.contains("color")) { - - if (_palette.contains(tNode->values["color"])) - getPaletteColor(tNode->values["color"], red, green, blue); - else if (!parseIntegerKey(tNode->values["color"].c_str(), 3, &red, &green, &blue)) - return parserError("Error when parsing color value for text definition"); - - } else { - return parserError("Cannot assign color for text drawing."); - } - - step.color.r = red; - step.color.g = green; - step.color.b = blue; - step.color.set = true; - step.hasAlign = true; - - return _theme->addTextStep(parentNode->values["id"], step); + return _theme->addTextData(parentNode->values["id"], tNode->values["font"], alignH, alignV); } bool ThemeParser::parserCallback_renderInfo() { diff --git a/gui/ThemeRenderer.cpp b/gui/ThemeRenderer.cpp index 0b02f88a2c..1123bf1816 100644 --- a/gui/ThemeRenderer.cpp +++ b/gui/ThemeRenderer.cpp @@ -44,6 +44,7 @@ const ThemeRenderer::DrawDataInfo ThemeRenderer::kDrawDataDefaults[] = { {kDDSpecialColorBackground, "special_bg", true, kDDNone}, {kDDPlainColorBackground, "plain_bg", true, kDDNone}, {kDDDefaultBackground, "default_bg", true, kDDNone}, + {kDDTextSelectionBackground, "text_selection", false, kDDNone}, {kDDWidgetBackgroundDefault, "widget_default", true, kDDNone}, {kDDWidgetBackgroundSmall, "widget_small", true, kDDNone}, @@ -72,6 +73,13 @@ const ThemeRenderer::DrawDataInfo ThemeRenderer::kDrawDataDefaults[] = { {kDDSeparator, "separator", true, kDDNone}, }; +const ThemeRenderer::TextDataInfo ThemeRenderer::kTextDataDefaults[] = { + {kTextDataDefault, "text_default"}, + {kTextDataHover, "text_hover"}, + {kTextDataDisabled, "text_disabled"}, + {kTextDataInverted, "text_inverted"} +}; + ThemeRenderer::ThemeRenderer(Common::String themeName, GraphicsMode mode) : _vectorRenderer(0), _system(0), _graphicsMode(kGfxDisabled), @@ -83,6 +91,10 @@ ThemeRenderer::ThemeRenderer(Common::String themeName, GraphicsMode mode) : for (int i = 0; i < kDrawDataMAX; ++i) { _widgets[i] = 0; } + + for (int i = 0; i < kTextDataMAX; ++i) { + _texts[i] = 0; + } _graphicsMode = mode; setGraphicsMode(_graphicsMode); @@ -111,14 +123,6 @@ bool ThemeRenderer::init() { Theme::loadTheme(_configFile, false, true); } - if (_fontName.empty()) { - if (_screen->w >= 400 && _screen->h >= 300) { - _font = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont); - } else { - _font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont); - } - } - return true; } @@ -195,29 +199,43 @@ void ThemeRenderer::addDrawStep(const Common::String &drawDataId, Graphics::Draw _widgets[id]->_steps.push_back(step); } -bool ThemeRenderer::addTextStep(const Common::String &drawDataId, Graphics::TextStep step) { +bool ThemeRenderer::addTextData(const Common::String &drawDataId, const Common::String &textDataId, TextAlign alignH, TextAlignVertical alignV) { DrawData id = getDrawDataId(drawDataId); + TextData textId = getTextDataId(textDataId); - step.font = 0; + if (id == -1 || textId == -1 || !_widgets[id]) + return false; - if (id != -1) { - assert(_widgets[id] != 0); - if (_widgets[id]->_hasText == true) - return false; + _widgets[id]->_textDataId = textId; + _widgets[id]->_textAlignH = alignH; + _widgets[id]->_textAlignV = alignV; - _widgets[id]->_textStep = step; - _widgets[id]->_hasText = true; + return true; +} + +bool ThemeRenderer::addFont(const Common::String &fontId, int r, int g, int b) { + TextData textId = getTextDataId(fontId); + + if (textId == -1) + return false; + + if (_texts[textId] != 0) + return false; + + _texts[textId] = new TextDrawData; + + // TODO: Allow the user to specify the font he wants, instead of choosing based on resolution + if (_screen->w >= 400 && _screen->h >= 300) { + _texts[textId]->_fontPtr = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont); } else { - if (drawDataId == "default") { - _texts[kTextColorDefault] = step; - } else if (drawDataId == "hover") { - _texts[kTextColorHover] = step; - } else if (drawDataId == "disabled") { - _texts[kTextColorDisabled] = step; - } else return false; + _texts[textId]->_fontPtr = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont); } - + + _texts[textId]->_color.r = r; + _texts[textId]->_color.g = g; + _texts[textId]->_color.b = b; return true; + } bool ThemeRenderer::addDrawData(const Common::String &data, bool cached) { @@ -230,7 +248,7 @@ bool ThemeRenderer::addDrawData(const Common::String &data, bool cached) { _widgets[data_id]->_cached = cached; _widgets[data_id]->_buffer = kDrawDataDefaults[data_id].buffer; _widgets[data_id]->_surfaceCache = 0; - _widgets[data_id]->_hasText = false; + _widgets[data_id]->_textDataId = -1; return true; } @@ -320,14 +338,19 @@ void ThemeRenderer::queueDD(DrawData type, const Common::Rect &r, uint32 dynamic } } -void ThemeRenderer::queueDDText(DrawData type, const Common::Rect &r, const Common::String &text, TextColor colorId, TextAlign align) { +void ThemeRenderer::queueDDText(TextData type, const Common::Rect &r, const Common::String &text, + bool elipsis, TextAlign alignH, TextAlignVertical alignV) { + + if (_texts[type] == 0) + return; + DrawQueueText q; q.type = type; q.area = r; q.area.clip(_screen->w, _screen->h); q.text = text; - q.colorId = colorId; - q.align = align; + q.alignH = alignH; + q.alignV = alignV; if (_buffering) { _textQueue.push_back(q); @@ -359,19 +382,11 @@ void ThemeRenderer::drawDD(const DrawQueue &q, bool draw, bool restore) { } void ThemeRenderer::drawDDText(const DrawQueueText &q) { - if (q.type == kDDNone) { + if (q.type != kTextDataInverted) restoreBackground(q.area); - if (_texts[q.colorId].font == 0) - _texts[q.colorId].font = _font; - - _vectorRenderer->textStep(q.text, q.area, _texts[q.colorId], q.align); - } else { - if (_widgets[q.type]->_textStep.font == 0) - _widgets[q.type]->_textStep.font = _font; - - _vectorRenderer->textStep(q.text, q.area, _widgets[q.type]->_textStep); - } + _vectorRenderer->setFgColor(_texts[q.type]->_color.r, _texts[q.type]->_color.g, _texts[q.type]->_color.b); + _vectorRenderer->drawString(_texts[q.type]->_fontPtr, q.text, q.area, q.alignH, q.alignV); addDirtyRect(q.area); } @@ -405,7 +420,7 @@ void ThemeRenderer::drawButton(const Common::Rect &r, const Common::String &str, dd = kDDButtonDisabled; queueDD(dd, r); - queueDDText(dd, r, str); + queueDDText(getTextData(dd), r, str, false, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV); } void ThemeRenderer::drawLineSeparator(const Common::Rect &r, WidgetStateInfo state) { @@ -420,17 +435,18 @@ void ThemeRenderer::drawCheckbox(const Common::Rect &r, const Common::String &st return; Common::Rect r2 = r; + DrawData dd = checked ? kDDCheckboxEnabled : kDDCheckboxDisabled; const int checkBoxSize = MIN((int)r.height(), getFontHeight()); r2.bottom = r2.top + checkBoxSize; r2.right = r2.left + checkBoxSize; - queueDD(checked ? kDDCheckboxEnabled : kDDCheckboxDisabled, r2); + queueDD(dd, r2); r2.left = r2.right + checkBoxSize; r2.right = r.right; - queueDDText(checked ? kDDCheckboxEnabled : kDDCheckboxDisabled, r2, str); + queueDDText(getTextData(dd), r2, str, false, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV); } void ThemeRenderer::drawSlider(const Common::Rect &r, int width, WidgetStateInfo state) { @@ -484,7 +500,7 @@ void ThemeRenderer::drawPopUpWidget(const Common::Rect &r, const Common::String if (!sel.empty()) { Common::Rect text(r.left, r.top, r.right - 16, r.bottom); - queueDDText(dd, text, sel); + queueDDText(getTextData(dd), text, sel, false, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV); } } @@ -530,7 +546,7 @@ void ThemeRenderer::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, Common::Rect tabRect(r.left + i * (tabWidth + tabOffset), r.top, r.left + i * (tabWidth + tabOffset) + tabWidth, r.top + tabHeight); queueDD(kDDTabInactive, tabRect); - queueDDText(kDDTabInactive, tabRect, tabs[i]); + queueDDText(getTextData(kDDTabInactive), tabRect, tabs[i], false, _widgets[kDDTabInactive]->_textAlignH, _widgets[kDDTabInactive]->_textAlignV); } if (active >= 0) { @@ -538,15 +554,30 @@ void ThemeRenderer::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const uint16 tabLeft = active * (tabWidth + tabOffset); const uint16 tabRight = MAX(r.right - tabRect.right, 0); queueDD(kDDTabActive, tabRect, (tabLeft << 16) | (tabRight & 0xFFFF)); - queueDDText(kDDTabActive, tabRect, tabs[active]); + queueDDText(getTextData(kDDTabActive), tabRect, tabs[active], false, _widgets[kDDTabActive]->_textAlignH, _widgets[kDDTabActive]->_textAlignV); } } void ThemeRenderer::drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, TextAlign align, bool inverted, int deltax, bool useEllipsis, FontStyle font) { if (!_initOk) return; - - queueDDText(kDDNone, r, str, getTextColor(state), align); + + if (inverted) + queueDD(kDDTextSelectionBackground, r); + + switch (state) { + case kStateDisabled: + queueDDText(inverted ? kTextDataInverted : kTextDataDisabled, r, str, useEllipsis); + break; + + case kStateHighlight: + queueDDText(inverted ? kTextDataInverted : kTextDataHover, r, str, useEllipsis); + break; + + case kStateEnabled: + queueDDText(inverted ? kTextDataInverted : kTextDataDefault, r, str, useEllipsis); + break; + } } void ThemeRenderer::debugWidgetPosition(const char *name, const Common::Rect &r) { diff --git a/gui/ThemeRenderer.h b/gui/ThemeRenderer.h index a43d13b6e3..ab4f5cb890 100644 --- a/gui/ThemeRenderer.h +++ b/gui/ThemeRenderer.h @@ -42,13 +42,21 @@ namespace GUI { struct WidgetDrawData; struct DrawDataInfo; +struct TextDrawData { + const Graphics::Font *_fontPtr; + + struct { + uint8 r, g, b; + } _color; +}; + struct WidgetDrawData { /** List of all the steps needed to draw this widget */ Common::List _steps; - /** Single step that defines the text shown inside the widget */ - Graphics::TextStep _textStep; - bool _hasText; + int _textDataId; + GUI::Theme::TextAlign _textAlignH; + GUI::Theme::TextAlignVertical _textAlignV; /** Extra space that the widget occupies when it's drawn. E.g. when taking into account rounded corners, drop shadows, etc @@ -97,6 +105,7 @@ protected: kDDSpecialColorBackground, kDDPlainColorBackground, kDDDefaultBackground, + kDDTextSelectionBackground, kDDWidgetBackgroundDefault, kDDWidgetBackgroundSmall, @@ -149,21 +158,28 @@ protected: uint32 dynData; /** Dynamic data which modifies the DrawData item (optional)*/ }; - enum TextColor { - kTextColorNone = -1, - kTextColorDefault, - kTextColorHover, - kTextColorDisabled, - kTextColorInverted, - kTextColorMAX + enum TextData { + kTextDataNone = -1, + kTextDataDefault = 0, + kTextDataHover, + kTextDataDisabled, + kTextDataInverted, + kTextDataMAX }; + static const struct TextDataInfo { + TextData id; + const char *name; + } kTextDataDefaults[]; + struct DrawQueueText { - DrawData type; + TextData type; Common::Rect area; Common::String text; - TextColor colorId; - TextAlign align; + + GUI::Theme::TextAlign alignH; + GUI::Theme::TextAlignVertical alignV; + bool elipsis; }; public: @@ -312,6 +328,14 @@ public: return kDDNone; } + + TextData getTextDataId(const Common::String &name) { + for (int i = 0; i < kTextDataMAX; ++i) + if (name.compareToIgnoreCase(kTextDataDefaults[i].name) == 0) + return kTextDataDefaults[i].id; + + return kTextDataNone; + } /** * Interface for ThemeParser class: Parsed DrawSteps are added via this function. @@ -334,12 +358,13 @@ public: * @param cached Whether this DD set will be cached beforehand. */ bool addDrawData(const Common::String &data, bool cached); + bool addFont(const Common::String &fontName, int r, int g, int b); /** * Adds a new TextStep from the ThemeParser. This will be deprecated/removed once the * new Font API is in place. */ - bool addTextStep(const Common::String &drawDataId, Graphics::TextStep step); + bool addTextData(const Common::String &drawDataId, const Common::String &textDataId, TextAlign alignH, TextAlignVertical alignV); /** Interface to the new Theme XML parser */ ThemeParser *parser() { @@ -414,6 +439,11 @@ protected: delete _widgets[i]; _widgets[i] = 0; } + + for (int i = 0; i < kTextDataMAX; ++i) { + delete _texts[i]; + _texts[i] = 0; + } _themeOk = false; } @@ -461,14 +491,9 @@ protected: _screen = 0; } } - - /** - * Checks if the given widget type has a Text drawing step associated to it. - * - * @param type DrawData type of the widget. - */ - bool hasWidgetText(DrawData type) { - return (_widgets[type] != 0 && _widgets[type]->_hasText); + + TextData getTextData(DrawData ddId) { + return _widgets[ddId] ? (TextData)_widgets[ddId]->_textDataId : kTextDataNone; } /** @@ -523,8 +548,8 @@ protected: * This function is called from all the Widget Drawing methods. */ inline void queueDD(DrawData type, const Common::Rect &r, uint32 dynamic = 0); - inline void queueDDText(DrawData type, const Common::Rect &r, const Common::String &text, - TextColor colorId = kTextColorNone, TextAlign align = kTextAlignLeft); + inline void queueDDText(TextData type, const Common::Rect &r, const Common::String &text, + bool elipsis, TextAlign alignH = kTextAlignLeft, TextAlignVertical alignV = kTextAlignVTop); /** * DEBUG: Draws a white square around the given position and writes the given next to it. @@ -547,22 +572,6 @@ protected: */ int getTabSpacing() const { return 0; } int getTabPadding() const { return 3; } - - /** - * Translates a WidgetStateInfo of a Text widget to the actual font color value. - */ - TextColor getTextColor(WidgetStateInfo state) { - switch (state) { - case kStateDisabled: - return kTextColorDisabled; - - case kStateHighlight: - return kTextColorHover; - - default: - return kTextColorDefault; - } - } OSystem *_system; /** Global system object. */ @@ -597,7 +606,7 @@ protected: WidgetDrawData *_widgets[kDrawDataMAX]; /** Array of all the text fonts that can be drawn. */ - Graphics::TextStep _texts[kTextColorMAX]; + TextDrawData *_texts[kTextDataMAX]; /** List of all the dirty screens that must be blitted to the overlay. */ Common::List _dirtyScreen; -- cgit v1.2.3