aboutsummaryrefslogtreecommitdiff
path: root/gui/ThemeEngine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gui/ThemeEngine.cpp')
-rw-r--r--gui/ThemeEngine.cpp435
1 files changed, 202 insertions, 233 deletions
diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp
index 755d322816..6a0a8c406c 100644
--- a/gui/ThemeEngine.cpp
+++ b/gui/ThemeEngine.cpp
@@ -40,110 +40,60 @@
#include "gui/ThemeEngine.h"
#include "gui/ThemeEval.h"
#include "gui/ThemeParser.h"
+#include "gui/ThemeData.h"
#define GUI_ENABLE_BUILTIN_THEME
namespace GUI {
-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<Graphics::DrawStep> _steps;
-
- 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
- Used when restoring the widget background */
- uint16 _backgroundOffset;
-
- /** Sets whether the widget is cached beforehand. */
- bool _cached;
- bool _buffer;
-
- /** Texture where the cached widget is stored. */
- Graphics::Surface *_surfaceCache;
+/**********************************************************
+ * ThemeEngine class
+ *********************************************************/
+ThemeEngine::ThemeEngine(Common::String fileName, GraphicsMode mode) :
+ _system(0), _vectorRenderer(0), _screen(0), _backBuffer(0),
+ _buffering(false), _bytesPerPixel(0), _graphicsMode(kGfxDisabled),
+ _font(0), _initOk(false), _themeOk(false), _enabled(false), _cursor(0),
+ _loadedThemeX(0), _loadedThemeY(0) {
+
+ _system = g_system;
+ _parser = new ThemeParser(this);
+ _themeEval = new GUI::ThemeEval();
- ~WidgetDrawData() {
- _steps.clear();
+ _useCursor = false;
- if (_surfaceCache) {
- _surfaceCache->free();
- delete _surfaceCache;
- }
+ for (int i = 0; i < kDrawDataMAX; ++i) {
+ _widgets[i] = 0;
}
-};
-
-class ThemeItem {
-
-public:
- ThemeItem(ThemeEngine *engine, const Common::Rect &area) :
- _engine(engine), _area(area) {}
- virtual ~ThemeItem() {}
-
- virtual void drawSelf(bool doDraw, bool doRestore) = 0;
-
-protected:
- ThemeEngine *_engine;
- Common::Rect _area;
-};
-class ThemeItemDrawData : public ThemeItem {
-public:
- ThemeItemDrawData(ThemeEngine *engine, const WidgetDrawData *data, const Common::Rect &area, uint32 dynData) :
- ThemeItem(engine, area), _dynamicData(dynData), _data(data) {}
-
- void drawSelf(bool draw, bool restore);
-
-protected:
- uint32 _dynamicData;
- const WidgetDrawData *_data;
-};
+ for (int i = 0; i < kTextDataMAX; ++i) {
+ _texts[i] = 0;
+ }
-class ThemeItemTextData : public ThemeItem {
-public:
- ThemeItemTextData(ThemeEngine *engine, const TextDrawData *data, const Common::Rect &area, const Common::String &text,
- GUI::Theme::TextAlign alignH, GUI::Theme::TextAlignVertical alignV,
- bool ellipsis, bool restoreBg, int deltaX) :
- ThemeItem(engine, area), _data(data), _text(text), _alignH(alignH), _alignV(alignV),
- _ellipsis(ellipsis), _restoreBg(restoreBg), _deltax(deltaX) {}
-
- void drawSelf(bool draw, bool restore);
-
-protected:
- const TextDrawData *_data;
- Common::String _text;
- GUI::Theme::TextAlign _alignH;
- GUI::Theme::TextAlignVertical _alignV;
- bool _ellipsis;
- bool _restoreBg;
- int _deltax;
-};
+ _graphicsMode = mode;
+ _themeFileName = fileName;
+ _initOk = false;
+}
-class ThemeItemBitmap : public ThemeItem {
-public:
- ThemeItemBitmap(ThemeEngine *engine, const Common::Rect &area, const Graphics::Surface *bitmap, bool alpha) :
- ThemeItem(engine, area), _bitmap(bitmap), _alpha(alpha) {}
+ThemeEngine::~ThemeEngine() {
+ freeRenderer();
+ freeScreen();
+ freeBackbuffer();
+ unloadTheme();
+ delete _parser;
+ delete _themeEval;
+ delete[] _cursor;
- void drawSelf(bool draw, bool restore);
+ for (ImagesMap::iterator i = _bitmaps.begin(); i != _bitmaps.end(); ++i)
+ ImageMan.unregisterSurface(i->_key);
+}
-protected:
- const Graphics::Surface *_bitmap;
- bool _alpha;
-};
+/**********************************************************
+ * Rendering mode management
+ *********************************************************/
const ThemeEngine::Renderer ThemeEngine::_rendererModes[] = {
{ "Disabled GFX", "none", kGfxDisabled },
{ "Standard Renderer (16bpp)", "normal_16bpp", kGfxStandard16bit },
@@ -179,149 +129,8 @@ const char *ThemeEngine::findModeConfigName(GraphicsMode mode) {
return findModeConfigName(kGfxDisabled);
}
-/**********************************************************
- * ThemeItem functions for drawing queues.
- *********************************************************/
-void ThemeItemDrawData::drawSelf(bool draw, bool restore) {
-
- Common::Rect extendedRect = _area;
- extendedRect.grow(_engine->kDirtyRectangleThreshold + _data->_backgroundOffset);
-
- if (restore)
- _engine->restoreBackground(extendedRect);
-
- if (draw) {
- Common::List<Graphics::DrawStep>::const_iterator step;
- for (step = _data->_steps.begin(); step != _data->_steps.end(); ++step)
- _engine->renderer()->drawStep(_area, *step, _dynamicData);
- }
-
- _engine->addDirtyRect(extendedRect);
-}
-
-void ThemeItemTextData::drawSelf(bool draw, bool restore) {
- if (_restoreBg || restore)
- _engine->restoreBackground(_area);
-
- if (draw) {
- _engine->renderer()->setFgColor(_data->_color.r, _data->_color.g, _data->_color.b);
- _engine->renderer()->drawString(_data->_fontPtr, _text, _area, _alignH, _alignV, _deltax, _ellipsis);
- }
-
- _engine->addDirtyRect(_area);
-}
-
-void ThemeItemBitmap::drawSelf(bool draw, bool restore) {
- if (restore)
- _engine->restoreBackground(_area);
-
- if (draw) {
- if (_alpha)
- _engine->renderer()->blitAlphaBitmap(_bitmap, _area);
- else
- _engine->renderer()->blitSubSurface(_bitmap, _area);
- }
-
- _engine->addDirtyRect(_area);
-}
-
-
-
-/**********************************************************
- * Data definitions for theme engine elements
- *********************************************************/
-const ThemeEngine::DrawDataInfo ThemeEngine::kDrawDataDefaults[] = {
- {kDDMainDialogBackground, "mainmenu_bg", true, kDDNone},
- {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},
- {kDDWidgetBackgroundEditText, "widget_textedit", true, kDDNone},
- {kDDWidgetBackgroundSlider, "widget_slider", true, kDDNone},
-
- {kDDButtonIdle, "button_idle", true, kDDWidgetBackgroundSlider},
- {kDDButtonHover, "button_hover", false, kDDButtonIdle},
- {kDDButtonDisabled, "button_disabled", true, kDDNone},
-
- {kDDSliderFull, "slider_full", false, kDDNone},
- {kDDSliderHover, "slider_hover", false, kDDNone},
- {kDDSliderDisabled, "slider_disabled", true, kDDNone},
-
- {kDDCheckboxDefault, "checkbox_default", true, kDDNone},
- {kDDCheckboxDisabled, "checkbox_disabled", true, kDDNone},
- {kDDCheckboxSelected, "checkbox_selected", false, kDDCheckboxDefault},
-
- {kDDTabActive, "tab_active", false, kDDTabInactive},
- {kDDTabInactive, "tab_inactive", true, kDDNone},
- {kDDTabBackground, "tab_background", true, kDDNone},
-
- {kDDScrollbarBase, "scrollbar_base", true, kDDNone},
-
- {kDDScrollbarButtonIdle, "scrollbar_button_idle", true, kDDNone},
- {kDDScrollbarButtonHover, "scrollbar_button_hover", false, kDDScrollbarButtonIdle},
-
- {kDDScrollbarHandleIdle, "scrollbar_handle_idle", false, kDDNone},
- {kDDScrollbarHandleHover, "scrollbar_handle_hover", false, kDDScrollbarBase},
-
- {kDDPopUpIdle, "popup_idle", true, kDDNone},
- {kDDPopUpHover, "popup_hover", false, kDDPopUpIdle},
-
- {kDDCaret, "caret", false, kDDNone},
- {kDDSeparator, "separator", true, kDDNone},
-};
-
-const ThemeEngine::TextDataInfo ThemeEngine::kTextDataDefaults[] = {
- {kTextDataDefault, "text_default"},
- {kTextDataHover, "text_hover"},
- {kTextDataDisabled, "text_disabled"},
- {kTextDataInverted, "text_inverted"},
- {kTextDataButton, "text_button"},
- {kTextDataButtonHover, "text_button_hover"},
- {kTextDataNormalFont, "text_normal"}
-};
-
-
-/**********************************************************
- * ThemeEngine class
- *********************************************************/
-ThemeEngine::ThemeEngine(Common::String fileName, GraphicsMode mode) :
- _system(0), _vectorRenderer(0), _screen(0), _backBuffer(0),
- _buffering(false), _bytesPerPixel(0), _graphicsMode(kGfxDisabled),
- _font(0), _initOk(false), _themeOk(false), _enabled(false), _cursor(0) {
- _system = g_system;
- _parser = new ThemeParser(this);
- _themeEval = new GUI::ThemeEval();
-
- _useCursor = false;
-
- for (int i = 0; i < kDrawDataMAX; ++i) {
- _widgets[i] = 0;
- }
-
- for (int i = 0; i < kTextDataMAX; ++i) {
- _texts[i] = 0;
- }
- _graphicsMode = mode;
- _themeFileName = fileName;
- _initOk = false;
-}
-
-ThemeEngine::~ThemeEngine() {
- freeRenderer();
- freeScreen();
- freeBackbuffer();
- unloadTheme();
- delete _parser;
- delete _themeEval;
- delete[] _cursor;
- for (ImagesMap::iterator i = _bitmaps.begin(); i != _bitmaps.end(); ++i)
- ImageMan.unregisterSurface(i->_key);
-}
/**********************************************************
@@ -515,6 +324,18 @@ void ThemeEngine::restoreBackground(Common::Rect r, bool special) {
_vectorRenderer->blitSurface(_backBuffer, r);
}
+bool ThemeEngine::isThemeLoadingRequired() {
+ int x = g_system->getOverlayWidth(), y = g_system->getOverlayHeight();
+
+ if (_loadedThemeX == x && _loadedThemeY == y)
+ return false;
+
+ _loadedThemeX = x;
+ _loadedThemeY = y;
+
+ return true;
+}
+
@@ -677,8 +498,7 @@ bool ThemeEngine::loadThemeXML(const Common::String &themeName) {
if (!node.exists() || !node.isReadable())
return false;
- // FIXME: Should this be initialized to something else than NULL?
- Common::Archive *archive = NULL;
+ Common::Archive *archive = 0;
if (node.getName().hasSuffix(".zip") && !node.isDirectory()) {
#ifdef USE_ZLIB
@@ -693,7 +513,9 @@ bool ThemeEngine::loadThemeXML(const Common::String &themeName) {
#endif
} else if (node.isDirectory()) {
- warning("Don't know how to open theme '%s'", themeName.c_str());
+
+// FIXME: This warning makes no sense whatsoever. Who added this?
+// warning("Don't know how to open theme '%s'", themeName.c_str());
archive = new Common::FSDirectory(node);
}
@@ -701,8 +523,6 @@ bool ThemeEngine::loadThemeXML(const Common::String &themeName) {
return false;
Common::File themercFile;
- // FIXME: Possibly dereferencing a NULL pointer here if the node's
- // name doesn't have a ".zip" suffix and the node is not a directory.
themercFile.open("THEMERC", *archive);
if (!themercFile.isOpen()) {
delete archive;
@@ -1215,6 +1035,11 @@ bool ThemeEngine::createCursor(const Common::String &filename, int hotspotX, int
return true;
}
+
+/**********************************************************
+ * Legacy GUI::Theme support functions
+ *********************************************************/
+
const Graphics::Font *ThemeEngine::getFont(FontStyle font) const {
return _texts[fontStyleToData(font)]->_fontPtr;
}
@@ -1236,4 +1061,148 @@ ThemeEngine::TextData ThemeEngine::getTextData(DrawData ddId) {
}
+
+/**********************************************************
+ * External data loading
+ *********************************************************/
+
+const Graphics::Font *ThemeEngine::loadFontFromArchive(const Common::String &filename) {
+ Common::Archive *arch = 0;
+ const Graphics::NewFont *font = 0;
+
+ if (getThemeFileName().hasSuffix(".zip")) {
+#ifdef USE_ZLIB
+ Common::ZipArchive *zip = new Common::ZipArchive(getThemeFileName());
+ if (!zip || !zip->isOpen())
+ return 0;
+
+ arch = zip;
+#else
+ return 0;
+#endif
+ } else {
+ Common::FSDirectory *dir = new Common::FSDirectory(getThemeFileName());
+ if (!dir || !dir->getFSNode().isDirectory())
+ return 0;
+
+ arch = dir;
+ }
+
+ Common::SeekableReadStream *stream(arch->openFile(filename));
+ if (stream) {
+ font = Graphics::NewFont::loadFromCache(*stream);
+ delete stream;
+ }
+
+ delete arch;
+ return font;
+}
+
+const Graphics::Font *ThemeEngine::loadFont(const Common::String &filename) {
+ const Graphics::Font *font = 0;
+ Common::String cacheFilename = genCacheFilename(filename.c_str());
+ Common::File fontFile;
+
+ if (!cacheFilename.empty()) {
+ if (fontFile.open(cacheFilename))
+ font = Graphics::NewFont::loadFromCache(fontFile);
+
+ if (font)
+ return font;
+
+ if ((font = loadFontFromArchive(cacheFilename)))
+ return font;
+ }
+
+ // normal open
+ if (fontFile.open(filename)) {
+ font = Graphics::NewFont::loadFont(fontFile);
+ }
+
+ if (!font) {
+ font = loadFontFromArchive(filename);
+ }
+
+ if (font) {
+ if (!cacheFilename.empty()) {
+ if (!Graphics::NewFont::cacheFontData(*(const Graphics::NewFont*)font, cacheFilename)) {
+ warning("Couldn't create cache file for font '%s'", filename.c_str());
+ }
+ }
+ }
+
+ return font;
+}
+
+Common::String ThemeEngine::genCacheFilename(const char *filename) {
+ Common::String cacheName(filename);
+ for (int i = cacheName.size() - 1; i >= 0; --i) {
+ if (cacheName[i] == '.') {
+ while ((uint)i < cacheName.size() - 1) {
+ cacheName.deleteLastChar();
+ }
+
+ cacheName += "fcc";
+ return cacheName;
+ }
+ }
+
+ return "";
+}
+
+
+/**********************************************************
+ * Static Theme XML functions
+ *********************************************************/
+
+bool ThemeEngine::themeConfigParseHeader(Common::String header, Common::String &themeName) {
+ header.trim();
+
+ if (header.empty())
+ return false;
+
+ if (header[0] != '[' || header.lastChar() != ']')
+ return false;
+
+ header.deleteChar(0);
+ header.deleteLastChar();
+
+ Common::StringTokenizer tok(header, ":");
+
+ if (tok.nextToken() != SCUMMVM_THEME_VERSION_STR)
+ return false;
+
+ themeName = tok.nextToken();
+ Common::String author = tok.nextToken();
+
+ return tok.empty();
+}
+
+bool ThemeEngine::themeConfigUseable(const Common::FSNode &node, Common::String &themeName) {
+ Common::File stream;
+ bool foundHeader = false;
+
+ if (node.getName().hasSuffix(".zip") && !node.isDirectory()) {
+#ifdef USE_ZLIB
+ Common::ZipArchive zipArchive(node);
+ if (zipArchive.hasFile("THEMERC")) {
+ stream.open("THEMERC", zipArchive);
+ }
+#endif
+ } else if (node.isDirectory()) {
+ Common::FSNode headerfile = node.getChild("THEMERC");
+ if (!headerfile.exists() || !headerfile.isReadable() || headerfile.isDirectory())
+ return false;
+ stream.open(headerfile);
+ }
+
+ if (stream.isOpen()) {
+ Common::String stxHeader = stream.readLine();
+ foundHeader = themeConfigParseHeader(stxHeader, themeName);
+ }
+
+ return foundHeader;
+}
+
+
} // end of namespace GUI.