aboutsummaryrefslogtreecommitdiff
path: root/gui/ThemeRenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gui/ThemeRenderer.cpp')
-rw-r--r--gui/ThemeRenderer.cpp286
1 files changed, 286 insertions, 0 deletions
diff --git a/gui/ThemeRenderer.cpp b/gui/ThemeRenderer.cpp
new file mode 100644
index 0000000000..283860341b
--- /dev/null
+++ b/gui/ThemeRenderer.cpp
@@ -0,0 +1,286 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/util.h"
+#include "graphics/surface.h"
+#include "graphics/colormasks.h"
+#include "common/system.h"
+#include "common/events.h"
+#include "common/config-manager.h"
+
+#include "gui/launcher.h"
+
+#include "gui/ThemeRenderer.h"
+#include "graphics/VectorRenderer.h"
+
+namespace GUI {
+
+using namespace Graphics;
+
+const char *ThemeRenderer::kDrawDataStrings[] = {
+ "mainmenu_bg",
+ "special_bg",
+ "plain_bg",
+ "default_bg",
+
+ "button_idle",
+ "button_hover",
+
+ "surface",
+
+ "slider_full",
+ "slider_empty",
+
+ "checkbox_enabled",
+ "checkbox_disabled",
+
+ "tab",
+
+ "scrollbar_base",
+ "scrollbar_top",
+ "scrollbar_bottom",
+ "scrollbar_handle",
+
+ "popup",
+ "caret",
+ "separator"
+};
+
+ThemeRenderer::ThemeRenderer() :
+ _vectorRenderer(0), _system(0), _graphicsMode(kGfxDisabled),
+ _screen(0), _bytesPerPixel(0), _initOk(false), _themeOk(false),
+ _needThemeLoad(false), _enabled(false) {
+ _system = g_system;
+ _parser = new ThemeParser(this);
+
+ for (int i = 0; i < kDrawDataMAX; ++i) {
+ _widgets[i] = 0;
+ }
+
+ _graphicsMode = kGfxAntialias16bit; // default GFX mode
+ // TODO: load this from a config file
+}
+
+template<typename PixelType>
+void ThemeRenderer::screenInit() {
+ freeScreen();
+
+ _screen = new Surface;
+ _screen->create(_system->getOverlayWidth(), _system->getOverlayHeight(), sizeof(PixelType));
+ _system->clearOverlay();
+}
+
+void ThemeRenderer::setGraphicsMode(Graphics_Mode mode) {
+
+ // FIXME: reload theme everytime we change resolution...
+ // what if we change the renderer too?
+ // ...We may need to reload it to re-cache the widget
+ // surfaces
+ if (_system->getOverlayWidth() != _screen->w ||
+ _system->getOverlayHeight() != _screen->h)
+ _needThemeLoad = true;
+
+ switch (mode) {
+ case kGfxStandard16bit:
+ case kGfxAntialias16bit:
+ _bytesPerPixel = sizeof(uint16);
+ screenInit<uint16>();
+ break;
+
+ default:
+ return;
+ }
+
+ freeRenderer();
+ _vectorRenderer = createRenderer(mode);
+ _vectorRenderer->setSurface(_screen);
+}
+
+void ThemeRenderer::addDrawStep(Common::String &drawDataId, Graphics::DrawStep *step) {
+ DrawData id = getDrawDataId(drawDataId);
+
+ assert(_widgets[id] != 0);
+ _widgets[id]->_steps.push_back(step);
+}
+
+bool ThemeRenderer::addDrawData(DrawData data_id, bool cached) {
+ assert(data_id >= 0 && data_id < kDrawDataMAX);
+
+ if (_widgets[data_id] != 0)
+ return false;
+
+ _widgets[data_id] = new WidgetDrawData;
+ _widgets[data_id]->_cached = cached;
+
+ return true;
+}
+
+bool ThemeRenderer::loadTheme(Common::String themeName) {
+ unloadTheme();
+
+ if (!loadThemeXML(themeName)) {
+ warning("Could not parse custom theme '%s'.\nFalling back to default theme", themeName.c_str());
+
+ if (!loadDefaultXML()) // if we can't load the embeded theme, this is a complete failure
+ error("Could not load default embeded theme");
+ }
+
+ for (int i = 0; i < kDrawDataMAX; ++i) {
+ if (_widgets[i] == 0) {
+#ifdef REQUIRE_ALL_DD_SETS
+ warning("Error when parsing custom theme '%s': Missing data assets.", themeName.c_str());
+ return false;
+#endif
+ } else if (_widgets[i]->_cached) {
+ // draw the cached widget to the cache surface
+ }
+ }
+
+ _needThemeLoad = false;
+ _themeOk = true;
+ return true;
+}
+
+bool ThemeRenderer::loadThemeXML(Common::String themeName) {
+ assert(_parser);
+
+ if (ConfMan.hasKey("themepath"))
+ Common::File::addDefaultDirectory(ConfMan.get("themepath"));
+
+#ifdef DATA_PATH
+ Common::File::addDefaultDirectoryRecursive(DATA_PATH);
+#endif
+
+ if (ConfMan.hasKey("extrapath"))
+ Common::File::addDefaultDirectoryRecursive(ConfMan.get("extrapath"));
+
+ if (!parser()->loadFile(themeName + ".xml"))
+ return false;
+
+ return parser()->parse();
+}
+
+bool ThemeRenderer::init() {
+ if (!_screen || _system->getOverlayWidth() != _screen->w ||
+ _system->getOverlayHeight() != _screen->h )
+ setGraphicsMode(_graphicsMode);
+
+ if (needThemeReload())
+ loadTheme();
+
+ _initOk = true;
+ return true;
+}
+
+bool ThemeRenderer::isWidgetCached(DrawData type, const Common::Rect &r) {
+ return _widgets[type] && _widgets[type]->_cached &&
+ _widgets[type]->_surfaceCache->w == r.width() &&
+ _widgets[type]->_surfaceCache->h == r.height();
+}
+
+void ThemeRenderer::drawCached(DrawData type, const Common::Rect &r) {
+ assert(_widgets[type]->_surfaceCache->bytesPerPixel == _screen->bytesPerPixel);
+ _vectorRenderer->blitSurface(_widgets[type]->_surfaceCache, r);
+}
+
+void ThemeRenderer::drawDD(DrawData type, const Common::Rect &r) {
+ if (isWidgetCached(type, r)) {
+ drawCached(type, r);
+ } else {
+ for (uint i = 0; i < _widgets[type]->_steps.size(); ++i)
+ _vectorRenderer->drawStep(r, *_widgets[type]->_steps[i]);
+ }
+}
+
+void ThemeRenderer::drawButton(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, uint16 hints) {
+ if (!ready())
+ return;
+
+ if (state == kStateEnabled)
+ drawDD(kDDButtonIdle, r);
+ else if (state == kStateHighlight)
+ drawDD(kDDButtonHover, r);
+
+ // TODO: Add text drawing.
+
+ addDirtyRect(r);
+}
+
+void ThemeRenderer::drawLineSeparator(const Common::Rect &r, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ drawDD(kDDSeparator, r);
+ addDirtyRect(r);
+}
+
+void ThemeRenderer::drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ drawDD(checked ? kDDCheckboxEnabled : kDDCheckboxDisabled, r);
+
+ Common::Rect r2 = r;
+ r2.left += 16; // TODO: add variable for checkbox text offset.
+
+ // TODO: text drawing
+// getFont()->drawString(&_screen, str, r2.left, r2.top, r2.width(), getColor(state), Graphics::kTextAlignLeft, 0, false);
+
+ addDirtyRect(r);
+}
+
+void ThemeRenderer::drawSlider(const Common::Rect &r, int width, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ drawDD(kDDSliderEmpty, r);
+
+ Common::Rect r2 = r;
+ r2.setWidth(MIN((int16)width, r.width()));
+
+ drawDD(kDDSliderFull, r2);
+
+ addDirtyRect(r);
+}
+
+void ThemeRenderer::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState sb_state, WidgetStateInfo state) {
+ if (!ready())
+ return;
+}
+
+void ThemeRenderer::renderDirtyScreen() {
+ // TODO: This isn't really optimized. Check dirty squares for collisions
+ // and all that.
+ if (_dirtyScreen.empty())
+ return;
+
+ for (uint i = 0; i < _dirtyScreen.size(); ++i)
+ _vectorRenderer->copyFrame(_system, _dirtyScreen[i]);
+
+ _system->updateScreen();
+ _dirtyScreen.clear();
+}
+
+} // end of namespace GUI.