From d385c34dd0c52ccc4c7fff50e88361dbb2cd588d Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 2 Jul 2008 18:11:41 +0000 Subject: InterfaceManager functionality translated into a Theme subclass "ThemeRenderer" to easen integration with the current GUI. svn-id: r32876 --- gui/InterfaceManager.cpp | 405 ----------------------------------------------- gui/InterfaceManager.h | 334 -------------------------------------- gui/ThemeDefaultXML.cpp | 4 +- gui/ThemeParser.cpp | 13 +- gui/ThemeParser.h | 8 +- gui/ThemeRenderer.cpp | 286 +++++++++++++++++++++++++++++++++ gui/ThemeRenderer.h | 297 ++++++++++++++++++++++++++++++++++ gui/object.h | 3 - gui/theme.h | 4 + 9 files changed, 600 insertions(+), 754 deletions(-) delete mode 100644 gui/InterfaceManager.cpp delete mode 100644 gui/InterfaceManager.h create mode 100644 gui/ThemeRenderer.cpp create mode 100644 gui/ThemeRenderer.h (limited to 'gui') diff --git a/gui/InterfaceManager.cpp b/gui/InterfaceManager.cpp deleted file mode 100644 index 80fa0d33db..0000000000 --- a/gui/InterfaceManager.cpp +++ /dev/null @@ -1,405 +0,0 @@ -/* 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/InterfaceManager.h" -#include "graphics/VectorRenderer.h" - -DECLARE_SINGLETON(GUI::InterfaceManager); - -namespace GUI { - -using namespace Graphics; - -const char *InterfaceManager::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" -}; - -InterfaceManager::InterfaceManager() : - _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 -void InterfaceManager::screenInit() { - freeScreen(); - - _screen = new Surface; - _screen->create(_system->getOverlayWidth(), _system->getOverlayHeight(), sizeof(PixelType)); - _system->clearOverlay(); -} - -void InterfaceManager::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(); - break; - - default: - return; - } - - freeRenderer(); - _vectorRenderer = createRenderer(mode); - _vectorRenderer->setSurface(_screen); -} - -void InterfaceManager::addDrawStep(Common::String &drawDataId, Graphics::DrawStep *step) { - DrawData id = getDrawDataId(drawDataId); - - assert(_widgets[id] != 0); - _widgets[id]->_steps.push_back(step); -} - -bool InterfaceManager::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 InterfaceManager::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 InterfaceManager::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(); -} - -void InterfaceManager::init() { - if (!_screen || _system->getOverlayWidth() != _screen->w || - _system->getOverlayHeight() != _screen->h ) - setGraphicsMode(_graphicsMode); - - if (needThemeReload()) - loadTheme(); - - _initOk = true; -} - -bool InterfaceManager::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 InterfaceManager::drawCached(DrawData type, const Common::Rect &r) { - assert(_widgets[type]->_surfaceCache->bytesPerPixel == _screen->bytesPerPixel); - _vectorRenderer->blitSurface(_widgets[type]->_surfaceCache, r); -} - -void InterfaceManager::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 InterfaceManager::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 InterfaceManager::drawLineSeparator(const Common::Rect &r, WidgetStateInfo state) { - if (!ready()) - return; - - drawDD(kDDSeparator, r); - addDirtyRect(r); -} - -void InterfaceManager::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 InterfaceManager::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 InterfaceManager::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState sb_state, WidgetStateInfo state) { - if (!ready()) - return; -} - -void InterfaceManager::redrawDialogStack() { - _vectorRenderer->clearSurface(); - - for (int i = 0; i < _dialogStack.size(); ++i) - _dialogStack[i]->draw(); -} - -void InterfaceManager::openDialog(Dialogs dname, Dialog *parent) { - Dialog *dlg = 0; - switch (dname) { - case kDialogLauncher: - dlg = new GUI::LauncherDialog; - break; - - default: - error("Unhandled dialog opening"); - break; - } - - if (dlg) - _dialogStack.push(dlg); -} - -int InterfaceManager::runGUI() { - init(); - - if (!ready()) - return 0; - - Common::EventManager *eventMan = _system->getEventManager(); - Dialog *activeDialog = getTopDialog(); - Dialog *lastDialog = 0; - - if (!activeDialog) - return 0; - - bool stackChange; - - int button; - uint32 time; - - _system->showOverlay(); - - while (activeDialog) { // draw!! - stackChange = (activeDialog != lastDialog); - lastDialog = activeDialog; - - if (stackChange || needRedraw()) - redrawDialogStack(); - - if (!_dirtyScreen.empty()) { - for (uint i = 0; i < _dirtyScreen.size(); ++i) - _vectorRenderer->copyFrame(_system, _dirtyScreen[i]); - _system->updateScreen(); - _dirtyScreen.clear(); - } - - Common::Event event; - - while (eventMan->pollEvent(event)) { - activeDialog->handleTickle(); - - Common::Point mouse(event.mouse.x - activeDialog->_x, event.mouse.y - activeDialog->_y); - - switch (event.type) { - case Common::EVENT_KEYDOWN: - activeDialog->handleKeyDown(event.kbd); - break; - - case Common::EVENT_KEYUP: - activeDialog->handleKeyUp(event.kbd); - break; - - case Common::EVENT_MOUSEMOVE: - activeDialog->handleMouseMoved(mouse.x, mouse.y, 0); - break; - - case Common::EVENT_LBUTTONDOWN: - case Common::EVENT_RBUTTONDOWN: - button = (event.type == Common::EVENT_LBUTTONDOWN ? 1 : 2); - time = _system->getMillis(); - if (_lastClick.count && (time < _lastClick.time + kDoubleClickDelay) - && ABS(_lastClick.x - event.mouse.x) < 3 - && ABS(_lastClick.y - event.mouse.y) < 3) { - _lastClick.count++; - } else { - _lastClick.x = event.mouse.x; - _lastClick.y = event.mouse.y; - _lastClick.count = 1; - } - _lastClick.time = time; - activeDialog->handleMouseDown(mouse.x, mouse.y, button, _lastClick.count); - break; - - case Common::EVENT_LBUTTONUP: - case Common::EVENT_RBUTTONUP: - button = (event.type == Common::EVENT_LBUTTONUP ? 1 : 2); - activeDialog->handleMouseUp(mouse.x, mouse.y, button, _lastClick.count); - break; - - case Common::EVENT_WHEELUP: - activeDialog->handleMouseWheel(mouse.x, mouse.y, -1); - break; - - case Common::EVENT_WHEELDOWN: - activeDialog->handleMouseWheel(mouse.x, mouse.y, 1); - break; - - case Common::EVENT_QUIT: - _system->quit(); - return 1; - - case Common::EVENT_SCREEN_CHANGED: - screenChange(); - break; - - default: - break; - } - } - - activeDialog = getTopDialog(); - _system->delayMillis(10); - } - - _system->hideOverlay(); - return 1; -} - - - -} // end of namespace GUI. diff --git a/gui/InterfaceManager.h b/gui/InterfaceManager.h deleted file mode 100644 index ac612e0c52..0000000000 --- a/gui/InterfaceManager.h +++ /dev/null @@ -1,334 +0,0 @@ -/* 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$ - * - */ - -#ifndef INTERFACE_MANAGER_H -#define INTERFACE_MANAGER_H - -#include "common/scummsys.h" -#include "graphics/surface.h" -#include "common/system.h" - -#include "graphics/surface.h" -#include "graphics/fontman.h" - -#include "gui/dialog.h" -#include "gui/ThemeParser.h" -#include "graphics/VectorRenderer.h" - -namespace GUI { - -struct WidgetDrawData; -class InterfaceManager; - -struct WidgetDrawData { - Common::Array _steps; - - bool _cached; - Graphics::Surface *_surfaceCache; - uint32 _cachedW, _cachedH; - - ~WidgetDrawData() { - for (uint i = 0; i < _steps.size(); ++i) - delete _steps[i]; - - _steps.clear(); - - if (_surfaceCache) { - _surfaceCache->free(); - delete _surfaceCache; - } - } -}; - -class InterfaceManager { - - typedef Common::String String; - typedef GUI::Dialog Dialog; - - friend class GUI::Dialog; - friend class GUI::GuiObject; - - static const char *kDrawDataStrings[]; - static const int kMaxDialogDepth = 4; - -public: - enum Graphics_Mode { - kGfxDisabled = 0, - kGfxStandard16bit, - kGfxAntialias16bit - }; - - enum Dialogs { - kDialogLauncher, - kDialogMAX - }; - - enum { - kDoubleClickDelay = 500, // milliseconds - kCursorAnimateDelay = 250 - }; - - enum DrawData { - kDDMainDialogBackground, - kDDSpecialColorBackground, - kDDPlainColorBackground, - kDDDefaulBackground, - - kDDButtonIdle, - kDDButtonHover, - - kDDSurface, - - kDDSliderFull, - kDDSliderEmpty, - - kDDCheckboxEnabled, - kDDCheckboxDisabled, - - kDDTab, - - kDDScrollbarBase, - kDDScrollbarButtonTop, - kDDScrollbarButtonBottom, - kDDScrollbarHandle, - - kDDPopUp, - kDDCaret, - kDDSeparator, - kDrawDataMAX - }; - - enum FontStyle { - kFontStyleBold = 0, //! A bold font. This is also the default font. - kFontStyleNormal = 1, //! A normal font. - kFontStyleItalic = 2, //! Italic styled font. - kFontStyleFixedNormal = 3, //! Fixed size font. - kFontStyleFixedBold = 4, //! Fixed size bold font. - kFontStyleFixedItalic = 5, //! Fixed size italic font. - kFontStyleMax - }; - - enum State { - kStateDisabled, //! Indicates that the widget is disabled, that does NOT include that it is invisible - kStateEnabled, //! Indicates that the widget is enabled - kStateHighlight //! Indicates that the widget is highlighted by the user - }; - - //! Widget background type - enum WidgetBackground { - kWidgetBackgroundNo, //! No background at all - kWidgetBackgroundPlain, //! Simple background, this may not include borders - kWidgetBackgroundBorder, //! Same as kWidgetBackgroundPlain just with a border - kWidgetBackgroundBorderSmall, //! Same as kWidgetBackgroundPlain just with a small border - kWidgetBackgroundEditText, //! Background used for edit text fields - kWidgetBackgroundSlider //! Background used for sliders - }; - - typedef State WidgetStateInfo; - - //! State of the scrollbar - enum ScrollbarState { - kScrollbarStateNo, - kScrollbarStateUp, - kScrollbarStateDown, - kScrollbarStateSlider, - kScrollbarStateSinglePage - }; - - //! Defined the align of the text - enum TextAlign { - kTextAlignLeft, //! Text should be aligned to the left - kTextAlignCenter, //! Text should be centered - kTextAlignRight //! Text should be aligned to the right - }; - - //! Function used to process areas other than the current dialog - enum ShadingStyle { - kShadingNone, //! No special post processing - kShadingDim, //! Dimming unused areas - kShadingLuminance //! Converting colors to luminance for unused areas - }; - - - InterfaceManager(); - - ~InterfaceManager() { - freeRenderer(); - freeScreen(); - unloadTheme(); - delete _parser; - - while (!_dialogStack.empty()) - delete _dialogStack.pop(); - } - - void setGraphicsMode(Graphics_Mode mode); - int runGUI(); - - void init(); - - /** Font management */ - const Graphics::Font *getFont(FontStyle font) const { return _font; } - int getFontHeight(FontStyle font = kFontStyleBold) const { if (_initOk) return _font->getFontHeight(); return 0; } - int getStringWidth(const Common::String &str, FontStyle font) const { if (_initOk) return _font->getStringWidth(str); return 0; } - int getCharWidth(byte c, FontStyle font) const { if (_initOk) return _font->getCharWidth(c); return 0; } - - /** Widget drawing */ - void drawWidgetBackground(const Common::Rect &r, uint16 hints, WidgetBackground background = kWidgetBackgroundPlain, WidgetStateInfo state = kStateEnabled) {} - void drawButton(const Common::Rect &r, const Common::String &str, WidgetStateInfo state = kStateEnabled, uint16 hints = 0); - void drawSurface(const Common::Rect &r, const Graphics::Surface &surface, WidgetStateInfo state = kStateEnabled, int alpha = 256, bool themeTrans = false) {} - void drawSlider(const Common::Rect &r, int width, WidgetStateInfo state = kStateEnabled); - void drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state = kStateEnabled); - void drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array &tabs, int active, uint16 hints, int titleVPad, WidgetStateInfo state = kStateEnabled) {} - void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState, WidgetStateInfo state = kStateEnabled); - void drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, WidgetStateInfo state = kStateEnabled, TextAlign align = kTextAlignLeft) {} - void drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo state = kStateEnabled) {} - void drawLineSeparator(const Common::Rect &r, WidgetStateInfo state = kStateEnabled); - - DrawData getDrawDataId(Common::String &name) { - for (int i = 0; i < kDrawDataMAX; ++i) - if (name.compareToIgnoreCase(kDrawDataStrings[i]) == 0) - return (DrawData)i; - - return (DrawData)-1; - } - - void addDrawStep(Common::String &drawDataId, Graphics::DrawStep *step); - bool addDrawData(DrawData data_id, bool cached); - - ThemeParser *parser() { - return _parser; - } - - bool ready() { - return _initOk && _themeOk; - } - - bool loadTheme() { - ConfMan.registerDefault("gui_theme", "default"); - Common::String style(ConfMan.get("gui_theme")); - - if (style.compareToIgnoreCase("default") == 0) - style = "modern"; - - return loadTheme(style); - } - - bool loadTheme(Common::String themeName); - void openDialog(Dialogs dname, Dialog *parent); - - void closeTopDialog() { - assert(_dialogStack.empty() == false); - delete _dialogStack.pop(); - } - -protected: - template void screenInit(); - - bool loadThemeXML(Common::String themeName); - bool loadDefaultXML(); - - void unloadTheme() { - if (!_themeOk) - return; - - for (int i = 0; i < kDrawDataMAX; ++i) { - delete _widgets[i]; - _widgets[i] = 0; - } - } - - void screenChange() {} - - void freeRenderer() { - delete _vectorRenderer; - _vectorRenderer = 0; - } - - void freeScreen() { - if (_screen != 0) { - _screen->free(); - delete _screen; - _screen = 0; - } - } - - Dialog *getTopDialog() const { - if (_dialogStack.empty()) - return 0; - return _dialogStack.top(); - } - - bool needThemeReload() { - return (_themeOk == false || _needThemeLoad == true); - } - - bool needRedraw() { - return true; - } - - void redrawDialogStack(); - - bool isWidgetCached(DrawData type, const Common::Rect &r); - void drawCached(DrawData type, const Common::Rect &r); - - inline void drawDD(DrawData type, const Common::Rect &r); - - void addDirtyRect(const Common::Rect &r) { - _dirtyScreen.push_back(r); - } - - OSystem *_system; - Graphics::VectorRenderer *_vectorRenderer; - GUI::ThemeParser *_parser; - - Graphics::Surface *_screen; - - int _bytesPerPixel; - Graphics_Mode _graphicsMode; - - Common::String _fontName; - const Graphics::Font *_font; - - WidgetDrawData *_widgets[kDrawDataMAX]; - Common::FixedStack _dialogStack; - Common::Array _dirtyScreen; - - bool _initOk; - bool _themeOk; - bool _caching; - bool _needThemeLoad; - bool _enabled; - - struct { - int16 x, y; // Position of mouse when the click occured - uint32 time; // Time - int count; // How often was it already pressed? - } _lastClick; -}; - -} // end of namespace GUI. - -#endif diff --git a/gui/ThemeDefaultXML.cpp b/gui/ThemeDefaultXML.cpp index cd571e680e..4b48e11991 100644 --- a/gui/ThemeDefaultXML.cpp +++ b/gui/ThemeDefaultXML.cpp @@ -24,11 +24,11 @@ */ #include "common/system.h" -#include "gui/InterfaceManager.h" +#include "gui/ThemeRenderer.h" namespace GUI { -bool InterfaceManager::loadDefaultXML() { +bool ThemeRenderer::loadDefaultXML() { const char *defaultXML = /** * Default theme description file. Work in progress. diff --git a/gui/ThemeParser.cpp b/gui/ThemeParser.cpp index 07789ebee3..eac8c20978 100644 --- a/gui/ThemeParser.cpp +++ b/gui/ThemeParser.cpp @@ -30,8 +30,9 @@ #include "common/hash-str.h" #include "common/xmlparser.h" -#include "gui/InterfaceManager.h" +#include "gui/ThemeRenderer.h" #include "gui/ThemeParser.h" +#include "gui/NewGui.h" #include "graphics/VectorRenderer.h" namespace GUI { @@ -39,7 +40,7 @@ namespace GUI { using namespace Graphics; using namespace Common; -ThemeParser::ThemeParser(InterfaceManager *parent) : XMLParser() { +ThemeParser::ThemeParser(ThemeRenderer *parent) : XMLParser() { _callbacks["drawstep"] = &ThemeParser::parserCallback_DRAWSTEP; _callbacks["drawdata"] = &ThemeParser::parserCallback_DRAWDATA; _callbacks["palette"] = &ThemeParser::parserCallback_palette; @@ -59,7 +60,7 @@ ThemeParser::ThemeParser(InterfaceManager *parent) : XMLParser() { _defaultStepGlobal = defaultDrawStep(); _defaultStepLocal = 0; - _GUI = parent; + _theme = parent; } bool ThemeParser::keyCallback(Common::String keyName) { @@ -213,7 +214,7 @@ bool ThemeParser::parserCallback_DRAWSTEP() { if (!parseDrawStep(stepNode, drawstep, true)) return false; - _GUI->addDrawStep(drawdataNode->values["id"], drawstep); + _theme->addDrawStep(drawdataNode->values["id"], drawstep); return true; } @@ -229,7 +230,7 @@ bool ThemeParser::parserCallback_DRAWDATA() { if (drawdataNode->values.contains("id") == false) return parserError("DrawData keys must contain an identifier."); - InterfaceManager::DrawData id = _GUI->getDrawDataId(drawdataNode->values["id"]); + ThemeRenderer::DrawData id = _theme->getDrawDataId(drawdataNode->values["id"]); if (id == -1) return parserError("%s is not a valid DrawData set identifier.", drawdataNode->values["id"].c_str()); @@ -252,7 +253,7 @@ bool ThemeParser::parserCallback_DRAWDATA() { } }*/ - if (_GUI->addDrawData(id, cached) == false) + if (_theme->addDrawData(id, cached) == false) return parserError("Repeated DrawData: Only one set of Drawing Data for a widget may be specified on each platform."); if (_defaultStepLocal) { diff --git a/gui/ThemeParser.h b/gui/ThemeParser.h index 68e8272b80..56d45eb802 100644 --- a/gui/ThemeParser.h +++ b/gui/ThemeParser.h @@ -36,7 +36,7 @@ #include "common/xmlparser.h" #include "graphics/VectorRenderer.h" -#include "gui/InterfaceManager.h" +#include "gui/ThemeRenderer.h" /** ********************************************* @@ -308,7 +308,7 @@ namespace GUI { using namespace Graphics; using namespace Common; -class InterfaceManager; +class ThemeRenderer; class ThemeParser : public XMLParser { typedef void (VectorRenderer::*DrawingFunctionCallback)(const Common::Rect &, const DrawStep &); @@ -316,10 +316,10 @@ class ThemeParser : public XMLParser { typedef GUI::InterfaceManager InterfaceManager; public: - ThemeParser(InterfaceManager *parent); + ThemeParser(GUI::ThemeRenderer *parent); protected: - InterfaceManager *_GUI; + ThemeRenderer *_theme; bool keyCallback(Common::String keyName); bool parserCallback_DRAWSTEP(); 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 +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(); + 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. diff --git a/gui/ThemeRenderer.h b/gui/ThemeRenderer.h new file mode 100644 index 0000000000..e9904d8ae3 --- /dev/null +++ b/gui/ThemeRenderer.h @@ -0,0 +1,297 @@ +/* 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$ + * + */ + +#ifndef INTERFACE_MANAGER_H +#define INTERFACE_MANAGER_H + +#include "common/scummsys.h" +#include "graphics/surface.h" +#include "common/system.h" + +#include "graphics/surface.h" +#include "graphics/fontman.h" + +#include "gui/dialog.h" +#include "gui/ThemeParser.h" +#include "graphics/VectorRenderer.h" + +namespace GUI { + +struct WidgetDrawData; +class InterfaceManager; + +struct WidgetDrawData { + Common::Array _steps; + + bool _cached; + Graphics::Surface *_surfaceCache; + uint32 _cachedW, _cachedH; + + ~WidgetDrawData() { + for (uint i = 0; i < _steps.size(); ++i) + delete _steps[i]; + + _steps.clear(); + + if (_surfaceCache) { + _surfaceCache->free(); + delete _surfaceCache; + } + } +}; + +class ThemeRenderer : public Theme { + + typedef Common::String String; + typedef GUI::Dialog Dialog; + + friend class GUI::Dialog; + friend class GUI::GuiObject; + + static const char *kDrawDataStrings[]; + static const int kMaxDialogDepth = 4; + +public: + enum Graphics_Mode { + kGfxDisabled = 0, + kGfxStandard16bit, + kGfxAntialias16bit + }; + + enum DrawData { + kDDMainDialogBackground, + kDDSpecialColorBackground, + kDDPlainColorBackground, + kDDDefaulBackground, + + kDDButtonIdle, + kDDButtonHover, + + kDDSurface, + + kDDSliderFull, + kDDSliderEmpty, + + kDDCheckboxEnabled, + kDDCheckboxDisabled, + + kDDTab, + + kDDScrollbarBase, + kDDScrollbarButtonTop, + kDDScrollbarButtonBottom, + kDDScrollbarHandle, + + kDDPopUp, + kDDCaret, + kDDSeparator, + kDrawDataMAX + }; + + ThemeRenderer(); + + ~ThemeRenderer() { + freeRenderer(); + freeScreen(); + unloadTheme(); + delete _parser; + + while (!_dialogStack.empty()) + delete _dialogStack.pop(); + } + + // virtual methods from Theme + bool init(); + void deinit() {} + void refresh() {} + void enable() {} + void disable() {} + void openDialog() {} + void closeAllDialogs() {} + void clearAll() {} + void updateScreen() {} + void resetDrawArea() {} + void openDialog(bool top) {} + + virtual bool isDynamic() { + return true; + } + + /** Font management */ + const Graphics::Font *getFont(FontStyle font) const { return _font; } + int getFontHeight(FontStyle font = kFontStyleBold) const { if (_initOk) return _font->getFontHeight(); return 0; } + int getStringWidth(const Common::String &str, FontStyle font) const { if (_initOk) return _font->getStringWidth(str); return 0; } + int getCharWidth(byte c, FontStyle font) const { if (_initOk) return _font->getCharWidth(c); return 0; } + + /** Widget drawing */ + void drawWidgetBackground(const Common::Rect &r, uint16 hints, WidgetBackground background = kWidgetBackgroundPlain, WidgetStateInfo state = kStateEnabled) {} + void drawButton(const Common::Rect &r, const Common::String &str, WidgetStateInfo state = kStateEnabled, uint16 hints = 0); + void drawSurface(const Common::Rect &r, const Graphics::Surface &surface, WidgetStateInfo state = kStateEnabled, int alpha = 256, bool themeTrans = false) {} + void drawSlider(const Common::Rect &r, int width, WidgetStateInfo state = kStateEnabled); + void drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state = kStateEnabled); + void drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array &tabs, int active, uint16 hints, int titleVPad, WidgetStateInfo state = kStateEnabled) {} + void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState, WidgetStateInfo state = kStateEnabled); + void drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, WidgetStateInfo state = kStateEnabled, TextAlign align = kTextAlignLeft) {} + void drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo state = kStateEnabled) {} + void drawLineSeparator(const Common::Rect &r, WidgetStateInfo state = kStateEnabled); + + void drawDialogBackground(const Common::Rect &r, uint16 hints, WidgetStateInfo state) {} + void drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, TextAlign align, bool inverted, int deltax, bool useEllipsis, FontStyle font) {} + void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state) {} + + bool addDirtyRect(Common::Rect r, bool backup = false, bool special = false) { + _dirtyScreen.push_back(r); + return true; + } + + // custom stuff - tanoku + DrawData getDrawDataId(Common::String &name) { + for (int i = 0; i < kDrawDataMAX; ++i) + if (name.compareToIgnoreCase(kDrawDataStrings[i]) == 0) + return (DrawData)i; + + return (DrawData)-1; + } + + void addDrawStep(Common::String &drawDataId, Graphics::DrawStep *step); + bool addDrawData(DrawData data_id, bool cached); + + ThemeParser *parser() { + return _parser; + } + + bool ready() { + return _initOk && _themeOk; + } + + bool loadTheme() { + ConfMan.registerDefault("gui_theme", "default"); + Common::String style(ConfMan.get("gui_theme")); + + if (style.compareToIgnoreCase("default") == 0) + style = "modern"; + + return loadTheme(style); + } + + bool loadTheme(Common::String themeName); + + void closeTopDialog() { + assert(_dialogStack.empty() == false); + delete _dialogStack.pop(); + } + + void setGraphicsMode(Graphics_Mode mode); + +protected: + template void screenInit(); + + bool loadThemeXML(Common::String themeName); + bool loadDefaultXML(); + + void unloadTheme() { + if (!_themeOk) + return; + + for (int i = 0; i < kDrawDataMAX; ++i) { + delete _widgets[i]; + _widgets[i] = 0; + } + } + + void screenChange() {} + void renderDirtyScreen(); + + void freeRenderer() { + delete _vectorRenderer; + _vectorRenderer = 0; + } + + void freeScreen() { + if (_screen != 0) { + _screen->free(); + delete _screen; + _screen = 0; + } + } + + Dialog *getTopDialog() const { + if (_dialogStack.empty()) + return 0; + return _dialogStack.top(); + } + + bool needThemeReload() { + return (_themeOk == false || _needThemeLoad == true); + } + + bool needRedraw() { + return true; + } + + void redrawDialogStack(); + + bool isWidgetCached(DrawData type, const Common::Rect &r); + void drawCached(DrawData type, const Common::Rect &r); + + inline void drawDD(DrawData type, const Common::Rect &r); + + // TODO + void restoreBackground(Common::Rect r, bool special = false) {} + + int getTabSpacing() const { + return 0; + } + + int getTabPadding() const { + return 3; + } + + OSystem *_system; + Graphics::VectorRenderer *_vectorRenderer; + GUI::ThemeParser *_parser; + + Graphics::Surface *_screen; + + int _bytesPerPixel; + Graphics_Mode _graphicsMode; + + Common::String _fontName; + const Graphics::Font *_font; + + WidgetDrawData *_widgets[kDrawDataMAX]; + Common::FixedStack _dialogStack; + Common::Array _dirtyScreen; + + bool _initOk; + bool _themeOk; + bool _caching; + bool _needThemeLoad; + bool _enabled; +}; + +} // end of namespace GUI. + +#endif diff --git a/gui/object.h b/gui/object.h index 2bdff3f76c..01046bd668 100644 --- a/gui/object.h +++ b/gui/object.h @@ -29,7 +29,6 @@ namespace GUI { class CommandReceiver; class CommandSender; -class InterfaceManager; class CommandReceiver { friend class CommandSender; @@ -66,7 +65,6 @@ protected: Common::String _name; Widget *_firstWidget; - InterfaceManager *_GUI; public: GuiObject(int x, int y, int w, int h) : _x(x), _y(y), _w(w), _h(h), _name(""), _firstWidget(0) { } @@ -85,7 +83,6 @@ public: virtual void draw() = 0; virtual void reflowLayout(); - virtual void setInterfaceManager(InterfaceManager *manager) { _GUI = manager; } protected: virtual void releaseFocus() = 0; diff --git a/gui/theme.h b/gui/theme.h index 4f61609fbd..320d2544e0 100644 --- a/gui/theme.h +++ b/gui/theme.h @@ -348,6 +348,10 @@ public: const Common::String &getStylefileName() const { return _stylefile; } const Common::String &getThemeName() const { return _stylename; } + virtual bool isDynamic() { + return false; + } + /** * Checks if the theme renderer supports drawing of images. * -- cgit v1.2.3