aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/module.mk1
-rw-r--r--common/rect.h10
-rw-r--r--common/xmlparser.cpp339
-rw-r--r--common/xmlparser.h487
-rw-r--r--dists/msvc9/scummvm.vcproj75
-rw-r--r--engines/dialogs.cpp57
-rw-r--r--engines/parallaction/saveload.cpp14
-rw-r--r--engines/scumm/dialogs.cpp135
-rw-r--r--graphics/VectorRenderer.cpp159
-rw-r--r--graphics/VectorRenderer.h557
-rw-r--r--graphics/VectorRendererSpec.cpp1591
-rw-r--r--graphics/VectorRendererSpec.h296
-rw-r--r--graphics/font.cpp49
-rw-r--r--graphics/module.mk4
-rw-r--r--gui/EditTextWidget.cpp12
-rw-r--r--gui/ListWidget.cpp52
-rw-r--r--gui/PopUpWidget.cpp14
-rw-r--r--gui/TabWidget.cpp37
-rw-r--r--gui/TabWidget.h5
-rw-r--r--gui/ThemeClassic.cpp710
-rw-r--r--gui/ThemeClassic.h127
-rw-r--r--gui/ThemeEngine.cpp1070
-rw-r--r--gui/ThemeEngine.h747
-rw-r--r--gui/ThemeEval.cpp179
-rw-r--r--gui/ThemeEval.h115
-rw-r--r--gui/ThemeLayout.cpp227
-rw-r--r--gui/ThemeLayout.h239
-rw-r--r--gui/ThemeModern.cpp1596
-rw-r--r--gui/ThemeModern.h341
-rw-r--r--gui/ThemeParser.cpp793
-rw-r--r--gui/ThemeParser.h278
-rw-r--r--gui/about.cpp21
-rw-r--r--gui/browser.cpp16
-rw-r--r--gui/console.cpp24
-rw-r--r--gui/dialog.cpp27
-rw-r--r--gui/dialog.h11
-rw-r--r--gui/launcher.cpp161
-rw-r--r--gui/module.mk8
-rw-r--r--gui/newgui.cpp173
-rw-r--r--gui/newgui.h19
-rw-r--r--gui/options.cpp89
-rw-r--r--gui/options.h7
-rw-r--r--gui/theme.cpp144
-rw-r--r--gui/theme.h126
-rw-r--r--gui/themebrowser.cpp87
-rw-r--r--gui/themebrowser.h3
-rw-r--r--gui/themes/classic080.ini469
-rw-r--r--gui/themes/default.inc1462
-rw-r--r--gui/themes/modern.ini649
-rw-r--r--gui/themes/modern.zipbin54022 -> 0 bytes
-rw-r--r--gui/themes/scummclassic.zipbin0 -> 43805 bytes
-rw-r--r--gui/themes/scummclassic/THEMERC1
-rw-r--r--gui/themes/scummclassic/classic_gfx.stx364
-rw-r--r--gui/themes/scummclassic/classic_layout.stx635
-rw-r--r--gui/themes/scummclassic/classic_layout_320.stx628
-rw-r--r--gui/themes/scummodern.zipbin0 -> 144239 bytes
-rw-r--r--gui/themes/scummodern/THEMERC1
-rw-r--r--gui/themes/scummodern/checkbox.bmpbin0 -> 774 bytes
-rw-r--r--gui/themes/scummodern/cursor.bmpbin0 -> 3126 bytes
-rw-r--r--gui/themes/scummodern/cursor_small.bmpbin0 -> 1062 bytes
-rw-r--r--gui/themes/scummodern/helvr12-l1.fccbin0 -> 5615 bytes
-rw-r--r--gui/themes/scummodern/logo.bmpbin0 -> 68214 bytes
-rw-r--r--gui/themes/scummodern/logo_small.bmpbin0 -> 17174 bytes
-rw-r--r--gui/themes/scummodern/scummodern_gfx.stx489
-rw-r--r--gui/themes/scummodern/scummodern_layout.stx647
-rw-r--r--gui/themes/scummodern/scummodern_layout_320.stx625
-rw-r--r--gui/themes/scummtheme.py91
-rw-r--r--gui/widget.cpp37
-rw-r--r--gui/widget.h5
69 files changed, 12726 insertions, 4609 deletions
diff --git a/common/module.mk b/common/module.mk
index 599ffcf8a6..e04af5270b 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -17,6 +17,7 @@ MODULE_OBJS := \
system.o \
unarj.o \
unzip.o \
+ xmlparser.o \
zlib.o
# Include common rules
diff --git a/common/rect.h b/common/rect.h
index dcf1c8b421..962069bf48 100644
--- a/common/rect.h
+++ b/common/rect.h
@@ -124,6 +124,16 @@ struct Rect {
return contains(p.x, p.y);
}
+ /*! @brief check if the given rect is _fully_ contained inside this rectangle
+
+ @param r The rectangle to check
+
+ @retur true if the given rect is inside, false otherwise
+ */
+ bool contains(const Rect &r) const {
+ return (left < r.left) && (right > r.right) && (top < r.top) && (bottom > r.bottom);
+ }
+
/*! @brief check if given rectangle intersects with this rectangle
@param r the rectangle to check
diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp
new file mode 100644
index 0000000000..44274f7c8d
--- /dev/null
+++ b/common/xmlparser.cpp
@@ -0,0 +1,339 @@
+/* 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 "common/system.h"
+#include "common/events.h"
+#include "common/hashmap.h"
+#include "common/hash-str.h"
+#include "common/xmlparser.h"
+
+namespace Common {
+
+using namespace Graphics;
+
+bool XMLParser::parserError(const char *errorString, ...) {
+ _state = kParserError;
+
+ int original_pos = _stream->pos();
+ int pos = original_pos;
+ int lineCount = 1;
+ int lineStart = 0;
+
+ if (_fileName == "Memory Stream") {
+ lineStart = MAX(0, original_pos - 35);
+ lineCount = 0;
+ } else {
+ do {
+ if (_char == '\n' || _char == '\r') {
+ lineCount++;
+
+ if (lineStart == 0)
+ lineStart = MAX(pos + 1, original_pos - 60);
+ }
+
+ _stream->seek(-1, SEEK_CUR);
+
+ } while (_stream->pos() > 0);
+ }
+
+ char lineStr[70];
+ _stream->seek(original_pos - 35, SEEK_SET);
+ _stream->readLine_NEW(lineStr, 70);
+
+ for (int i = 0; i < 70; ++i)
+ if (lineStr[i] == '\n')
+ lineStr[i] = ' ';
+
+ printf("\n File <%s>, line %d:\n", _fileName.c_str(), lineCount);
+
+ bool startFull = lineStr[0] == '<';
+ bool endFull = lineStr[strlen(lineStr) - 1] == '>';
+
+ printf("%s%s%s\n", startFull ? "" : "...", lineStr, endFull ? "" : "...");
+
+ int cursor = 35;
+
+ if (!startFull)
+ cursor += 3;
+
+ while (cursor--)
+ printf(" ");
+
+ printf("^\n");
+ printf("Parser error: ");
+
+ va_list args;
+ va_start(args, errorString);
+ vprintf(errorString, args);
+ va_end(args);
+
+ printf("\n\n");
+
+ return false;
+}
+
+bool XMLParser::parseActiveKey(bool closed) {
+ bool ignore = false;
+ assert(_activeKey.empty() == false);
+
+ ParserNode *key = _activeKey.top();
+ XMLKeyLayout *layout = (_activeKey.size() == 1) ? _XMLkeys : getParentNode(key)->layout;
+
+ if (layout->children.contains(key->name)) {
+ key->layout = layout->children[key->name];
+
+ Common::StringMap localMap = key->values;
+ int keyCount = localMap.size();
+
+ for (Common::List<XMLKeyLayout::XMLKeyProperty>::const_iterator i = key->layout->properties.begin(); i != key->layout->properties.end(); ++i) {
+ if (i->required && !localMap.contains(i->name))
+ return parserError("Missing required property '%s' inside key '%s'", i->name.c_str(), key->name.c_str());
+ else if (localMap.contains(i->name))
+ keyCount--;
+ }
+
+ if (keyCount > 0)
+ return parserError("Unhandled property inside key '%s': '%s'", key->name.c_str(), localMap.begin()->_key.c_str());
+
+ } else {
+ return parserError("Unexpected key in the active scope: '%s'.", key->name.c_str());
+ }
+
+ // check if any of the parents must be ignored.
+ // if a parent is ignored, all children are too.
+ for (int i = _activeKey.size() - 1; i >= 0; --i) {
+ if (_activeKey[i]->ignore)
+ ignore = true;
+ }
+
+ if (ignore == false && keyCallback(key) == false) {
+ // HACK: People may be stupid and overlook the fact that
+ // when keyCallback() fails, a parserError() must be set.
+ // We set it manually in that case.
+ if (_state != kParserError)
+ parserError("Unhandled exception when parsing '%s' key.", key->name.c_str());
+
+ return false;
+ }
+
+ if (closed)
+ return closeKey();
+
+ return true;
+}
+
+bool XMLParser::parseKeyValue(Common::String keyName) {
+ assert(_activeKey.empty() == false);
+
+ if (_activeKey.top()->values.contains(keyName))
+ return false;
+
+ _token.clear();
+ char stringStart;
+
+ if (_char == '"' || _char == '\'') {
+ stringStart = _char;
+ _char = _stream->readByte();
+
+ while (_char && _char != stringStart) {
+ _token += _char;
+ _char = _stream->readByte();
+ }
+
+ if (_char == 0)
+ return false;
+
+ _char = _stream->readByte();
+
+ } else if (!parseToken()) {
+ return false;
+ }
+
+ _activeKey.top()->values[keyName] = _token;
+ return true;
+}
+
+bool XMLParser::closeKey() {
+ bool ignore = false;
+ bool result = true;
+
+ for (int i = _activeKey.size() - 1; i >= 0; --i) {
+ if (_activeKey[i]->ignore)
+ ignore = true;
+ }
+
+ if (ignore == false)
+ result = closedKeyCallback(_activeKey.top());
+
+ freeNode(_activeKey.pop());
+
+ return result;
+}
+
+bool XMLParser::parse() {
+
+ if (_stream == 0)
+ return parserError("XML stream not ready for reading.");
+
+ if (_XMLkeys == 0)
+ buildLayout();
+
+ while (!_activeKey.empty())
+ freeNode(_activeKey.pop());
+
+ cleanup();
+
+ bool activeClosure = false;
+ bool selfClosure = false;
+
+ _state = kParserNeedKey;
+ _activeKey.clear();
+
+ _char = _stream->readByte();
+
+ while (_char && _state != kParserError) {
+ if (skipSpaces())
+ continue;
+
+ if (skipComments())
+ continue;
+
+ switch (_state) {
+ case kParserNeedKey:
+ if (_char != '<') {
+ parserError("Parser expecting key start.");
+ break;
+ }
+
+ if ((_char = _stream->readByte()) == 0) {
+ parserError("Unexpected end of file.");
+ break;
+ }
+
+ if (_char == '/') { // FIXME: What if it's a comment start
+ _char = _stream->readByte();
+ activeClosure = true;
+ }
+
+ _state = kParserNeedKeyName;
+ break;
+
+ case kParserNeedKeyName:
+ if (!parseToken()) {
+ parserError("Invalid key name.");
+ break;
+ }
+
+ if (activeClosure) {
+ if (_activeKey.empty() || _token != _activeKey.top()->name) {
+ parserError("Unexpected closure.");
+ break;
+ }
+ } else {
+ ParserNode *node = allocNode(); //new ParserNode;
+ node->name = _token;
+ node->ignore = false;
+ node->depth = _activeKey.size();
+ node->layout = 0;
+ _activeKey.push(node);
+ }
+
+ _state = kParserNeedPropertyName;
+ break;
+
+ case kParserNeedPropertyName:
+ if (activeClosure) {
+ if (!closeKey()) {
+ parserError("Missing data when closing key '%s'.", _activeKey.top()->name.c_str());
+ break;
+ }
+
+ activeClosure = false;
+
+ if (_char != '>')
+ parserError("Invalid syntax in key closure.");
+ else
+ _state = kParserNeedKey;
+
+ _char = _stream->readByte();
+ break;
+ }
+
+ selfClosure = false;
+
+ if (_char == '/') { // FIXME: comment start?
+ selfClosure = true;
+ _char = _stream->readByte();
+ }
+
+ if (_char == '>') {
+ if (parseActiveKey(selfClosure)) {
+ _char = _stream->readByte();
+ _state = kParserNeedKey;
+ }
+ break;
+ }
+
+ if (!parseToken())
+ parserError("Error when parsing key value.");
+ else
+ _state = kParserNeedPropertyOperator;
+
+ break;
+
+ case kParserNeedPropertyOperator:
+ if (_char != '=')
+ parserError("Syntax error after key name.");
+ else
+ _state = kParserNeedPropertyValue;
+
+ _char = _stream->readByte();
+ break;
+
+ case kParserNeedPropertyValue:
+ if (!parseKeyValue(_token))
+ parserError("Invalid key value.");
+ else
+ _state = kParserNeedPropertyName;
+
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (_state == kParserError)
+ return false;
+
+ if (_state != kParserNeedKey || !_activeKey.empty())
+ return parserError("Unexpected end of file.");
+
+ return true;
+}
+
+}
+
diff --git a/common/xmlparser.h b/common/xmlparser.h
new file mode 100644
index 0000000000..5f649f517f
--- /dev/null
+++ b/common/xmlparser.h
@@ -0,0 +1,487 @@
+/* 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 XML_PARSER_H
+#define XML_PARSER_H
+
+#include "common/scummsys.h"
+#include "graphics/surface.h"
+#include "common/system.h"
+#include "common/xmlparser.h"
+#include "common/stream.h"
+#include "common/file.h"
+#include "common/fs.h"
+
+#include "common/hashmap.h"
+#include "common/hash-str.h"
+#include "common/stack.h"
+
+namespace Common {
+
+/*
+ XMLParser.cpp/h -- Generic XML Parser
+ =====================================
+
+ External documentation available at:
+ http://www.smartlikearoboc.com/scummvm_doc/xmlparser_doc.html
+*/
+
+#define MAX_XML_DEPTH 8
+
+#define XML_KEY(keyName) {\
+ lay = new CustomXMLKeyLayout;\
+ lay->callback = (&kLocalParserName::parserCallback_##keyName);\
+ layout.top()->children[#keyName] = lay;\
+ layout.push(lay); \
+ _layoutList.push_back(lay);\
+ for (Common::List<XMLKeyLayout::XMLKeyProperty>::const_iterator p = globalProps.begin(); p != globalProps.end(); ++p){\
+ layout.top()->properties.push_back(*p);}
+
+#define XML_KEY_RECURSIVE(keyName) {\
+ layout.top()->children[#keyName] = layout.top();\
+ layout.push(layout.top());\
+ }
+
+#define KEY_END() layout.pop(); }
+
+#define XML_PROP(propName, req) {\
+ prop.name = #propName; \
+ prop.required = req; \
+ layout.top()->properties.push_back(prop); }
+
+#define XML_GLOBAL_PROP(propName, req) {\
+ prop.name = #propName; \
+ prop.required = req;\
+ globalProps.push_back(prop); }
+
+
+#define CUSTOM_XML_PARSER(parserName) \
+ protected: \
+ typedef parserName kLocalParserName; \
+ bool keyCallback(ParserNode *node) {return node->layout->doCallback(this, node); }\
+ struct CustomXMLKeyLayout : public XMLKeyLayout {\
+ typedef bool (parserName::*ParserCallback)(ParserNode *node);\
+ ParserCallback callback;\
+ bool doCallback(XMLParser *parent, ParserNode *node) {return ((kLocalParserName*)parent->*callback)(node);} };\
+ virtual void buildLayout() { \
+ Common::Stack<XMLKeyLayout*> layout; \
+ CustomXMLKeyLayout *lay = 0; \
+ XMLKeyLayout::XMLKeyProperty prop; \
+ Common::List<XMLKeyLayout::XMLKeyProperty> globalProps; \
+ _XMLkeys = new CustomXMLKeyLayout; \
+ layout.push(_XMLkeys);
+
+#define PARSER_END() layout.clear(); }
+
+/**
+ * The base XMLParser class implements generic functionality for parsing
+ * XML-like files.
+ *
+ * In order to use it, it must be inherited with a child class that implements
+ * the XMLParser::keyCallback() function.
+ *
+ * @see XMLParser::keyCallback()
+ */
+class XMLParser {
+
+public:
+ /**
+ * Parser constructor.
+ */
+ XMLParser() : _XMLkeys(0), _stream(0) {}
+
+ virtual ~XMLParser() {
+ while (!_activeKey.empty())
+ freeNode(_activeKey.pop());
+
+ delete _XMLkeys;
+ delete _stream;
+
+ for (Common::List<XMLKeyLayout*>::iterator i = _layoutList.begin();
+ i != _layoutList.end(); ++i)
+ delete *i;
+
+ _layoutList.clear();
+ }
+
+ /** Active state for the parser */
+ enum ParserState {
+ kParserNeedKey,
+ kParserNeedKeyName,
+
+ kParserNeedPropertyName,
+ kParserNeedPropertyOperator,
+ kParserNeedPropertyValue,
+
+ kParserError
+ };
+
+ struct XMLKeyLayout;
+ struct ParserNode;
+
+ typedef Common::HashMap<Common::String, XMLParser::XMLKeyLayout*, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ChildMap;
+
+ /** nested struct representing the layout of the XML file */
+ struct XMLKeyLayout {
+ struct XMLKeyProperty {
+ Common::String name;
+ bool required;
+ };
+
+ Common::List<XMLKeyProperty> properties;
+ ChildMap children;
+
+ virtual bool doCallback(XMLParser *parent, ParserNode *node) = 0;
+
+ virtual ~XMLKeyLayout() {
+ properties.clear();
+ }
+ } *_XMLkeys;
+
+ /** Struct representing a parsed node */
+ struct ParserNode {
+ Common::String name;
+ Common::StringMap values;
+ bool ignore;
+ int depth;
+ XMLKeyLayout *layout;
+ };
+
+ FixedSizeMemoryPool<sizeof(ParserNode), MAX_XML_DEPTH> _nodePool;
+
+ ParserNode *allocNode() {
+ void* mem = _nodePool.malloc();
+ return new (mem) ParserNode;
+ }
+
+ void freeNode(ParserNode *node) {
+ node->~ParserNode();
+ _nodePool.free(node);
+ }
+
+ /**
+ * Loads a file into the parser.
+ * Used for the loading of Theme Description files
+ * straight from the filesystem.
+ *
+ * @param filename Name of the file to load.
+ */
+ bool loadFile(const Common::String &filename) {
+ Common::File *f = new Common::File;
+
+ if (!f->open(filename)) {
+ delete f;
+ return false;
+ }
+
+ _fileName = filename;
+ _stream = f;
+ return true;
+ }
+
+ bool loadFile(const FSNode &node) {
+ Common::File *f = new Common::File;
+
+ if (!f->open(node)) {
+ delete f;
+ return false;
+ }
+
+ _fileName = node.getName();
+ _stream = f;
+ return true;
+ }
+
+ /**
+ * Loads a memory buffer into the parser.
+ * Used for loading the default theme fallback directly
+ * from memory if no themes can be found.
+ *
+ * @param buffer Pointer to the buffer.
+ * @param size Size of the buffer
+ * @param disposable Sets if the XMLParser owns the buffer,
+ * i.e. if it can be freed safely after it's
+ * no longer needed by the parser.
+ */
+ bool loadBuffer(const byte *buffer, uint32 size, bool disposable = false) {
+ _stream = new MemoryReadStream(buffer, size, disposable);
+ _fileName = "Memory Stream";
+ return true;
+ }
+
+ bool loadStream(Common::SeekableReadStream *stream) {
+ _stream = stream;
+ _fileName = "File Stream";
+ return true;
+ }
+
+ void close() {
+ if (_stream) {
+ delete _stream;
+ _stream = 0;
+ }
+ }
+
+ /**
+ * The actual parsing function.
+ * Parses the loaded data stream, returns true if successful.
+ */
+ bool parse();
+
+ /**
+ * Returns the active node being parsed (the one on top of
+ * the node stack).
+ */
+ ParserNode *getActiveNode() {
+ if (!_activeKey.empty())
+ return _activeKey.top();
+
+ return 0;
+ }
+
+ /**
+ * Returns the parent of a given node in the stack.
+ */
+ ParserNode *getParentNode(ParserNode *child) {
+ return child->depth > 0 ? _activeKey[child->depth - 1] : 0;
+ }
+
+protected:
+
+ /**
+ * The buildLayout function builds the layout for the parser to use
+ * based on a series of helper macros. This function is automatically
+ * generated by the CUSTOM_XML_PARSER() macro on custom parsers.
+ *
+ * See the documentation regarding XML layouts.
+ */
+ virtual void buildLayout() = 0;
+
+ /**
+ * The keycallback function is automatically overloaded on custom parsers
+ * when using the CUSTOM_XML_PARSER() macro.
+ *
+ * Its job is to call the corresponding Callback function for the given node.
+ * A function for each key type must be declared separately. See the custom
+ * parser creation instructions.
+ *
+ * When parsing a key in such function, one may chose to skip it, e.g. because it's not needed
+ * on the current configuration. In order to ignore a key, you must set
+ * the "ignore" field of its KeyNode struct to "true": The key and all its children
+ * will then be automatically ignored by the parser.
+ *
+ * The callback function must return true if the key was properly handled (this includes the case when the
+ * key is being ignored). False otherwise. The return of keyCallback() is the same as
+ * the callback function's.
+ * See the sample implementation in GUI::ThemeParser.
+ */
+ virtual bool keyCallback(ParserNode *node) = 0;
+
+ /**
+ * The closed key callback function MAY be overloaded by inheriting classes to
+ * implement parser-specific functions.
+ *
+ * The closedKeyCallback is issued once a key has been finished parsing, to let
+ * the parser verify that all the required subkeys, etc, were included.
+ *
+ * Unlike the keyCallbacks(), there's just a closedKeyCallback() for all keys.
+ * Use "node->name" to distinguish between each key type.
+ *
+ * Returns true if the key was properly closed, false otherwise.
+ * By default, all keys are properly closed.
+ */
+ virtual bool closedKeyCallback(ParserNode *node) {
+ return true;
+ }
+
+ /**
+ * Called when a node is closed. Manages its cleanup and calls the
+ * closing callback function if needed.
+ */
+ bool closeKey();
+
+ /**
+ * Parses the value of a given key. There's no reason to overload this.
+ */
+ bool parseKeyValue(Common::String keyName);
+
+ /**
+ * Called once a key has been parsed. It handles the closing/cleanup of the
+ * node stack and calls the keyCallback.
+ */
+ bool parseActiveKey(bool closed);
+
+ /**
+ * Prints an error message when parsing fails and stops the parser.
+ * Parser error always returns "false" so we can pass the return value directly
+ * and break down the parsing.
+ */
+ bool parserError(const char *errorString, ...) GCC_PRINTF(2, 3);
+
+ /**
+ * Skips spaces/whitelines etc. Returns true if any spaces were skipped.
+ */
+ bool skipSpaces() {
+ if (!isspace(_char))
+ return false;
+
+ while (_char && isspace(_char))
+ _char = _stream->readByte();
+
+ return true;
+ }
+
+ /**
+ * Skips comment blocks and comment lines.
+ * Returns true if any comments were skipped.
+ * Overload this if you want to disable comments on your XML syntax
+ * or to change the commenting syntax.
+ */
+ virtual bool skipComments() {
+ char endComment1 = 0, endComment2 = 0;
+
+ if (_char == '/') {
+ _char = _stream->readByte();
+
+ if (_char != '*') {
+ _stream->seek(-1, SEEK_CUR);
+ _char = '/';
+ return false;
+ }
+
+ _char = _stream->readByte();
+
+ while (_char) {
+ endComment1 = endComment2;
+ endComment2 = _char;
+ _char = _stream->readByte();
+
+ if (endComment1 == '*' && endComment2 == '/')
+ break;
+
+ if (_char == 0)
+ return parserError("Comment has no closure.");
+ }
+ _char = _stream->readByte();
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Check if a given character can be part of a KEY or VALUE name.
+ * Overload this if you want to support keys with strange characters
+ * in their name.
+ */
+ virtual inline bool isValidNameChar(char c) {
+ return isalnum(c) || c == '_';
+ }
+
+ /**
+ * Parses a the first textual token found.
+ * There's no reason to overload this.
+ */
+ bool parseToken() {
+ _token.clear();
+
+ while (isValidNameChar(_char)) {
+ _token += _char;
+ _char = _stream->readByte();
+ }
+
+ return isspace(_char) != 0 || _char == '>' || _char == '=' || _char == '/';
+ }
+
+ /**
+ * Parses the values inside an integer key.
+ * The count parameter specifies the number of values inside
+ * the key, which are expected to be separated with commas.
+ *
+ * Sample usage:
+ * parseIntegerKey("255, 255, 255", 3, &red, &green, &blue);
+ * [will parse each field into its own integer]
+ *
+ * parseIntegerKey("1234", 1, &number);
+ * [will parse the single number into the variable]
+ *
+ * @param key String containing the integers to be parsed.
+ * @param count Number of comma-separated ints in the string.
+ * @param ... Integer variables to store the parsed ints, passed
+ * by reference.
+ * @returns True if the parsing succeeded.
+ */
+ bool parseIntegerKey(const char *key, int count, ...) {
+ char *parseEnd;
+ int *num_ptr;
+
+ va_list args;
+ va_start(args, count);
+
+ while (count--) {
+ while (isspace(*key))
+ key++;
+
+ num_ptr = va_arg(args, int*);
+ *num_ptr = strtol(key, &parseEnd, 10);
+
+ key = parseEnd;
+
+ while (isspace(*key))
+ key++;
+
+ if (count && *key++ != ',')
+ return false;
+ }
+
+ va_end(args);
+ return (*key == 0);
+ }
+
+ /**
+ * Overload if your parser needs to support parsing the same file
+ * several times, so you can clean up the internal state of the
+ * parser before each parse.
+ */
+ virtual void cleanup() {}
+
+ Common::List<XMLKeyLayout*> _layoutList;
+
+private:
+ char _char;
+ SeekableReadStream *_stream;
+ Common::String _fileName;
+
+ ParserState _state; /** Internal state of the parser */
+
+ Common::String _error; /** Current error message */
+ Common::String _token; /** Current text token */
+
+ Common::Stack<ParserNode*> _activeKey; /** Node stack of the parsed keys */
+};
+
+}
+
+#endif
diff --git a/dists/msvc9/scummvm.vcproj b/dists/msvc9/scummvm.vcproj
index 06545097f6..09b496b087 100644
--- a/dists/msvc9/scummvm.vcproj
+++ b/dists/msvc9/scummvm.vcproj
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
- Version="9,00"
+ Version="9.00"
Name="scummvm"
ProjectGUID="{8434CB15-D08F-427D-9E6D-581AE5B28440}"
RootNamespace="scummvm"
@@ -103,9 +103,6 @@
Name="VCAppVerifierTool"
/>
<Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
@@ -200,9 +197,6 @@
Name="VCAppVerifierTool"
/>
<Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
@@ -470,6 +464,14 @@
>
</File>
<File
+ RelativePath="..\..\common\xmlparser.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\xmlparser.h"
+ >
+ </File>
+ <File
RelativePath="..\..\common\zlib.cpp"
>
</File>
@@ -1117,14 +1119,6 @@
>
</File>
<File
- RelativePath="..\..\gui\eval.cpp"
- >
- </File>
- <File
- RelativePath="..\..\gui\eval.h"
- >
- </File>
- <File
RelativePath="..\..\gui\Key.cpp"
>
</File>
@@ -1213,10 +1207,6 @@
>
</File>
<File
- RelativePath="..\..\gui\theme-config.cpp"
- >
- </File>
- <File
RelativePath="..\..\gui\theme.cpp"
>
</File>
@@ -1233,14 +1223,41 @@
>
</File>
<File
- RelativePath="..\..\gui\ThemeClassic.cpp"
+ RelativePath="..\..\gui\ThemeEngine.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\gui\ThemeEngine.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\gui\ThemeEval.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\gui\ThemeLayout.cpp"
>
</File>
<File
- RelativePath="..\..\gui\ThemeModern.cpp"
+ RelativePath="..\..\gui\ThemeLayout.h"
>
</File>
<File
+ RelativePath="..\..\gui\ThemeParser.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\gui\ThemeParser.h"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
RelativePath="..\..\gui\widget.cpp"
>
</File>
@@ -1345,6 +1362,22 @@
>
</File>
<File
+ RelativePath="..\..\graphics\VectorRenderer.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\graphics\VectorRenderer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\graphics\VectorRendererSpec.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\graphics\VectorRendererSpec.h"
+ >
+ </File>
+ <File
RelativePath="..\..\graphics\thumbnail.cpp"
>
</File>
diff --git a/engines/dialogs.cpp b/engines/dialogs.cpp
index 92932c8964..97c55d4a1f 100644
--- a/engines/dialogs.cpp
+++ b/engines/dialogs.cpp
@@ -32,7 +32,6 @@
#include "graphics/scaler.h"
#include "gui/about.h"
-#include "gui/eval.h"
#include "gui/newgui.h"
#include "gui/ListWidget.h"
#include "gui/theme.h"
@@ -59,9 +58,7 @@ using GUI::WIDGET_ENABLED;
typedef GUI::OptionsDialog GUI_OptionsDialog;
typedef GUI::Dialog GUI_Dialog;
-GlobalDialog::GlobalDialog(String name)
- : GUI::Dialog(name) {
-_drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR;}
+GlobalDialog::GlobalDialog(String name) : GUI::Dialog(name) {}
enum {
kSaveCmd = 'SAVE',
@@ -76,37 +73,41 @@ enum {
};
MainMenuDialog::MainMenuDialog(Engine *engine)
- : GlobalDialog("globalmain"), _engine(engine) {
+ : GlobalDialog("GlobalMenu"), _engine(engine) {
+ _backgroundType = GUI::Theme::kDialogBackgroundSpecial;
#ifndef DISABLE_FANCY_THEMES
_logo = 0;
- if (g_gui.evaluator()->getVar("global_logo.visible") == 1 && g_gui.theme()->supportsImages()) {
- _logo = new GUI::GraphicsWidget(this, "global_logo");
+ if (g_gui.xmlEval()->getVar("Globals.ShowGlobalMenuLogo", 0) == 1 && g_gui.theme()->supportsImages()) {
+ _logo = new GUI::GraphicsWidget(this, "GlobalMenu.Logo");
_logo->useThemeTransparency(true);
_logo->setGfx(g_gui.theme()->getImageSurface(GUI::Theme::kImageLogoSmall));
} else {
- new StaticTextWidget(this, "global_title", "ScummVM");
+ StaticTextWidget *title = new StaticTextWidget(this, "GlobalMenu.Title", "ScummVM");
+ title->setAlign(GUI::kTextAlignCenter);
}
#else
- new StaticTextWidget(this, "global_title", "ScummVM");
+ StaticTextWidget *title = new StaticTextWidget(this, "GlobalMenu.Title", "ScummVM");
+ title->setAlign(GUI::kTextAlignCenter);
#endif
- new StaticTextWidget(this, "global_version", gScummVMVersionDate);
+ StaticTextWidget *version = new StaticTextWidget(this, "GlobalMenu.Version", gScummVMVersionDate);
+ version->setAlign(GUI::kTextAlignCenter);
- new GUI::ButtonWidget(this, "globalmain_resume", "Resume", kPlayCmd, 'P');
+ new GUI::ButtonWidget(this, "GlobalMenu.Resume", "Resume", kPlayCmd, 'P');
// new GUI::ButtonWidget(this, "globalmain_load", "Load", kLoadCmd, 'L');
// new GUI::ButtonWidget(this, "globalmain_save", "Save", kSaveCmd, 'S');
- new GUI::ButtonWidget(this, "globalmain_options", "Options", kOptionsCmd, 'O');
+ new GUI::ButtonWidget(this, "GlobalMenu.Options", "Options", kOptionsCmd, 'O');
- new GUI::ButtonWidget(this, "globalmain_about", "About", kAboutCmd, 'A');
+ new GUI::ButtonWidget(this, "GlobalMenu.About", "About", kAboutCmd, 'A');
- _rtlButton = new GUI::ButtonWidget(this, "globalmain_rtl", "Return to Launcher", kRTLCmd, 'R');
+ _rtlButton = new GUI::ButtonWidget(this, "GlobalMenu.RTL", "Return to Launcher", kRTLCmd, 'R');
_rtlButton->setEnabled(_engine->hasFeature(Engine::kSupportsRTL));
- new GUI::ButtonWidget(this, "globalmain_quit", "Quit", kQuitCmd, 'Q');
+ new GUI::ButtonWidget(this, "GlobalMenu.Quit", "Quit", kQuitCmd, 'Q');
_aboutDialog = new GUI::AboutDialog();
_optionsDialog = new ConfigDialog();
@@ -149,22 +150,24 @@ void MainMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
void MainMenuDialog::reflowLayout() {
#ifndef DISABLE_FANCY_THEMES
- if (g_gui.evaluator()->getVar("global_logo.visible") == 1 && g_gui.theme()->supportsImages()) {
+ if (g_gui.xmlEval()->getVar("Globals.ShowGlobalMenuLogo", 0) == 1 && g_gui.theme()->supportsImages()) {
if (!_logo)
- _logo = new GUI::GraphicsWidget(this, "global_logo");
+ _logo = new GUI::GraphicsWidget(this, "GlobalMenu.Logo");
_logo->useThemeTransparency(true);
_logo->setGfx(g_gui.theme()->getImageSurface(GUI::Theme::kImageLogoSmall));
- GUI::StaticTextWidget *title = (StaticTextWidget *)findWidget("global_title");
+ GUI::StaticTextWidget *title = (StaticTextWidget *)findWidget("GlobalMenu.Title");
if (title) {
removeWidget(title);
title->setNext(0);
delete title;
}
} else {
- GUI::StaticTextWidget *title = (StaticTextWidget *)findWidget("global_title");
- if (!title)
- new StaticTextWidget(this, "global_title", "ScummVM");
+ GUI::StaticTextWidget *title = (StaticTextWidget *)findWidget("GlobalMenu.Title");
+ if (!title) {
+ title = new StaticTextWidget(this, "GlobalMenu.Title", "ScummVM");
+ title->setAlign(GUI::kTextAlignCenter);
+ }
if (_logo) {
removeWidget(_logo);
@@ -212,30 +215,30 @@ enum {
// "" as value for the domain, and in fact provide a somewhat better user
// experience at the same time.
ConfigDialog::ConfigDialog()
- : GUI::OptionsDialog("", "scummconfig") {
+ : GUI::OptionsDialog("", "ScummConfig") {
//
// Sound controllers
//
- addVolumeControls(this, "scummconfig_");
+ addVolumeControls(this, "ScummConfig.");
//
// Some misc options
//
// SCUMM has a talkspeed range of 0-9
- addSubtitleControls(this, "scummconfig_", 9);
+ addSubtitleControls(this, "ScummConfig.", 9);
//
// Add the buttons
//
- new GUI::ButtonWidget(this, "scummconfig_ok", "OK", GUI::OptionsDialog::kOKCmd, 'O');
- new GUI::ButtonWidget(this, "scummconfig_cancel", "Cancel", kCloseCmd, 'C');
+ new GUI::ButtonWidget(this, "ScummConfig.Ok", "OK", GUI::OptionsDialog::kOKCmd, 'O');
+ new GUI::ButtonWidget(this, "ScummConfig.Cancel", "Cancel", kCloseCmd, 'C');
#ifdef SMALL_SCREEN_DEVICE
- new GUI::ButtonWidget(this, "scummconfig_keys", "Keys", kKeysCmd, 'K');
+ new GUI::ButtonWidget(this, "ScummConfig.Keys", "Keys", kKeysCmd, 'K');
//
// Create the sub dialog(s)
diff --git a/engines/parallaction/saveload.cpp b/engines/parallaction/saveload.cpp
index d357e31cdc..8093d4f234 100644
--- a/engines/parallaction/saveload.cpp
+++ b/engines/parallaction/saveload.cpp
@@ -252,15 +252,17 @@ enum {
};
+
SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel)
- : Dialog("scummsaveload"), _list(0), _chooseButton(0), _gfxWidget(0) {
+ : Dialog("ScummSaveLoad"), _list(0), _chooseButton(0), _gfxWidget(0) {
// _drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR;
+ _backgroundType = GUI::Theme::kDialogBackgroundSpecial;
- new GUI::StaticTextWidget(this, "scummsaveload_title", title);
+ new GUI::StaticTextWidget(this, "ScummSaveLoad.Title", title);
// Add choice list
- _list = new GUI::ListWidget(this, "scummsaveload_list");
+ _list = new GUI::ListWidget(this, "ScummSaveLoad.List");
_list->setEditable(true);
_list->setNumberingMode(GUI::kListNumberingOne);
@@ -271,12 +273,12 @@ SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel)
_playtime = new GUI::StaticTextWidget(this, 0, 0, 10, 10, "No playtime saved", GUI::kTextAlignCenter);
// Buttons
- new GUI::ButtonWidget(this, "scummsaveload_cancel", "Cancel", GUI::kCloseCmd, 0);
- _chooseButton = new GUI::ButtonWidget(this, "scummsaveload_choose", buttonLabel, kChooseCmd, 0);
+ new GUI::ButtonWidget(this, "ScummSaveLoad.Cancel", "Cancel", GUI::kCloseCmd, 0);
+ _chooseButton = new GUI::ButtonWidget(this, "ScummSaveLoad.Choose", buttonLabel, kChooseCmd, 0);
_chooseButton->setEnabled(false);
_container = new GUI::ContainerWidget(this, 0, 0, 10, 10);
- _container->setHints(GUI::THEME_HINT_USE_SHADOW);
+// _container->setHints(GUI::THEME_HINT_USE_SHADOW);
}
SaveLoadChooser::~SaveLoadChooser() {
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 799203abe7..382a0a9338 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -36,9 +36,10 @@
#endif
#include "gui/about.h"
-#include "gui/eval.h"
+#include "gui/theme.h"
#include "gui/newgui.h"
#include "gui/ListWidget.h"
+#include "gui/ThemeEval.h"
#include "scumm/dialogs.h"
#include "scumm/sound.h"
@@ -212,9 +213,8 @@ static const ResString string_map_table_v345[] = {
#pragma mark -
-ScummDialog::ScummDialog(String name)
- : GUI::Dialog(name) {
-_drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR;
+ScummDialog::ScummDialog(String name) : GUI::Dialog(name) {
+ _backgroundType = GUI::Theme::kDialogBackgroundSpecial;
}
#pragma mark -
@@ -233,17 +233,21 @@ enum {
};
SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode, ScummEngine *engine)
- : Dialog("scummsaveload"), _saveMode(saveMode), _list(0), _chooseButton(0), _gfxWidget(0), _vm(engine) {
+ : Dialog("ScummSaveLoad"), _saveMode(saveMode), _list(0), _chooseButton(0), _gfxWidget(0), _vm(engine) {
+
+ _backgroundType = GUI::Theme::kDialogBackgroundSpecial;
- _drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR;
-
- new StaticTextWidget(this, "scummsaveload_title", title);
+ new StaticTextWidget(this, "ScummSaveLoad.Title", title);
// Add choice list
- _list = new GUI::ListWidget(this, "scummsaveload_list");
+ _list = new GUI::ListWidget(this, "ScummSaveLoad.List");
_list->setEditable(saveMode);
_list->setNumberingMode(saveMode ? GUI::kListNumberingOne : GUI::kListNumberingZero);
+// Tanoku: SVNMerge removed this. Unconvinient. ///////////////
+// _container = new GUI::ContainerWidget(this, 0, 0, 10, 10);
+///////////////////////////////////////////////////////////////
+
_gfxWidget = new GUI::GraphicsWidget(this, 0, 0, 10, 10);
_date = new StaticTextWidget(this, 0, 0, 10, 10, "No date saved", kTextAlignCenter);
@@ -251,12 +255,12 @@ SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel,
_playtime = new StaticTextWidget(this, 0, 0, 10, 10, "No playtime saved", kTextAlignCenter);
// Buttons
- new GUI::ButtonWidget(this, "scummsaveload_cancel", "Cancel", kCloseCmd, 0);
- _chooseButton = new GUI::ButtonWidget(this, "scummsaveload_choose", buttonLabel, kChooseCmd, 0);
+ new GUI::ButtonWidget(this, "ScummSaveLoad.Cancel", "Cancel", kCloseCmd, 0);
+ _chooseButton = new GUI::ButtonWidget(this, "ScummSaveLoad.Choose", buttonLabel, kChooseCmd, 0);
_chooseButton->setEnabled(false);
_container = new GUI::ContainerWidget(this, 0, 0, 10, 10);
- _container->setHints(GUI::THEME_HINT_USE_SHADOW);
+// _container->setHints(GUI::THEME_HINT_USE_SHADOW);
}
SaveLoadChooser::~SaveLoadChooser() {
@@ -317,17 +321,20 @@ void SaveLoadChooser::handleCommand(CommandSender *sender, uint32 cmd, uint32 da
}
void SaveLoadChooser::reflowLayout() {
- if (g_gui.evaluator()->getVar("scummsaveload_extinfo.visible") == 1) {
- int thumbX = g_gui.evaluator()->getVar("scummsaveload_thumbnail.x");
- int thumbY = g_gui.evaluator()->getVar("scummsaveload_thumbnail.y");
- int hPad = g_gui.evaluator()->getVar("scummsaveload_thumbnail.hPad");
- int vPad = g_gui.evaluator()->getVar("scummsaveload_thumbnail.vPad");
+ if (g_gui.xmlEval()->getVar("Globals.ScummSaveLoad.ExtInfo.Visible") == 1) {
+ int16 x, y;
+ uint16 w, h;
+
+ if (!g_gui.xmlEval()->getWidgetData("ScummSaveLoad.Thumbnail", x, y, w, h))
+ error("Error when loading position data for Save/Load Thumbnails.");
+
+ int thumbW = kThumbnailWidth;
int thumbH = ((g_system->getHeight() % 200 && g_system->getHeight() != 350) ? kThumbnailHeight2 : kThumbnailHeight1);
-
- _container->resize(thumbX - hPad, thumbY - vPad, kThumbnailWidth + hPad * 2, thumbH + vPad * 2 + kLineHeight * 4);
-
- // Add the thumbnail display
- _gfxWidget->resize(thumbX, thumbY, kThumbnailWidth, thumbH);
+ int thumbX = x + (w >> 1) - (thumbW >> 1);
+ int thumbY = y + kLineHeight;
+
+ _container->resize(x, y, w, h);
+ _gfxWidget->resize(thumbX, thumbY, thumbW, thumbH);
int height = thumbY + thumbH + kLineHeight;
@@ -347,9 +354,9 @@ void SaveLoadChooser::reflowLayout() {
_time->clearFlags(GUI::WIDGET_INVISIBLE);
_playtime->clearFlags(GUI::WIDGET_INVISIBLE);
- _fillR = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillR");
- _fillG = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillG");
- _fillB = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillB");
+ _fillR = 0; //g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillR");
+ _fillG = 0; //g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillG");
+ _fillB = 0; //g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillB");
updateInfos(false);
} else {
_container->setFlags(GUI::WIDGET_INVISIBLE);
@@ -431,20 +438,20 @@ Common::StringList generateSavegameList(ScummEngine *scumm, bool saveMode) {
}
ScummMenuDialog::ScummMenuDialog(ScummEngine *scumm)
- : ScummDialog("scummmain"), _vm(scumm) {
+ : ScummDialog("ScummMain"), _vm(scumm) {
- new GUI::ButtonWidget(this, "scummmain_resume", "Resume", kPlayCmd, 'P');
+ new GUI::ButtonWidget(this, "ScummMain.Resume", "Resume", kPlayCmd, 'P');
- new GUI::ButtonWidget(this, "scummmain_load", "Load", kLoadCmd, 'L');
- new GUI::ButtonWidget(this, "scummmain_save", "Save", kSaveCmd, 'S');
+ new GUI::ButtonWidget(this, "ScummMain.Load", "Load", kLoadCmd, 'L');
+ new GUI::ButtonWidget(this, "ScummMain.Save", "Save", kSaveCmd, 'S');
- new GUI::ButtonWidget(this, "scummmain_options", "Options", kOptionsCmd, 'O');
+ new GUI::ButtonWidget(this, "ScummMain.Options", "Options", kOptionsCmd, 'O');
#ifndef DISABLE_HELP
- new GUI::ButtonWidget(this, "scummmain_help", "Help", kHelpCmd, 'H');
+ new GUI::ButtonWidget(this, "ScummMain.Help", "Help", kHelpCmd, 'H');
#endif
- new GUI::ButtonWidget(this, "scummmain_about", "About", kAboutCmd, 'A');
+ new GUI::ButtonWidget(this, "ScummMain.About", "About", kAboutCmd, 'A');
- new GUI::ButtonWidget(this, "scummmain_quit", "Quit", kQuitCmd, 'Q');
+ new GUI::ButtonWidget(this, "ScummMain.Quit", "Quit", kQuitCmd, 'Q');
//
// Create the sub dialog(s)
@@ -564,29 +571,29 @@ enum {
// "" as value for the domain, and in fact provide a somewhat better user
// experience at the same time.
ConfigDialog::ConfigDialog()
- : GUI::OptionsDialog("", "scummconfig") {
+ : GUI::OptionsDialog("", "ScummConfig") {
//
// Sound controllers
//
- addVolumeControls(this, "scummconfig_");
+ addVolumeControls(this, "ScummConfig.");
//
// Some misc options
//
// SCUMM has a talkspeed range of 0-9
- addSubtitleControls(this, "scummconfig_", 9);
+ addSubtitleControls(this, "ScummConfig.", 9);
//
// Add the buttons
//
- new GUI::ButtonWidget(this, "scummconfig_ok", "OK", GUI::OptionsDialog::kOKCmd, 'O');
- new GUI::ButtonWidget(this, "scummconfig_cancel", "Cancel", kCloseCmd, 'C');
+ new GUI::ButtonWidget(this, "ScummConfig.Ok", "OK", GUI::OptionsDialog::kOKCmd, 'O');
+ new GUI::ButtonWidget(this, "ScummConfig.Cancel", "Cancel", kCloseCmd, 'C');
#ifdef SMALL_SCREEN_DEVICE
- new GUI::ButtonWidget(this, "scummconfig_keys", "Keys", kKeysCmd, 'K');
+ new GUI::ButtonWidget(this, "ScummConfig.Keys", "Keys", kKeysCmd, 'K');
#endif
#ifdef SMALL_SCREEN_DEVICE
@@ -626,22 +633,23 @@ enum {
};
HelpDialog::HelpDialog(const GameSettings &game)
- : ScummDialog("scummhelp"), _game(game) {
- _title = new StaticTextWidget(this, "scummhelp_title", "");
+ : ScummDialog("ScummHelp"), _game(game) {
+ _title = new StaticTextWidget(this, "ScummHelp.Title", "");
_page = 1;
+ _backgroundType = GUI::Theme::kDialogBackgroundDefault;
_numPages = ScummHelp::numPages(_game.id);
- _prevButton = new GUI::ButtonWidget(this, "scummhelp_prev", "Previous", kPrevCmd, 'P');
- _nextButton = new GUI::ButtonWidget(this, "scummhelp_next", "Next", kNextCmd, 'N');
- new GUI::ButtonWidget(this, "scummhelp_close", "Close", kCloseCmd, 'C');
+ _prevButton = new GUI::ButtonWidget(this, "ScummHelp.Prev", "Previous", kPrevCmd, 'P');
+ _nextButton = new GUI::ButtonWidget(this, "ScummHelp.Next", "Next", kNextCmd, 'N');
+ new GUI::ButtonWidget(this, "ScummHelp.Close", "Close", kCloseCmd, 'C');
_prevButton->clearFlags(WIDGET_ENABLED);
// Dummy entries
for (int i = 0; i < HELP_NUM_LINES; i++) {
- _key[i] = new StaticTextWidget(this, 0, 0, 10, 10, "", kTextAlignLeft);
- _dsc[i] = new StaticTextWidget(this, 0, 0, 10, 10, "", kTextAlignLeft);
+ _key[i] = new StaticTextWidget(this, 0, 0, 10, 10, "", Graphics::kTextAlignRight);
+ _dsc[i] = new StaticTextWidget(this, 0, 0, 10, 10, "", Graphics::kTextAlignLeft);
}
}
@@ -649,22 +657,21 @@ HelpDialog::HelpDialog(const GameSettings &game)
void HelpDialog::reflowLayout() {
ScummDialog::reflowLayout();
- _drawingHints &= ~GUI::THEME_HINT_SPECIAL_COLOR;
-
int lineHeight = g_gui.getFontHeight();
-
- int keyX = g_gui.evaluator()->getVar("scummhelp_key.x");
- int keyYoff = g_gui.evaluator()->getVar("scummhelp_key.yoffset");
- int keyW = g_gui.evaluator()->getVar("scummhelp_key.w");
- int keyH = g_gui.evaluator()->getVar("scummhelp_key.h");
- int dscX = g_gui.evaluator()->getVar("scummhelp_dsc.x");
- int dscYoff = g_gui.evaluator()->getVar("scummhelp_dsc.yoffset");
- int dscW = g_gui.evaluator()->getVar("scummhelp_dsc.w");
- int dscH = g_gui.evaluator()->getVar("scummhelp_dsc.h");
+ int16 x, y;
+ uint16 w, h;
+
+ g_gui.xmlEval()->getWidgetData("ScummHelp.HelpText", x, y, w, h);
+
+ int keyW = w * 20 / 100;
+ int dscX = x + keyW + 32;
+ int dscW = w * 80 / 100;
+
+ int xoff = (_w >> 1) - (w >> 1);
for (int i = 0; i < HELP_NUM_LINES; i++) {
- _key[i]->resize(keyX, keyYoff + lineHeight * (i + 2), keyW, keyH);
- _dsc[i]->resize(dscX, dscYoff + lineHeight * (i + 2), dscW, dscH);
+ _key[i]->resize(xoff + x, y + lineHeight * i, keyW, lineHeight + 2);
+ _dsc[i]->resize(xoff + dscX, y + lineHeight * i, dscW, lineHeight + 2);
}
displayKeyBindings();
@@ -836,7 +843,7 @@ void ConfirmDialog::handleKeyDown(Common::KeyState state) {
ValueDisplayDialog::ValueDisplayDialog(const Common::String& label, int minVal, int maxVal,
int val, uint16 incKey, uint16 decKey)
- : GUI::Dialog("scummDummyDialog", false),
+ : GUI::Dialog("scummDummyDialog"),
_label(label), _min(minVal), _max(maxVal),
_value(val), _incKey(incKey), _decKey(decKey) {
assert(_min <= _value && _value <= _max);
@@ -844,8 +851,7 @@ ValueDisplayDialog::ValueDisplayDialog(const Common::String& label, int minVal,
void ValueDisplayDialog::drawDialog() {
const int labelWidth = _w - 8 - _percentBarWidth;
- g_gui.theme()->drawDialogBackground(Common::Rect(_x, _y, _x+_w, _y+_h),
- GUI::THEME_HINT_SAVE_BACKGROUND | GUI::THEME_HINT_FIRST_DRAW);
+ g_gui.theme()->drawDialogBackground(Common::Rect(_x, _y, _x+_w, _y+_h), GUI::Theme::kDialogBackgroundDefault);
g_gui.theme()->drawText(Common::Rect(_x+4, _y+4, _x+labelWidth+4,
_y+g_gui.theme()->getFontHeight()+4), _label);
g_gui.theme()->drawSlider(Common::Rect(_x+4+labelWidth, _y+4, _x+_w-4, _y+_h-4),
@@ -937,7 +943,10 @@ void SubtitleSettingsDialog::cycleValue() {
if (_value > 2)
_value = 0;
- setInfoText(subtitleDesc[_value]);
+ if (_value == 1 && g_system->getOverlayWidth() <= 320)
+ setInfoText("Speech & Subs");
+ else
+ setInfoText(subtitleDesc[_value]);
_timer = getMillis() + 1500;
}
diff --git a/graphics/VectorRenderer.cpp b/graphics/VectorRenderer.cpp
new file mode 100644
index 0000000000..4f9bd48334
--- /dev/null
+++ b/graphics/VectorRenderer.cpp
@@ -0,0 +1,159 @@
+/* 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 "common/system.h"
+#include "common/events.h"
+
+#include "graphics/surface.h"
+#include "graphics/colormasks.h"
+
+#include "gui/ThemeEngine.h"
+#include "graphics/VectorRenderer.h"
+
+#define VECTOR_RENDERER_FAST_TRIANGLES
+
+namespace Graphics {
+
+const VectorRenderer::ConvolutionDataSet VectorRenderer::_convolutionData[VectorRenderer::kConvolutionMAX] = {
+ { {{1, 1, 1}, {1, 8, 1}, {1, 1, 1}}, 16, 0 }, // soft blur matrix
+ { {{2, 2, 2}, {2, 2, 2}, {2, 2, 2}}, 18, 0 }, // hard blur matrix
+ { {{1, 2, 1}, {2, 4, 2}, {1, 2, 1}}, 16, 0 }, // gaussian blur matrix
+ { {{2, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 1, 127}, // emboss matrix
+ { {{-1, -1, -1}, {-1, 9, -1}, {-1, -1, -1}}, 1, 0}, // sharpen matrix
+ { {{1, 1, 1}, {1, -7, 1}, {1, 1, 1}}, 1, 0} // edge find matrix
+};
+
+/********************************************************************
+ * DRAWSTEP handling functions
+ ********************************************************************/
+void VectorRenderer::drawStep(const Common::Rect &area, const DrawStep &step, uint32 extra) {
+
+ if (step.bgColor.set)
+ setBgColor(step.bgColor.r, step.bgColor.g, step.bgColor.b);
+
+ if (step.fgColor.set)
+ setFgColor(step.fgColor.r, step.fgColor.g, step.fgColor.b);
+
+ if (step.bevelColor.set)
+ setBevelColor(step.bevelColor.r, step.bevelColor.g, step.bevelColor.b);
+
+ if (step.gradColor1.set && step.gradColor2.set)
+ setGradientColors(step.gradColor1.r, step.gradColor1.g, step.gradColor1.b,
+ step.gradColor2.r, step.gradColor2.g, step.gradColor2.b);
+
+ setShadowOffset(_disableShadows ? 0 : step.shadow);
+ setBevel(step.bevel);
+ setGradientFactor(step.factor);
+ setStrokeWidth(step.stroke);
+ setFillMode((FillMode)step.fillMode);
+
+ _dynamicData = extra;
+
+ (this->*(step.drawingCall))(area, step);
+}
+
+int VectorRenderer::stepGetRadius(const DrawStep &step, const Common::Rect &area) {
+ int radius = 0;
+
+ if (step.radius == 0xFF)
+ radius = MIN(area.width(), area.height()) / 2;
+ else
+ radius = step.radius;
+
+ if (step.scale != (1 << 16) && step.scale != 0)
+ radius = (radius * step.scale) >> 16;
+
+ return radius;
+}
+
+void VectorRenderer::stepGetPositions(const DrawStep &step, const Common::Rect &area, uint16 &in_x, uint16 &in_y, uint16 &in_w, uint16 &in_h) {
+ if (!step.autoWidth) {
+ in_w = step.w == -1 ? area.height() : step.w;
+
+ switch(step.xAlign) {
+ case Graphics::DrawStep::kVectorAlignManual:
+ if (step.x >= 0) in_x = area.left + step.x;
+ else in_x = area.left + area.width() + step.x; // value relative to the opposite corner.
+ break;
+
+ case Graphics::DrawStep::kVectorAlignCenter:
+ in_x = area.left + (area.width() / 2) - (in_w / 2);
+ break;
+
+ case Graphics::DrawStep::kVectorAlignLeft:
+ in_x = area.left;
+ break;
+
+ case Graphics::DrawStep::kVectorAlignRight:
+ in_x = area.left + area.width() - in_w;
+ break;
+
+ default:
+ error("Vertical alignment in horizontal data.");
+ }
+ } else {
+ in_x = area.left;
+ in_w = area.width();
+ }
+
+ if (!step.autoHeight) {
+ in_h = step.h == -1 ? area.width() : step.h;
+
+ switch(step.yAlign) {
+ case Graphics::DrawStep::kVectorAlignManual:
+ if (step.y >= 0) in_y = area.top + step.y;
+ else in_y = area.top + area.height() + step.y; // relative
+ break;
+
+ case Graphics::DrawStep::kVectorAlignCenter:
+ in_y = area.top + (area.height() / 2) - (in_h / 2);
+ break;
+
+ case Graphics::DrawStep::kVectorAlignTop:
+ in_y = area.top;
+ break;
+
+ case Graphics::DrawStep::kVectorAlignBottom:
+ in_y = area.top + area.height() - in_h;
+ break;
+
+ default:
+ error("Horizontal alignment in vertical data.");
+ }
+ } else {
+ in_y = area.top;
+ in_h = area.height();
+ }
+
+ if (step.scale != (1 << 16) && step.scale != 0) {
+ in_x = (in_x * step.scale) >> 16;
+ in_y = (in_y * step.scale) >> 16;
+ in_w = (in_w * step.scale) >> 16;
+ in_h = (in_h * step.scale) >> 16;
+ }
+}
+
+} // end of namespace Graphics
diff --git a/graphics/VectorRenderer.h b/graphics/VectorRenderer.h
new file mode 100644
index 0000000000..c2cd6b0010
--- /dev/null
+++ b/graphics/VectorRenderer.h
@@ -0,0 +1,557 @@
+/* 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 VECTOR_RENDERER_H
+#define VECTOR_RENDERER_H
+
+#include "common/scummsys.h"
+#include "common/system.h"
+
+#include "graphics/surface.h"
+#include "graphics/colormasks.h"
+
+#include "gui/ThemeEngine.h"
+
+namespace Graphics {
+class VectorRenderer;
+
+struct DrawStep {
+ struct {
+ uint8 r, g, b;
+ bool set;
+ }
+ fgColor, /** Foreground color */
+ bgColor, /** backgroudn color */
+ gradColor1, /** gradient start*/
+ gradColor2, /** gradient end */
+ bevelColor;
+
+ bool autoWidth, autoHeight;
+ int16 x, y, w, h; /** width, height and position, if not measured automatically.
+ negative values mean counting from the opposite direction */
+
+ enum VectorAlignment {
+ kVectorAlignManual,
+ kVectorAlignLeft,
+ kVectorAlignRight,
+ kVectorAlignBottom,
+ kVectorAlignTop,
+ kVectorAlignCenter
+ } xAlign, yAlign;
+
+ uint8 shadow, stroke, factor, radius, bevel; /** Misc options... */
+
+ uint8 fillMode; /** active fill mode */
+ uint32 extraData; /** Generic parameter for extra options (orientation/bevel) */
+
+ uint32 scale; /** scale of all the coordinates in FIXED POINT with 16 bits mantissa */
+
+ void (VectorRenderer::*drawingCall)(const Common::Rect &, const DrawStep &); /** Pointer to drawing function */
+ Graphics::Surface *blitSrc;
+};
+
+VectorRenderer *createRenderer(int mode);
+
+/**
+ * VectorRenderer: The core Vector Renderer Class
+ *
+ * This virtual class exposes the API with all the vectorial
+ * rendering functions that may be used to draw on a given Surface.
+ *
+ * This class must be instantiated as one of its children, which implement
+ * the actual rendering functionality for each Byte Depth / Byte Format
+ * combination, and may also contain platform specific code.
+ *
+ * TODO: Expand documentation.
+ *
+ * @see VectorRendererSpec
+ * @see VectorRendererAA
+ */
+class VectorRenderer {
+public:
+ VectorRenderer() : _shadowOffset(0), _fillMode(kFillDisabled),
+ _activeSurface(NULL), _strokeWidth(1), _gradientFactor(1), _disableShadows(false) {
+
+ }
+
+ virtual ~VectorRenderer() {}
+
+ /** Specifies the way in which a shape is filled */
+ enum FillMode {
+ kFillDisabled = 0,
+ kFillForeground = 1,
+ kFillBackground = 2,
+ kFillGradient = 3
+ };
+
+ enum TriangleOrientation {
+ kTriangleAuto = 0,
+ kTriangleUp,
+ kTriangleDown,
+ kTriangleLeft,
+ kTriangleRight
+ };
+
+ enum ConvolutionData {
+ kConvolutionSoftBlur,
+ kConvolutionHardBlur,
+ kConvolutionGaussianBlur,
+ kConvolutionEmboss,
+ kConvolutionSharpen,
+ kConvolutionEdgeDetect,
+ kConvolutionMAX
+ };
+
+ struct ConvolutionDataSet {
+ int matrix[3][3];
+ int divisor;
+ int offset;
+ };
+
+ /**
+ * Draws a line by considering the special cases for optimization.
+ *
+ * @param x1 Horizontal (X) coordinate for the line start
+ * @param x2 Horizontal (X) coordinate for the line end
+ * @param y1 Vertical (Y) coordinate for the line start
+ * @param y2 Vertical (Y) coordinate for the line end
+ */
+ virtual void drawLine(int x1, int y1, int x2, int y2) = 0;
+
+ /**
+ * Draws a circle centered at (x,y) with radius r.
+ *
+ * @param x Horizontal (X) coordinate for the center of the circle
+ * @param y Vertical (Y) coordinate for the center of the circle
+ * @param r Radius of the circle.
+ */
+ virtual void drawCircle(int x, int y, int r) = 0;
+
+ /**
+ * Draws a square starting at (x,y) with the given width and height.
+ *
+ * @param x Horizontal (X) coordinate for the center of the square
+ * @param y Vertical (Y) coordinate for the center of the square
+ * @param w Width of the square.
+ * @param h Height of the square
+ */
+ virtual void drawSquare(int x, int y, int w, int h) = 0;
+
+ /**
+ * Draws a rounded square starting at (x,y) with the given width and height.
+ * The corners of the square are rounded with the given radius.
+ *
+ * @param x Horizontal (X) coordinate for the center of the square
+ * @param y Vertical (Y) coordinate for the center of the square
+ * @param w Width of the square.
+ * @param h Height of the square
+ * @param r Radius of the corners.
+ */
+ virtual void drawRoundedSquare(int x, int y, int r, int w, int h) = 0;
+
+ /**
+ * Draws a triangle starting at (x,y) with the given base and height.
+ * The triangle will always be isosceles, with the given base and height.
+ * The orientation parameter controls the position of the base of the triangle.
+ *
+ * @param x Horizontal (X) coordinate for the top left corner of the triangle
+ * @param y Vertical (Y) coordinate for the top left corner of the triangle
+ * @param base Width of the base of the triangle
+ * @param h Height of the triangle
+ * @param orient Orientation of the triangle.
+ */
+ virtual void drawTriangle(int x, int y, int base, int height, TriangleOrientation orient) = 0;
+
+ /**
+ * Draws a beveled square like the ones in the Classic GUI themes.
+ * Beveled squares are always drawn with a transparent background. Draw them on top
+ * of a standard square to fill it.
+ *
+ * @param x Horizontal (X) coordinate for the center of the square
+ * @param y Vertical (Y) coordinate for the center of the square
+ * @param w Width of the square.
+ * @param h Height of the square
+ * @param bevel Amount of bevel. Must be positive.
+ */
+ virtual void drawBeveledSquare(int x, int y, int w, int h, int bevel) = 0;
+
+ /**
+ * Draws a tab-like shape, specially thought for the Tab widget.
+ * If a radius is given, the tab will have rounded corners. Otherwise,
+ * the tab will be squared.
+ *
+ * @param x Horizontal (X) coordinate for the tab
+ * @param y Vertical (Y) coordinate for the tab
+ * @param w Width of the tab
+ * @param h Height of the tab
+ * @param r Radius of the corners of the tab (0 for squared tabs).
+ */
+ virtual void drawTab(int x, int y, int r, int w, int h) = 0;
+
+
+ /**
+ * Simple helper function to draw a cross.
+ */
+ virtual void drawCross(int x, int y, int w, int h) {
+ drawLine(x, y, x + w, y + w);
+ drawLine(x + w, y, x, y + h);
+ }
+
+ /**
+ * Gets the pixel pitch for the current drawing surface.
+ * Note: This is a real pixel-pitch, not a byte-pitch.
+ * That means it can be safely used in pointer arithmetics and
+ * in pixel manipulation.
+ *
+ * @return integer with the active bytes per pixel
+ */
+ virtual uint16 surfacePitch() {
+ return _activeSurface->pitch / _activeSurface->bytesPerPixel;
+ }
+
+ /**
+ * Gets the BYTES (not bits) per Pixel we are working on,
+ * based on the active drawing surface.
+ *
+ * @return integer byte with the active bytes per pixel value
+ */
+ virtual uint8 bytesPerPixel() {
+ return _activeSurface->bytesPerPixel;
+ }
+
+ /**
+ * Set the active foreground painting color for the renderer.
+ * All the foreground drawing from then on will be done with that color, unless
+ * specified otherwise.
+ *
+ * Foreground drawing means all outlines and basic shapes.
+ *
+ * @param r value of the red color byte
+ * @param g value of the green color byte
+ * @param b value of the blue color byte
+ */
+ virtual void setFgColor(uint8 r, uint8 g, uint8 b) = 0;
+
+ /**
+ * Set the active background painting color for the renderer.
+ * All the background drawing from then on will be done with that color, unless
+ * specified otherwise.
+ *
+ * Background drawing means all the shape filling.
+ *
+ * @param r value of the red color byte
+ * @param g value of the green color byte
+ * @param b value of the blue color byte
+ */
+ virtual void setBgColor(uint8 r, uint8 g, uint8 b) = 0;
+
+ virtual void setBevelColor(uint8 r, uint8 g, uint8 b) = 0;
+
+ /**
+ * Set the active gradient color. All shapes drawn using kFillGradient
+ * as their fill mode will use this VERTICAL gradient as their fill color.
+ *
+ * @param r1 value of the red color byte for the start color
+ * @param g1 value of the green color byte for the start color
+ * @param b1 value of the blue color byte for the start color
+ * @param r2 value of the red color byte for the end color
+ * @param g2 value of the green color byte for the end color
+ * @param b2 value of the blue color byte for the end color
+ */
+ virtual void setGradientColors(uint8 r1, uint8 g1, uint8 b1, uint8 r2, uint8 g2, uint8 b2) = 0;
+
+ /**
+ * Sets the active drawing surface. All drawing from this
+ * point on will be done on that surface.
+ *
+ * @param surface Pointer to a Surface object.
+ */
+ virtual void setSurface(Surface *surface) {
+ _activeSurface = surface;
+ }
+
+ /**
+ * Fills the active surface with the specified fg/bg color or the active gradient.
+ * Defaults to using the active Foreground color for filling.
+ *
+ * @param mode Fill mode (bg, fg or gradient) used to fill the surface
+ */
+ virtual void fillSurface() = 0;
+
+ /**
+ * Clears the active surface.
+ */
+ virtual void clearSurface() {
+ byte *src = (byte *)_activeSurface->pixels;
+ memset(src, 0, _activeSurface->w * _activeSurface->h * _activeSurface->bytesPerPixel);
+ }
+
+ /**
+ * Sets the active fill mode for all shapes.
+ *
+ * @see VectorRenderer::FillMode
+ * @param mode Specified fill mode.
+ */
+ virtual void setFillMode(FillMode mode) {
+ _fillMode = mode;
+ }
+
+ /**
+ * Sets the stroke width. All shapes drawn with a stroke will
+ * have that width. Pass 0 to disable shape stroking.
+ *
+ * @param width Witdh of the stroke in pixels.
+ */
+ virtual void setStrokeWidth(int width) {
+ _strokeWidth = width;
+ }
+
+ /**
+ * Enables adding shadows to all drawn primitives.
+ * Shadows are drawn automatically under the shapes. The given offset
+ * controls their intensity and size (the higher the offset, the
+ * bigger the shadows). If the offset is 0, no shadows are drawn.
+ *
+ * @param offset Shadow offset.
+ */
+ virtual void setShadowOffset(int offset) {
+ if (offset >= 0)
+ _shadowOffset = offset;
+ }
+
+ virtual void setBevel(int amount) {
+ if (amount >= 0)
+ _bevel = amount;
+ }
+
+ /**
+ * Sets the multiplication factor of the active gradient.
+ *
+ * @see _gradientFactor
+ * @param factor Multiplication factor.
+ */
+ virtual void setGradientFactor(int factor) {
+ if (factor > 0)
+ _gradientFactor = factor;
+ }
+
+ /**
+ * Translates the position data inside a DrawStep into actual
+ * screen drawing positions.
+ */
+ void stepGetPositions(const DrawStep &step, const Common::Rect &area, uint16 &in_x, uint16 &in_y, uint16 &in_w, uint16 &in_h);
+
+ /**
+ * Translates the radius data inside a drawstep into the real radius
+ * for the shape. Used for automatic radius calculations.
+ */
+ int stepGetRadius(const DrawStep &step, const Common::Rect &area);
+
+ /**
+ * DrawStep callback functions for each drawing feature
+ */
+ void drawCallback_CIRCLE(const Common::Rect &area, const DrawStep &step) {
+ uint16 x, y, w, h, radius;
+
+ radius = stepGetRadius(step, area);
+ stepGetPositions(step, area, x, y, w, h);
+
+ drawCircle(x + radius, y + radius, radius);
+ }
+
+ void drawCallback_SQUARE(const Common::Rect &area, const DrawStep &step) {
+ uint16 x, y, w, h;
+ stepGetPositions(step, area, x, y, w, h);
+ drawSquare(x, y, w, h);
+ }
+
+ void drawCallback_LINE(const Common::Rect &area, const DrawStep &step) {
+ uint16 x, y, w, h;
+ stepGetPositions(step, area, x, y, w, h);
+ drawLine(x, y, x + w, y + w);
+ }
+
+ void drawCallback_ROUNDSQ(const Common::Rect &area, const DrawStep &step) {
+ uint16 x, y, w, h;
+ stepGetPositions(step, area, x, y, w, h);
+ drawRoundedSquare(x, y, stepGetRadius(step, area), w, h);
+ }
+
+ void drawCallback_FILLSURFACE(const Common::Rect &area, const DrawStep &step) {
+ fillSurface();
+ }
+
+ void drawCallback_TRIANGLE(const Common::Rect &area, const DrawStep &step) {
+ uint16 x, y, w, h;
+ stepGetPositions(step, area, x, y, w, h);
+ drawTriangle(x, y, w, h, (TriangleOrientation)step.extraData);
+ }
+
+ void drawCallback_BEVELSQ(const Common::Rect &area, const DrawStep &step) {
+ uint16 x, y, w, h;
+ stepGetPositions(step, area, x, y, w, h);
+ drawBeveledSquare(x, y, w, h, _bevel);
+ }
+
+ void drawCallback_TAB(const Common::Rect &area, const DrawStep &step) {
+ uint16 x, y, w, h;
+ stepGetPositions(step, area, x, y, w, h);
+ drawTab(x, y, stepGetRadius(step, area), w, h);
+ }
+
+ void drawCallback_BITMAP(const Common::Rect &area, const DrawStep &step) {
+ uint16 x, y, w, h;
+ stepGetPositions(step, area, x, y, w, h);
+ blitAlphaBitmap(step.blitSrc, Common::Rect(x, y, x + w, y + h));
+ }
+
+ void drawCallback_CROSS(const Common::Rect &area, const DrawStep &step) {
+ uint16 x, y, w, h;
+ stepGetPositions(step, area, x, y, w, h);
+ drawCross(x, y, w, h);
+ }
+
+ void drawCallback_VOID(const Common::Rect &area, const DrawStep &step) {}
+
+ /**
+ * Draws the specified draw step on the screen.
+ *
+ * @see DrawStep
+ * @param area Zone to paint on
+ * @param step Pointer to a DrawStep struct.
+ */
+ virtual void drawStep(const Common::Rect &area, const DrawStep &step, uint32 extra = 0);
+
+ /**
+ * Copies the part of the current frame to the system overlay.
+ *
+ * @param sys Pointer to the global System class
+ * @param r Zone of the surface to copy into the overlay.
+ */
+ virtual void copyFrame(OSystem *sys, const Common::Rect &r) = 0;
+
+ /**
+ * Copies the current surface to the system overlay
+ *
+ * @param sys Pointer to the global System class
+ */
+ virtual void copyWholeFrame(OSystem *sys) = 0;
+
+ /**
+ * Blits a given graphics surface on top of the current drawing surface.
+ *
+ * Note that the source surface and the active
+ * surface are expected to be of the same size, hence the area delimited
+ * by "r" in the source surface will be blitted into the area delimited by
+ * "r" on the current surface.
+ *
+ * If you wish to blit a smaller surface into the active drawing area, use
+ * VectorRenderer::blitSubSurface().
+ *
+ * @param source Surface to blit into the drawing surface.
+ * @param r Position in the active drawing surface to do the blitting.
+ */
+ virtual void blitSurface(const Graphics::Surface *source, const Common::Rect &r) = 0;
+
+ /**
+ * Blits a given graphics surface into a small area of the current drawing surface.
+ *
+ * Note that the given surface is expected to be smaller than the
+ * active drawing surface, hence the WHOLE source surface will be
+ * blitted into the active surface, at the position specified by "r".
+ */
+ virtual void blitSubSurface(const Graphics::Surface *source, const Common::Rect &r) = 0;
+
+ virtual void blitAlphaBitmap(const Graphics::Surface *source, const Common::Rect &r) = 0;
+
+ /**
+ * Draws a string into the screen. Wrapper for the Graphics::Font string drawing
+ * method.
+ */
+ virtual void drawString(const Graphics::Font *font, const Common::String &text,
+ const Common::Rect &area, GUI::Theme::TextAlign alignH,
+ GUI::Theme::TextAlignVertical alignV, int deltax, bool useEllipsis) = 0;
+
+ /**
+ * Allows to temporarily enable/disable all shadows drawing.
+ * i.e. for performance issues, blitting, etc
+ */
+ virtual void disableShadows() { _disableShadows = true; }
+ virtual void enableShadows() { _disableShadows = false; }
+
+ /**
+ * Applies a convolution matrix on the given surface area.
+ * Call applyConvolutionMatrix() instead if you want to use
+ * the embeded matrixes (blur/sharpen masks, bevels, etc).
+ *
+ * @param area Area in which the convolution matrix will be applied.
+ * @param filter Convolution matrix (3X3)
+ * @param filterDiv Divisor for the convolution matrix.
+ * Make sure this equals the total sum of the elements
+ * of the matrix or brightness data will be distorted.
+ * @param offset Offset on the convolution area.
+ */
+ virtual void areaConvolution(const Common::Rect &area, const int filter[3][3], int filterDiv, int offset) = 0;
+
+ /**
+ * Applies one of the predefined convolution effects on the given area.
+ *
+ * WARNING: Because of performance issues, this is currently disabled on all renderers.
+ *
+ * @param id Id of the convolution data set (see VectorRenderer::ConvolutionData)
+ * @param area Area in which the convolution effect will be applied.
+ */
+ virtual void applyConvolutionMatrix(const ConvolutionData id, const Common::Rect &area) {
+ areaConvolution(area, _convolutionData[id].matrix, _convolutionData[id].divisor, _convolutionData[id].offset);
+ }
+
+ /**
+ * Applies a whole-screen shading effect, used before opening a new dialog.
+ * Currently supports screen dimmings and luminance (b&w).
+ */
+ virtual void applyScreenShading(GUI::Theme::ShadingStyle) = 0;
+
+protected:
+ Surface *_activeSurface; /** Pointer to the surface currently being drawn */
+
+ FillMode _fillMode; /** Defines in which way (if any) are filled the drawn shapes */
+
+ int _shadowOffset; /** offset for drawn shadows */
+ int _bevel; /** amount of fake bevel */
+ bool _disableShadows; /** Disables temporarily shadow drawing for overlayed images. */
+ int _strokeWidth; /** Width of the stroke of all drawn shapes */
+ uint32 _dynamicData; /** Dynamic data from the GUI Theme that modifies the drawing of the current shape */
+
+ int _gradientFactor; /** Multiplication factor of the active gradient */
+ int _gradientBytes[3]; /** Color bytes of the active gradient, used to speed up calculation */
+
+ static const ConvolutionDataSet _convolutionData[kConvolutionMAX];
+
+ static const int _dimPercentValue = 256 * 50 / 100; /** default value for screen dimming (50%) */
+};
+
+} // end of namespace Graphics
+
+#endif
diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp
new file mode 100644
index 0000000000..9884fcfd2d
--- /dev/null
+++ b/graphics/VectorRendererSpec.cpp
@@ -0,0 +1,1591 @@
+/* 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 "common/system.h"
+#include "common/events.h"
+
+#include "graphics/surface.h"
+#include "graphics/colormasks.h"
+
+#include "gui/ThemeEngine.h"
+#include "graphics/VectorRenderer.h"
+#include "graphics/VectorRendererSpec.h"
+
+#define VECTOR_RENDERER_FAST_TRIANGLES
+
+/** Fixed point SQUARE ROOT **/
+inline uint32 fp_sqroot(uint32 x) {
+ register uint32 root, remHI, remLO, testDIV, count;
+
+ root = 0;
+ remHI = 0;
+ remLO = x;
+ count = 23;
+
+ do {
+ remHI = (remHI << 2) | (remLO >> 30);
+ remLO <<= 2;
+ root <<= 1;
+ testDIV = (root << 1) + 1;
+
+ if (remHI >= testDIV) {
+ remHI -= testDIV;
+ root++;
+ }
+ } while (count--);
+
+ return root;
+}
+
+/*
+ HELPER MACROS for Bresenham's circle drawing algorithm
+ Note the proper spelling on this header.
+*/
+#define __BE_ALGORITHM() { \
+ if (f >= 0) { \
+ y--; \
+ ddF_y += 2; \
+ f += ddF_y; \
+ py -= pitch; \
+ } \
+ px += pitch; \
+ ddF_x += 2; \
+ f += ddF_x + 1; \
+}
+
+#define __BE_DRAWCIRCLE(ptr1,ptr2,ptr3,ptr4,x,y,px,py) { \
+ *(ptr1 + (y) - (px)) = color; \
+ *(ptr1 + (x) - (py)) = color; \
+ *(ptr2 - (x) - (py)) = color; \
+ *(ptr2 - (y) - (px)) = color; \
+ *(ptr3 - (y) + (px)) = color; \
+ *(ptr3 - (x) + (py)) = color; \
+ *(ptr4 + (x) + (py)) = color; \
+ *(ptr4 + (y) + (px)) = color; \
+}
+
+#define __BE_DRAWCIRCLE_XCOLOR(ptr1,ptr2,ptr3,ptr4,x,y,px,py) { \
+ *(ptr1 + (y) - (px)) = color1; \
+ *(ptr1 + (x) - (py)) = color2; \
+ *(ptr2 - (x) - (py)) = color2; \
+ *(ptr2 - (y) - (px)) = color1; \
+ *(ptr3 - (y) + (px)) = color3; \
+ *(ptr3 - (x) + (py)) = color4; \
+ *(ptr4 + (x) + (py)) = color4; \
+ *(ptr4 + (y) + (px)) = color3; \
+}
+
+#define __BE_RESET() { \
+ f = 1 - r; \
+ ddF_x = 0; ddF_y = -2 * r; \
+ x = 0; y = r; px = 0; py = pitch * r; \
+}
+
+#define __TRIANGLE_MAINX() \
+ if (error_term >= 0) { \
+ ptr_right += pitch; \
+ ptr_left += pitch; \
+ error_term += dysub; \
+ } else { \
+ error_term += ddy; \
+ } \
+ ptr_right++; \
+ ptr_left--;
+
+#define __TRIANGLE_MAINY() \
+ if (error_term >= 0) { \
+ ptr_right++; \
+ ptr_left--; \
+ error_term += dxsub; \
+ } else { \
+ error_term += ddx; \
+ } \
+ ptr_right += pitch; \
+ ptr_left += pitch;
+
+/** HELPER MACROS for WU's circle drawing algorithm **/
+#define __WU_DRAWCIRCLE(ptr1,ptr2,ptr3,ptr4,x,y,px,py,a) { \
+ blendPixelPtr(ptr1 + (y) - (px), color, a); \
+ blendPixelPtr(ptr1 + (x) - (py), color, a); \
+ blendPixelPtr(ptr2 - (x) - (py), color, a); \
+ blendPixelPtr(ptr2 - (y) - (px), color, a); \
+ blendPixelPtr(ptr3 - (y) + (px), color, a); \
+ blendPixelPtr(ptr3 - (x) + (py), color, a); \
+ blendPixelPtr(ptr4 + (x) + (py), color, a); \
+ blendPixelPtr(ptr4 + (y) + (px), color, a); \
+}
+
+// optimized Wu's algorithm
+#define __WU_ALGORITHM() { \
+ oldT = T; \
+ T = fp_sqroot(rsq - ((y * y) << 16)) ^ 0xFFFF; \
+ py += p; \
+ if (T < oldT) { \
+ x--; px -= p; \
+ } \
+ a2 = (T >> 8); \
+ a1 = ~a2; \
+}
+
+
+
+namespace Graphics {
+
+VectorRenderer *createRenderer(int mode) {
+ switch (mode) {
+ case GUI::ThemeEngine::kGfxStandard16bit:
+ return new VectorRendererSpec<uint16, ColorMasks<565> >;
+
+ case GUI::ThemeEngine::kGfxAntialias16bit:
+ return new VectorRendererAA<uint16, ColorMasks<565> >;
+
+ default:
+ return 0;
+ }
+}
+
+template <typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+areaConvolution(const Common::Rect &area, const int filter[3][3], int filterDiv, int offset) {
+ PixelType *ptr = 0;
+ int newR, newG, newB;
+ uint8 r, g, b;
+ int yVal;
+
+ for (int y = area.top; y < area.bottom; ++y) {
+ for (int x = area.left; x < area.right; ++x) {
+ newR = newG = newB = 0;
+
+ for (int j = 0; j < 3; ++j) {
+ yVal = MIN(MAX(y - 1 + j, 0), area.bottom - 1);
+
+ for (int i = 0; i < 3; ++i) {
+ ptr = (PixelType *)Base::_activeSurface->getBasePtr(MIN(MAX(x - 1 + j, 0), area.right - 1), yVal);
+ colorToRGB<PixelFormat>((uint32)*ptr, r, g, b);
+
+ newR += r * filter[j][i];
+ newG += g * filter[j][i];
+ newB += b * filter[j][i];
+ }
+ }
+
+ newR = (newR / filterDiv) + offset;
+ newG = (newG / filterDiv) + offset;
+ newB = (newB / filterDiv) + offset;
+
+ ptr = (PixelType *)Base::_activeSurface->getBasePtr(x, y);
+ *ptr = RGBToColor<PixelFormat>(CLIP(newR, 0, 255), CLIP(newG, 0, 255), CLIP(newB, 0, 255));
+ }
+ }
+}
+
+template <typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+setGradientColors(uint8 r1, uint8 g1, uint8 b1, uint8 r2, uint8 g2, uint8 b2) {
+ _gradientEnd = RGBToColor<PixelFormat>(r2, g2, b2);
+ _gradientStart = RGBToColor<PixelFormat>(r1, g1, b1);
+
+ Base::_gradientBytes[0] = (_gradientEnd & PixelFormat::kRedMask) - (_gradientStart & PixelFormat::kRedMask);
+ Base::_gradientBytes[1] = (_gradientEnd & PixelFormat::kGreenMask) - (_gradientStart & PixelFormat::kGreenMask);
+ Base::_gradientBytes[2] = (_gradientEnd & PixelFormat::kBlueMask) - (_gradientStart & PixelFormat::kBlueMask);
+}
+
+template <typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+fillSurface() {
+ PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(0, 0);
+
+ int w = _activeSurface->w;
+ int h = _activeSurface->h ;
+ int pitch = surfacePitch();
+
+ if (Base::_fillMode == kFillBackground)
+ colorFill(ptr, ptr + w * h, _bgColor);
+ else if (Base::_fillMode == kFillForeground)
+ colorFill(ptr, ptr + w * h, _fgColor);
+ else if (Base::_fillMode == kFillGradient) {
+ int i = h;
+ while (i--) {
+ colorFill(ptr, ptr + w, calcGradient(h - i, h));
+ ptr += pitch;
+ }
+ }
+}
+
+template <typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+copyFrame(OSystem *sys, const Common::Rect &r) {
+
+ sys->copyRectToOverlay(
+
+#ifdef OVERLAY_MULTIPLE_DEPTHS
+ (const PixelType*)
+#else
+ (const OverlayColor*)
+#endif
+
+ _activeSurface->getBasePtr(r.left, r.top), _activeSurface->w,
+ r.left, r.top, r.width(), r.height()
+ );
+}
+
+template <typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+blitSurface(const Graphics::Surface *source, const Common::Rect &r) {
+ assert(source->w == _activeSurface->w && source->h == _activeSurface->h);
+
+ PixelType *dst_ptr = (PixelType *)_activeSurface->getBasePtr(r.left, r.top);
+ PixelType *src_ptr = (PixelType *)source->getBasePtr(r.left, r.top);
+
+ int dst_pitch = surfacePitch();
+ int src_pitch = source->pitch / source->bytesPerPixel;
+
+ int h = r.height(), w = r.width();
+
+ while (h--) {
+ memcpy(dst_ptr, src_ptr, w * sizeof(PixelType));
+ dst_ptr += dst_pitch;
+ src_ptr += src_pitch;
+ }
+}
+
+template <typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+blitSubSurface(const Graphics::Surface *source, const Common::Rect &r) {
+ PixelType *dst_ptr = (PixelType *)_activeSurface->getBasePtr(r.left, r.top);
+ PixelType *src_ptr = (PixelType *)source->getBasePtr(0, 0);
+
+ int dst_pitch = surfacePitch();
+ int src_pitch = source->pitch / source->bytesPerPixel;
+
+ int h = r.height(), w = r.width();
+
+ while (h--) {
+ memcpy(dst_ptr, src_ptr, w * sizeof(PixelType));
+ dst_ptr += dst_pitch;
+ src_ptr += src_pitch;
+ }
+}
+
+template <typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+blitAlphaBitmap(const Graphics::Surface *source, const Common::Rect &r) {
+ int16 x = r.left;
+ int16 y = r.top;
+
+ if (r.width() > source->w)
+ x = x + (r.width() >> 1) - (source->w >> 1);
+
+ if (r.height() > source->h)
+ y = y + (r.height() >> 1) - (source->h >> 1);
+
+ PixelType *dst_ptr = (PixelType *)_activeSurface->getBasePtr(x, y);
+ PixelType *src_ptr = (PixelType *)source->getBasePtr(0, 0);
+
+ int dst_pitch = surfacePitch();
+ int src_pitch = source->pitch / source->bytesPerPixel;
+
+ int w, h = source->h;
+
+ while (h--) {
+ w = source->w;
+
+ while (w--) {
+ if (*src_ptr != _bitmapAlphaColor)
+ *dst_ptr = *src_ptr;
+
+ dst_ptr++;
+ src_ptr++;
+ }
+
+ dst_ptr = dst_ptr - source->w + dst_pitch;
+ src_ptr = src_ptr - source->w + src_pitch;
+ }
+}
+
+template <typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+applyScreenShading(GUI::Theme::ShadingStyle shadingStyle) {
+ int pixels = _activeSurface->w * _activeSurface->h;
+ PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(0, 0);
+ uint8 r, g, b;
+ uint lum;
+
+ const uint32 shiftMask = (uint32)~(
+ (1 << PixelFormat::kGreenShift) |
+ (1 << PixelFormat::kRedShift) |
+ (1 << PixelFormat::kBlueShift)) >> 1;
+
+ if (shadingStyle == GUI::Theme::kShadingDim) {
+
+ int n = (pixels + 7) >> 3;
+ switch (pixels % 8) {
+ case 0: do {
+ *ptr = (*ptr >> 1) & shiftMask; ++ptr;
+ case 7: *ptr = (*ptr >> 1) & shiftMask; ++ptr;
+ case 6: *ptr = (*ptr >> 1) & shiftMask; ++ptr;
+ case 5: *ptr = (*ptr >> 1) & shiftMask; ++ptr;
+ case 4: *ptr = (*ptr >> 1) & shiftMask; ++ptr;
+ case 3: *ptr = (*ptr >> 1) & shiftMask; ++ptr;
+ case 2: *ptr = (*ptr >> 1) & shiftMask; ++ptr;
+ case 1: *ptr = (*ptr >> 1) & shiftMask; ++ptr;
+ } while (--n > 0);
+ }
+
+ } else if (shadingStyle == GUI::Theme::kShadingLuminance) {
+ while (pixels--) {
+ colorToRGB<PixelFormat>(*ptr, r, g, b);
+ lum = (r >> 2) + (g >> 1) + (b >> 3);
+ *ptr++ = RGBToColor<PixelFormat>(lum, lum, lum);
+ }
+ }
+}
+
+template <typename PixelType, typename PixelFormat>
+inline void VectorRendererSpec<PixelType, PixelFormat>::
+blendPixelPtr(PixelType *ptr, PixelType color, uint8 alpha) {
+ register int idst = *ptr;
+ register int isrc = color;
+
+ *ptr = (PixelType)(
+ (PixelFormat::kRedMask & ((idst & PixelFormat::kRedMask) +
+ ((int)(((int)(isrc & PixelFormat::kRedMask) -
+ (int)(idst & PixelFormat::kRedMask)) * alpha) >> 8))) |
+ (PixelFormat::kGreenMask & ((idst & PixelFormat::kGreenMask) +
+ ((int)(((int)(isrc & PixelFormat::kGreenMask) -
+ (int)(idst & PixelFormat::kGreenMask)) * alpha) >> 8))) |
+ (PixelFormat::kBlueMask & ((idst & PixelFormat::kBlueMask) +
+ ((int)(((int)(isrc & PixelFormat::kBlueMask) -
+ (int)(idst & PixelFormat::kBlueMask)) * alpha) >> 8))) );
+}
+
+template <typename PixelType, typename PixelFormat>
+inline PixelType VectorRendererSpec<PixelType, PixelFormat>::
+calcGradient(uint32 pos, uint32 max) {
+ PixelType output = 0;
+ pos = (MIN(pos * Base::_gradientFactor, max) << 12) / max;
+
+ output |= (_gradientStart + ((Base::_gradientBytes[0] * pos) >> 12)) & PixelFormat::kRedMask;
+ output |= (_gradientStart + ((Base::_gradientBytes[1] * pos) >> 12)) & PixelFormat::kGreenMask;
+ output |= (_gradientStart + ((Base::_gradientBytes[2] * pos) >> 12)) & PixelFormat::kBlueMask;
+ output |= ~(PixelFormat::kRedMask | PixelFormat::kGreenMask | PixelFormat::kBlueMask);
+
+ return output;
+}
+
+template <typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+colorFill(PixelType *first, PixelType *last, PixelType color) {
+ register int count = (last - first);
+ register int n = (count + 7) >> 3;
+ switch (count % 8) {
+ case 0: do {
+ *first++ = color;
+ case 7: *first++ = color;
+ case 6: *first++ = color;
+ case 5: *first++ = color;
+ case 4: *first++ = color;
+ case 3: *first++ = color;
+ case 2: *first++ = color;
+ case 1: *first++ = color;
+ } while (--n > 0);
+ }
+}
+
+/********************************************************************
+ ********************************************************************
+ * Primitive shapes drawing - Public API calls - VectorRendererSpec *
+ ********************************************************************
+ ********************************************************************/
+template <typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+drawString(const Graphics::Font *font, const Common::String &text, const Common::Rect &area,
+ GUI::Theme::TextAlign alignH, GUI::Theme::TextAlignVertical alignV, int deltax, bool ellipsis) {
+
+ int offset = area.top;
+
+ if (font->getFontHeight() < area.height()) {
+ switch (alignV) {
+ case GUI::Theme::kTextAlignVCenter:
+ offset = area.top + ((area.height() - font->getFontHeight()) >> 1);
+ break;
+ case GUI::Theme::kTextAlignVBottom:
+ offset = area.bottom - font->getFontHeight();
+ break;
+ default:
+ break;
+ }
+ }
+
+ font->drawString(_activeSurface, text, area.left, offset, area.width(), _fgColor, (Graphics::TextAlignment)alignH, deltax, ellipsis);
+}
+
+/** LINES **/
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+drawLine(int x1, int y1, int x2, int y2) {
+ x1 = CLIP(x1, 0, (int)Base::_activeSurface->w);
+ x2 = CLIP(x2, 0, (int)Base::_activeSurface->w);
+ y1 = CLIP(y1, 0, (int)Base::_activeSurface->h);
+ y2 = CLIP(y2, 0, (int)Base::_activeSurface->h);
+
+ // we draw from top to bottom
+ if (y2 < y1) {
+ SWAP(x1, x2);
+ SWAP(y1, y2);
+ }
+
+ int dx = ABS(x2 - x1);
+ int dy = ABS(y2 - y1);
+
+ // this is a point, not a line. stoopid.
+ if (dy == 0 && dx == 0)
+ return;
+
+ if (Base::_strokeWidth == 0)
+ return;
+
+ PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1);
+ int pitch = Base::surfacePitch();
+ int st = Base::_strokeWidth >> 1;
+
+ if (dy == 0) { // horizontal lines
+ // these can be filled really fast with a single memset.
+ colorFill(ptr, ptr + dx + 1, (PixelType)_fgColor);
+
+ for (int i = 0, p = pitch; i < st; ++i, p += pitch) {
+ colorFill(ptr + p, ptr + dx + 1 + p, (PixelType)_fgColor);
+ colorFill(ptr - p, ptr + dx + 1 - p, (PixelType)_fgColor);
+ }
+
+ } else if (dx == 0) { // vertical lines
+ // these ones use a static pitch increase.
+ while (y1++ <= y2) {
+ colorFill(ptr - st, ptr + st, (PixelType)_fgColor);
+ ptr += pitch;
+ }
+
+ } else if (ABS(dx) == ABS(dy)) { // diagonal lines
+ // these ones also use a fixed pitch increase
+ pitch += (x2 > x1) ? 1 : -1;
+
+ while (dy--) {
+ colorFill(ptr - st, ptr + st, (PixelType)_fgColor);
+ ptr += pitch;
+ }
+
+ } else { // generic lines, use the standard algorithm...
+ drawLineAlg(x1, y1, x2, y2, dx, dy, (PixelType)_fgColor);
+ }
+}
+
+/** CIRCLES **/
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+drawCircle(int x, int y, int r) {
+ if (x + r > Base::_activeSurface->w || y + r > Base::_activeSurface->h ||
+ x - r < 0 || y - r < 0 || x == 0 || y == 0 || r <= 0)
+ return;
+
+ if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
+ && x + r + Base::_shadowOffset < Base::_activeSurface->w
+ && y + r + Base::_shadowOffset < Base::_activeSurface->h) {
+ drawCircleAlg(x + Base::_shadowOffset + 1, y + Base::_shadowOffset + 1, r, 0, kFillForeground);
+ }
+
+ switch (Base::_fillMode) {
+ case kFillDisabled:
+ if (Base::_strokeWidth)
+ drawCircleAlg(x, y, r, _fgColor, kFillDisabled);
+ break;
+
+ case kFillForeground:
+ drawCircleAlg(x, y, r, _fgColor, kFillForeground);
+ break;
+
+ case kFillBackground:
+ if (Base::_strokeWidth > 1) {
+ drawCircleAlg(x, y, r, _fgColor, kFillForeground);
+ drawCircleAlg(x, y, r - Base::_strokeWidth, _bgColor, kFillBackground);
+ } else {
+ drawCircleAlg(x, y, r, _bgColor, kFillBackground);
+ drawCircleAlg(x, y, r, _fgColor, kFillDisabled);
+ }
+ break;
+
+ case kFillGradient:
+ break;
+ }
+}
+
+/** SQUARES **/
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+drawSquare(int x, int y, int w, int h) {
+ if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h ||
+ w <= 0 || h <= 0 || x < 0 || y < 0)
+ return;
+
+ if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
+ && x + w + Base::_shadowOffset < Base::_activeSurface->w
+ && y + h + Base::_shadowOffset < Base::_activeSurface->h) {
+ drawSquareShadow(x, y, w, h, Base::_shadowOffset);
+ }
+
+ switch (Base::_fillMode) {
+ case kFillDisabled:
+ if (Base::_strokeWidth)
+ drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled);
+ break;
+
+ case kFillForeground:
+ drawSquareAlg(x, y, w, h, _fgColor, kFillForeground);
+ break;
+
+ case kFillBackground:
+ drawSquareAlg(x, y, w, h, _bgColor, kFillBackground);
+ drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled);
+ break;
+
+ case kFillGradient:
+ VectorRendererSpec::drawSquareAlg(x, y, w, h, 0, kFillGradient);
+ if (Base::_strokeWidth)
+ drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled);
+ break;
+ }
+}
+
+/** ROUNDED SQUARES **/
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+drawRoundedSquare(int x, int y, int r, int w, int h) {
+ if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h ||
+ w <= 0 || h <= 0 || x < 0 || y < 0 || r <= 0)
+ return;
+
+ if ((r << 1) > w || (r << 1) > h)
+ r = MIN(w >> 1, h >> 1);
+
+ if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
+ && x + w + Base::_shadowOffset < Base::_activeSurface->w
+ && y + h + Base::_shadowOffset < Base::_activeSurface->h) {
+ drawRoundedSquareShadow(x, y, r, w, h, Base::_shadowOffset);
+ }
+
+ switch (Base::_fillMode) {
+ case kFillDisabled:
+ if (Base::_strokeWidth)
+ drawRoundedSquareAlg(x, y, r, w, h, _fgColor, kFillDisabled);
+ break;
+
+ case kFillForeground:
+ drawRoundedSquareAlg(x, y, r, w, h, _fgColor, kFillForeground);
+ break;
+
+ case kFillBackground:
+ VectorRendererSpec::drawRoundedSquareAlg(x, y, r, w, h, _bgColor, kFillBackground);
+ drawRoundedSquareAlg(x, y, r, w, h, _fgColor, kFillDisabled);
+ break;
+
+ case kFillGradient:
+ if (Base::_strokeWidth > 1) {
+ drawRoundedSquareAlg(x, y, r, w, h, _fgColor, kFillForeground);
+ VectorRendererSpec::drawRoundedSquareAlg(x + Base::_strokeWidth/2, y + Base::_strokeWidth/2,
+ r - Base::_strokeWidth/2, w - Base::_strokeWidth, h - Base::_strokeWidth, 0, kFillGradient);
+ } else {
+ VectorRendererSpec::drawRoundedSquareAlg(x, y, r, w, h, 0, kFillGradient);
+ if (Base::_strokeWidth)
+ drawRoundedSquareAlg(x, y, r, w, h, _fgColor, kFillDisabled);
+ }
+ break;
+ }
+
+ if (Base::_bevel)
+ drawRoundedSquareFakeBevel(x, y, r, w, h, Base::_bevel);
+}
+
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+drawTab(int x, int y, int r, int w, int h) {
+ if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h ||
+ w <= 0 || h <= 0 || x < 0 || y < 0 || r > w || r > h)
+ return;
+
+ if (r == 0 && Base::_bevel > 0) {
+ drawBevelTabAlg(x, y, w, h, Base::_bevel, _bevelColor, _fgColor, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF));
+ return;
+ }
+
+ if (r == 0) return;
+
+ switch (Base::_fillMode) {
+ case kFillDisabled:
+ return;
+
+ case kFillGradient:
+ case kFillBackground:
+ drawTabAlg(x, y, w, h, r, (Base::_fillMode == kFillBackground) ? _bgColor : _fgColor, Base::_fillMode);
+ if (Base::_strokeWidth)
+ drawTabAlg(x, y, w, h, r, _fgColor, kFillDisabled, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF));
+ break;
+
+ case kFillForeground:
+ drawTabAlg(x, y, w, h, r, (Base::_fillMode == kFillBackground) ? _bgColor : _fgColor, Base::_fillMode);
+ break;
+ }
+}
+
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+drawTriangle(int x, int y, int w, int h, TriangleOrientation orient) {
+
+ if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h)
+ return;
+
+ PixelType color = 0;
+
+ if (Base::_strokeWidth <= 1) {
+ if (Base::_fillMode == kFillForeground)
+ color = _fgColor;
+ else if (Base::_fillMode == kFillBackground)
+ color = _bgColor;
+ } else {
+ if (Base::_fillMode == kFillDisabled)
+ return;
+ color = _fgColor;
+ }
+
+ if (Base::_dynamicData != 0)
+ orient = (TriangleOrientation)Base::_dynamicData;
+
+ int newW = w / 2;
+ if (newW % 2) newW++;
+
+ switch(orient) {
+ case kTriangleUp:
+ case kTriangleDown:
+ drawTriangleFast(x + (newW / 2), y + (h / 2) - (newW / 2), newW, (orient == kTriangleDown), color, Base::_fillMode);
+ break;
+
+ case kTriangleLeft:
+ case kTriangleRight:
+ case kTriangleAuto:
+ break;
+ }
+
+ if (Base::_strokeWidth > 0)
+ if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillGradient) {
+ drawTriangleFast(x + (newW / 2), y + (h / 2) - (newW / 2), newW, (orient == kTriangleDown), _fgColor, kFillDisabled);
+ }
+}
+
+
+
+
+
+/********************************************************************
+ ********************************************************************
+ * Aliased Primitive drawing ALGORITHMS - VectorRendererSpec
+ ********************************************************************
+ ********************************************************************/
+/** TAB ALGORITHM - NON AA */
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer::FillMode fill_m, int baseLeft, int baseRight) {
+ int f, ddF_x, ddF_y;
+ int x, y, px, py;
+ int pitch = Base::surfacePitch();
+ int sw = 0, sp = 0, hp = 0;
+
+ PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
+ PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
+ PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
+
+ int real_radius = r;
+ int short_h = h - r + 2;
+ int long_h = h;
+
+ if (fill_m == kFillDisabled) {
+ while (sw++ < Base::_strokeWidth) {
+ colorFill(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color);
+ colorFill(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color);
+ sp += pitch;
+
+ __BE_RESET();
+ r--;
+
+ while (x++ < y) {
+ __BE_ALGORITHM();
+ *(ptr_tr + (y) - (px)) = color;
+ *(ptr_tr + (x) - (py)) = color;
+ *(ptr_tl - (x) - (py)) = color;
+ *(ptr_tl - (y) - (px)) = color;
+
+ if (Base::_strokeWidth > 1) {
+ *(ptr_tr + (y) - (px - pitch)) = color;
+ *(ptr_tr + (x) - (py)) = color;
+ *(ptr_tl - (x) - (py)) = color;
+ *(ptr_tl - (y) - (px - pitch)) = color;
+ }
+ }
+ }
+
+ ptr_fill += pitch * real_radius;
+ while (short_h--) {
+ colorFill(ptr_fill, ptr_fill + Base::_strokeWidth - 1, color);
+ colorFill(ptr_fill + w - Base::_strokeWidth + 2, ptr_fill + w, color);
+ ptr_fill += pitch;
+ }
+
+ if (baseLeft) {
+ sw = 0;
+ ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + h);
+ while (sw++ < Base::_strokeWidth) {
+ colorFill(ptr_fill - baseLeft, ptr_fill, color);
+ ptr_fill += pitch;
+ }
+ }
+
+ if (baseRight) {
+ sw = 0;
+ ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w, y1 + h);
+ while (sw++ < Base::_strokeWidth) {
+ colorFill(ptr_fill, ptr_fill + baseRight, color);
+ ptr_fill += pitch;
+ }
+ }
+ } else {
+ __BE_RESET();
+
+ PixelType color1, color2;
+ color1 = color2 = color;
+
+ while (x++ < y) {
+ __BE_ALGORITHM();
+
+ if (fill_m == kFillGradient) {
+ color1 = calcGradient(real_radius - x, long_h);
+ color2 = calcGradient(real_radius - y, long_h);
+ }
+
+ colorFill(ptr_tl - x - py, ptr_tr + x - py, color2);
+ colorFill(ptr_tl - y - px, ptr_tr + y - px, color1);
+
+ *(ptr_tr + (y) - (px)) = color1;
+ *(ptr_tr + (x) - (py)) = color2;
+ *(ptr_tl - (x) - (py)) = color2;
+ *(ptr_tl - (y) - (px)) = color1;
+ }
+
+ ptr_fill += pitch * r;
+ while (short_h--) {
+ if (fill_m == kFillGradient)
+ color = calcGradient(real_radius++, long_h);
+ colorFill(ptr_fill, ptr_fill + w + 1, color);
+ ptr_fill += pitch;
+ }
+ }
+}
+
+
+/** BEVELED TABS FOR CLASSIC THEME **/
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+drawBevelTabAlg(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color, int baseLeft, int baseRight) {
+ int pitch = Base::surfacePitch();
+ int i, j;
+
+ PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
+
+ i = bevel;
+ while (i--) {
+ colorFill(ptr_left, ptr_left + w, top_color);
+ ptr_left += pitch;
+ }
+
+ if (baseLeft > 0) {
+ i = h - bevel;
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
+ while (i--) {
+ colorFill(ptr_left, ptr_left + bevel, top_color);
+ ptr_left += pitch;
+ }
+ }
+
+ i = h - bevel;
+ j = bevel;
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y);
+ while (i--) {
+ colorFill(ptr_left + j, ptr_left + bevel, bottom_color);
+ if (j > 0) j--;
+ ptr_left += pitch;
+ }
+
+ i = bevel;
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y + h - bevel);
+ while (i--) {
+ colorFill(ptr_left, ptr_left + baseRight + bevel, bottom_color);
+
+ if (baseLeft)
+ colorFill(ptr_left - w - baseLeft + bevel, ptr_left - w + bevel + bevel, top_color);
+ ptr_left += pitch;
+ }
+}
+
+/** SQUARE ALGORITHM **/
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+drawSquareAlg(int x, int y, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
+ PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x, y);
+ int pitch = Base::surfacePitch();
+ int max_h = h;
+
+ if (fill_m != kFillDisabled) {
+ while (h--) {
+ if (fill_m == kFillGradient)
+ color = calcGradient(max_h - h, max_h);
+
+ colorFill(ptr, ptr + w, color);
+ ptr += pitch;
+ }
+ } else {
+ int sw = Base::_strokeWidth, sp = 0, hp = pitch * (h - 1);
+
+ while (sw--) {
+ colorFill(ptr + sp, ptr + w + sp, color);
+ colorFill(ptr + hp - sp, ptr + w + hp - sp, color);
+ sp += pitch;
+ }
+
+ while (h--) {
+ colorFill(ptr, ptr + Base::_strokeWidth, color);
+ colorFill(ptr + w - Base::_strokeWidth, ptr + w, color);
+ ptr += pitch;
+ }
+ }
+}
+
+/** SQUARE ALGORITHM **/
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+drawBevelSquareAlg(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color, bool fill) {
+ int pitch = Base::surfacePitch();
+
+ int height = h;
+ PixelType *ptr_fill = (PixelType *)_activeSurface->getBasePtr(x, y);
+
+ if (fill) {
+ while (height--) {
+ blendFill(ptr_fill, ptr_fill + w, _bgColor, 200);
+ ptr_fill += pitch;
+ }
+ }
+
+ int i, j;
+ x = MAX(x - bevel, 0);
+ y = MAX(y - bevel, 0);
+ h += bevel << 1;
+ w += bevel << 1;
+
+ PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
+
+ i = bevel;
+ while (i--) {
+ colorFill(ptr_left, ptr_left + w, top_color);
+ ptr_left += pitch;
+ }
+
+ i = h - bevel;
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + bevel);
+ while (i--) {
+ colorFill(ptr_left, ptr_left + bevel, top_color);
+ ptr_left += pitch;
+ }
+
+ i = bevel;
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + h - bevel);
+ while (i--) {
+ colorFill(ptr_left + i, ptr_left + w, bottom_color);
+ ptr_left += pitch;
+ }
+
+ i = h - bevel;
+ j = bevel - 1;
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y);
+ while (i--) {
+ colorFill(ptr_left + j, ptr_left + bevel, bottom_color);
+ if (j > 0) j--;
+ ptr_left += pitch;
+ }
+}
+
+/** GENERIC LINE ALGORITHM **/
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType,PixelFormat>::
+drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) {
+ PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1);
+ int pitch = Base::surfacePitch();
+ int xdir = (x2 > x1) ? 1 : -1;
+
+ *ptr = (PixelType)color;
+
+ if (dx > dy) {
+ int ddy = dy * 2;
+ int dysub = ddy - (dx * 2);
+ int error_term = ddy - dx;
+
+ while (dx--) {
+ if (error_term >= 0) {
+ ptr += pitch;
+ error_term += dysub;
+ } else {
+ error_term += ddy;
+ }
+
+ ptr += xdir;
+ *ptr = (PixelType)color;
+ }
+ } else {
+ int ddx = dx * 2;
+ int dxsub = ddx - (dy * 2);
+ int error_term = ddx - dy;
+
+ while (dy--) {
+ if (error_term >= 0) {
+ ptr += xdir;
+ error_term += dxsub;
+ } else {
+ error_term += ddx;
+ }
+
+ ptr += pitch;
+ *ptr = (PixelType)color;
+ }
+ }
+
+ ptr = (PixelType *)_activeSurface->getBasePtr(x2, y2);
+ *ptr = (PixelType)color;
+}
+
+/** VERTICAL TRIANGLE DRAWING ALGORITHM **/
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType,PixelFormat>::
+drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) {
+ int dx = w >> 1, dy = h, gradient_h = 0;
+ int pitch = Base::surfacePitch();
+ PixelType *ptr_right = 0, *ptr_left = 0;
+
+ if (inverted) {
+ ptr_right = (PixelType *)_activeSurface->getBasePtr(x1, y1);
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + w, y1);
+ } else {
+ ptr_right = ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + dx, y1);
+ }
+
+ if (dx > dy) {
+ int ddy = dy * 2;
+ int dysub = ddy - (dx * 2);
+ int error_term = ddy - dx;
+
+ switch(fill_m) {
+ case kFillDisabled:
+ while (dx--) {
+ __TRIANGLE_MAINX();
+ *ptr_right = color;
+ *ptr_left = color;
+ }
+ colorFill(ptr_left, ptr_right, color);
+ break;
+
+ case kFillForeground:
+ case kFillBackground:
+ while (dx--) {
+ __TRIANGLE_MAINX();
+ if (inverted) colorFill(ptr_right, ptr_left, color);
+ else colorFill(ptr_left, ptr_right, color);
+ }
+ break;
+
+ case kFillGradient:
+ while (dx--) {
+ __TRIANGLE_MAINX();
+ if (inverted) colorFill(ptr_right, ptr_left, calcGradient(gradient_h++, h));
+ else colorFill(ptr_left, ptr_right, calcGradient(gradient_h++, h));
+ }
+ break;
+ }
+ } else {
+ int ddx = dx * 2;
+ int dxsub = ddx - (dy * 2);
+ int error_term = ddx - dy;
+
+ switch(fill_m) {
+ case kFillDisabled:
+ while (dy--) {
+ __TRIANGLE_MAINY();
+ *ptr_right = color;
+ *ptr_left = color;
+ }
+ colorFill(ptr_left, ptr_right, color);
+ break;
+
+ case kFillForeground:
+ case kFillBackground:
+ while (dy--) {
+ __TRIANGLE_MAINY();
+ if (inverted) colorFill(ptr_right, ptr_left, color);
+ else colorFill(ptr_left, ptr_right, color);
+ }
+ break;
+ case kFillGradient:
+ while (dy--) {
+ __TRIANGLE_MAINY();
+ if (inverted) colorFill(ptr_right, ptr_left, calcGradient(gradient_h++, h));
+ else colorFill(ptr_left, ptr_right, calcGradient(gradient_h++, h));
+ }
+ break;
+ }
+ }
+}
+
+
+/** VERTICAL TRIANGLE DRAWING - FAST VERSION FOR SQUARED TRIANGLES */
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType,PixelFormat>::
+drawTriangleFast(int x1, int y1, int size, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) {
+ int pitch = Base::surfacePitch();
+ int hstep = 0, dy = size;
+ bool grad = (fill_m == kFillGradient);
+
+ PixelType *ptr_right = 0, *ptr_left = 0;
+
+ if (inverted) {
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x1, y1);
+ ptr_right = (PixelType *)_activeSurface->getBasePtr(x1 + size, y1);
+ } else {
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x1, y1 + size);
+ ptr_right = (PixelType *)_activeSurface->getBasePtr(x1 + size, y1 + size);
+ pitch = -pitch;
+ }
+
+ if (fill_m == kFillDisabled) {
+ while (ptr_left < ptr_right) {
+ *ptr_left = color;
+ *ptr_right = color;
+ ptr_left += pitch;
+ ptr_right += pitch;
+ if (hstep++ % 2) {
+ ptr_left++;
+ ptr_right--;
+ }
+ }
+ } else {
+ while (ptr_left < ptr_right) {
+ colorFill(ptr_left, ptr_right, grad ? calcGradient(dy--, size) : color);
+ ptr_left += pitch;
+ ptr_right += pitch;
+ if (hstep++ % 2) {
+ ptr_left++;
+ ptr_right--;
+ }
+ }
+ }
+}
+
+/** ROUNDED SQUARE ALGORITHM **/
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
+ int f, ddF_x, ddF_y;
+ int x, y, px, py;
+ int pitch = Base::surfacePitch();
+ int sw = 0, sp = 0, hp = h * pitch;
+
+ PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
+ PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
+ PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
+ PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
+ PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
+
+ int real_radius = r;
+ int short_h = h - (2 * r) + 2;
+ int long_h = h;
+
+ if (fill_m == kFillDisabled) {
+ while (sw++ < Base::_strokeWidth) {
+ colorFill(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color);
+ colorFill(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color);
+ sp += pitch;
+
+ __BE_RESET();
+ r--;
+
+ while (x++ < y) {
+ __BE_ALGORITHM();
+ __BE_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py);
+
+ if (Base::_strokeWidth > 1) {
+ __BE_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x - 1, y, px, py);
+ __BE_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px - pitch, py);
+ }
+ }
+ }
+
+ ptr_fill += pitch * real_radius;
+ while (short_h--) {
+ colorFill(ptr_fill, ptr_fill + Base::_strokeWidth, color);
+ colorFill(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color);
+ ptr_fill += pitch;
+ }
+ } else {
+ __BE_RESET();
+ PixelType color1, color2, color3, color4;
+
+ if (fill_m == kFillGradient) {
+ while (x++ < y) {
+ __BE_ALGORITHM();
+
+ color1 = calcGradient(real_radius - x, long_h);
+ color2 = calcGradient(real_radius - y, long_h);
+ color3 = calcGradient(long_h - r + x, long_h);
+ color4 = calcGradient(long_h - r + y, long_h);
+
+ colorFill(ptr_tl - x - py, ptr_tr + x - py, color2);
+ colorFill(ptr_tl - y - px, ptr_tr + y - px, color1);
+
+ colorFill(ptr_bl - x + py, ptr_br + x + py, color4);
+ colorFill(ptr_bl - y + px, ptr_br + y + px, color3);
+
+ __BE_DRAWCIRCLE_XCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py);
+ }
+ } else {
+ while (x++ < y) {
+ __BE_ALGORITHM();
+
+ colorFill(ptr_tl - x - py, ptr_tr + x - py, color);
+ colorFill(ptr_tl - y - px, ptr_tr + y - px, color);
+
+ colorFill(ptr_bl - x + py, ptr_br + x + py, color);
+ colorFill(ptr_bl - y + px, ptr_br + y + px, color);
+
+ // do not remove - messes up the drawing at lower resolutions
+ __BE_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py);
+ }
+ }
+
+ ptr_fill += pitch * r;
+ while (short_h--) {
+ if (fill_m == kFillGradient)
+ color = calcGradient(real_radius++, long_h);
+ colorFill(ptr_fill, ptr_fill + w + 1, color);
+ ptr_fill += pitch;
+ }
+ }
+}
+
+/** CIRCLE ALGORITHM **/
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+drawCircleAlg(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode fill_m) {
+ int f, ddF_x, ddF_y;
+ int x, y, px, py, sw = 0;
+ int pitch = Base::surfacePitch();
+ PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
+
+ if (fill_m == kFillDisabled) {
+ while (sw++ < Base::_strokeWidth) {
+ __BE_RESET();
+ r--;
+
+ *(ptr + y) = color;
+ *(ptr - y) = color;
+ *(ptr + py) = color;
+ *(ptr - py) = color;
+
+ while (x++ < y) {
+ __BE_ALGORITHM();
+ __BE_DRAWCIRCLE(ptr, ptr, ptr, ptr, x, y, px, py);
+
+ if (Base::_strokeWidth > 1) {
+ __BE_DRAWCIRCLE(ptr, ptr, ptr, ptr, x - 1, y, px, py);
+ __BE_DRAWCIRCLE(ptr, ptr, ptr, ptr, x, y, px - pitch, py);
+ }
+ }
+ }
+ } else {
+ colorFill(ptr - r, ptr + r, color);
+ __BE_RESET();
+
+ while (x++ < y) {
+ __BE_ALGORITHM();
+ colorFill(ptr - x + py, ptr + x + py, color);
+ colorFill(ptr - x - py, ptr + x - py, color);
+ colorFill(ptr - y + px, ptr + y + px, color);
+ colorFill(ptr - y - px, ptr + y - px, color);
+ }
+ }
+}
+
+
+
+
+
+/********************************************************************
+ ********************************************************************
+ * SHADOW drawing algorithms - VectorRendererSpec *******************
+ ********************************************************************
+ ********************************************************************/
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+drawSquareShadow(int x, int y, int w, int h, int blur) {
+ PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x + w - 1, y + blur);
+ int pitch = Base::surfacePitch();
+ int i, j;
+
+ i = h - blur;
+
+ while (i--) {
+ j = blur;
+ while (j--)
+ blendPixelPtr(ptr + j, 0, ((blur - j) << 8) / blur);
+ ptr += pitch;
+ }
+
+ ptr = (PixelType *)_activeSurface->getBasePtr(x + blur, y + h - 1);
+
+ while (i++ < blur) {
+ j = w - blur;
+ while (j--)
+ blendPixelPtr(ptr + j, 0, ((blur - i) << 8) / blur);
+ ptr += pitch;
+ }
+
+ ptr = (PixelType *)_activeSurface->getBasePtr(x + w, y + h);
+
+ i = 0;
+ while (i++ < blur) {
+ j = blur - 1;
+ while (j--)
+ blendPixelPtr(ptr + j, 0, (((blur - j) * (blur - i)) << 8) / (blur * blur));
+ ptr += pitch;
+ }
+}
+
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int blur) {
+ int f, ddF_x, ddF_y;
+ int x, y, px, py;
+ int pitch = Base::surfacePitch();
+ int alpha = 102;
+
+ x1 += blur;
+ y1 += blur;
+
+ PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
+ PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
+ PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
+ PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - blur, y1 + r);
+
+ int short_h = h - (2 * r) + 1;
+
+ __BE_RESET();
+
+ // HACK: As we are drawing circles exploting 8-axis symmetry,
+ // there are 4 pixels on each circle which are drawn twice.
+ // this is ok on filled circles, but when blending on surfaces,
+ // we cannot let it blend twice. awful.
+ uint32 hb = 0;
+
+ while (x++ < y) {
+ __BE_ALGORITHM();
+
+ if (((1 << x) & hb) == 0) {
+ blendFill(ptr_tr - px - r, ptr_tr + y - px, 0, alpha);
+ blendFill(ptr_bl - y + px, ptr_br + y + px, 0, alpha);
+ hb |= (1 << x);
+ }
+
+ if (((1 << y) & hb) == 0) {
+ blendFill(ptr_tr - r - py, ptr_tr + x - py, 0, alpha);
+ blendFill(ptr_bl - x + py, ptr_br + x + py, 0, alpha);
+ hb |= (1 << y);
+ }
+ }
+
+ while (short_h--) {
+ blendFill(ptr_fill - r, ptr_fill + blur, 0, alpha);
+ ptr_fill += pitch;
+ }
+}
+
+template<typename PixelType, typename PixelFormat>
+void VectorRendererSpec<PixelType, PixelFormat>::
+drawRoundedSquareFakeBevel(int x1, int y1, int r, int w, int h, int amount) {
+ int x, y;
+ int p = Base::surfacePitch(), px, py;
+ int sw = 0, sp = 0;
+
+ uint32 rsq = (r * r) << 16;
+ uint32 T = 0, oldT;
+ uint8 a1, a2;
+
+ PixelType color = _bevelColor; //RGBToColor<PixelFormat>(63, 60, 17);
+
+ PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
+ PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
+ PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
+ PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
+
+ int short_h = h - 2 * r;
+
+ while (sw++ < amount) {
+ colorFill(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color);
+ sp += p;
+
+ x = r - (sw - 1); y = 0; T = 0;
+ px = p * x; py = 0;
+
+ while (x > y++) {
+ __WU_ALGORITHM();
+
+ blendPixelPtr(ptr_tr + (y) - (px - p), color, a2);
+ blendPixelPtr(ptr_tr + (x - 1) - (py), color, a2);
+ blendPixelPtr(ptr_tl - (x - 1) - (py), color, a2);
+ blendPixelPtr(ptr_tl - (y) - (px - p), color, a2);
+ blendPixelPtr(ptr_bl - (y) + (px - p), color, a2);
+ blendPixelPtr(ptr_bl - (x - 1) + (py), color, a2);
+
+ blendPixelPtr(ptr_tr + (y) - (px), color, a1);
+ blendPixelPtr(ptr_tr + (x) - (py), color, a1);
+ blendPixelPtr(ptr_tl - (x) - (py), color, a1);
+ blendPixelPtr(ptr_tl - (y) - (px), color, a1);
+ blendPixelPtr(ptr_bl - (y) + (px), color, a1);
+ blendPixelPtr(ptr_bl - (x) + (py), color, a1);
+ }
+ }
+
+ ptr_fill += p * r;
+ while (short_h-- >= 0) {
+ colorFill(ptr_fill, ptr_fill + amount, color);
+ ptr_fill += p;
+ }
+}
+
+
+
+
+
+
+
+/******************************************************************************/
+
+
+
+
+
+
+
+
+
+/********************************************************************
+ * ANTIALIASED PRIMITIVES drawing algorithms - VectorRendererAA
+ ********************************************************************/
+/** LINES **/
+template<typename PixelType, typename PixelFormat>
+void VectorRendererAA<PixelType, PixelFormat>::
+drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) {
+
+ PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
+ int pitch = Base::surfacePitch();
+ int xdir = (x2 > x1) ? 1 : -1;
+ uint16 error_tmp, error_acc, gradient;
+ uint8 alpha;
+
+ *ptr = (PixelType)color;
+
+ if (dx > dy) {
+ gradient = (uint32)(dy << 16) / (uint32)dx;
+ error_acc = 0;
+
+ while (--dx) {
+ error_tmp = error_acc;
+ error_acc += gradient;
+
+ if (error_acc <= error_tmp)
+ ptr += pitch;
+
+ ptr += xdir;
+ alpha = (error_acc >> 8);
+
+ blendPixelPtr(ptr, color, ~alpha);
+ blendPixelPtr(ptr + pitch, color, alpha);
+ }
+ } else {
+ gradient = (uint32)(dx << 16) / (uint32)dy;
+ error_acc = 0;
+
+ while (--dy) {
+ error_tmp = error_acc;
+ error_acc += gradient;
+
+ if (error_acc <= error_tmp)
+ ptr += xdir;
+
+ ptr += pitch;
+ alpha = (error_acc >> 8);
+
+ blendPixelPtr(ptr, color, ~alpha);
+ blendPixelPtr(ptr + xdir, color, alpha);
+ }
+ }
+
+ Base::putPixel(x2, y2, color);
+}
+
+/** ROUNDED SQUARES **/
+template<typename PixelType, typename PixelFormat>
+void VectorRendererAA<PixelType, PixelFormat>::
+drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
+ int x, y;
+ int p = Base::surfacePitch(), px, py;
+ int sw = 0, sp = 0, hp = h * p;
+
+ uint32 rsq = (r * r) << 16;
+ uint32 T = 0, oldT;
+ uint8 a1, a2;
+
+ PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
+ PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
+ PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
+ PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
+ PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
+
+ int short_h = h - 2 * r;
+
+ if (fill_m == VectorRenderer::kFillDisabled) {
+ while (sw++ < Base::_strokeWidth) {
+ colorFill(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color);
+ colorFill(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color);
+ sp += p;
+
+ x = r - (sw - 1); y = 0; T = 0;
+ px = p * x; py = 0;
+
+ while (x > y++) {
+ __WU_ALGORITHM();
+
+ if (sw != 1 && sw != Base::_strokeWidth)
+ a2 = a1 = 255;
+
+ __WU_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, (x - 1), y, (px - p), py, a2);
+ __WU_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1);
+ }
+ }
+
+ ptr_fill += p * r;
+ while (short_h-- >= 0) {
+ colorFill(ptr_fill, ptr_fill + Base::_strokeWidth, color);
+ colorFill(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color);
+ ptr_fill += p;
+ }
+ } else {
+ x = r; y = 0; T = 0;
+ px = p * x; py = 0;
+
+ while (x > 1 + y++) {
+ __WU_ALGORITHM();
+
+ colorFill(ptr_tl - x - py, ptr_tr + x - py, color);
+ colorFill(ptr_tl - y - px, ptr_tr + y - px, color);
+
+ colorFill(ptr_bl - x + py, ptr_br + x + py, color);
+ colorFill(ptr_bl - y + px, ptr_br + y + px, color);
+
+ __WU_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1);
+ }
+
+ ptr_fill += p * r;
+ while (short_h-- >= 0) {
+ colorFill(ptr_fill, ptr_fill + w + 1, color);
+ ptr_fill += p;
+ }
+ }
+}
+
+/** CIRCLES **/
+template<typename PixelType, typename PixelFormat>
+void VectorRendererAA<PixelType, PixelFormat>::
+drawCircleAlg(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode fill_m) {
+ int x, y, sw = 0;
+ int p = Base::surfacePitch(), px, py;
+
+ uint32 rsq = (r * r) << 16;
+ uint32 T = 0, oldT;
+ uint8 a1, a2;
+
+ PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
+
+ if (fill_m == VectorRenderer::kFillDisabled) {
+ while (sw++ < Base::_strokeWidth) {
+ x = r - (sw - 1); y = 0; T = 0;
+ px = p * x; py = 0;
+
+ *(ptr + x) = (PixelType)color;
+ *(ptr - x) = (PixelType)color;
+ *(ptr + px) = (PixelType)color;
+ *(ptr - px) = (PixelType)color;
+
+ while (x > y++) {
+ __WU_ALGORITHM();
+
+ if (sw != 1 && sw != Base::_strokeWidth)
+ a2 = a1 = 255;
+
+ __WU_DRAWCIRCLE(ptr, ptr, ptr, ptr, (x - 1), y, (px - p), py, a2);
+ __WU_DRAWCIRCLE(ptr, ptr, ptr, ptr, x, y, px, py, a1);
+ }
+ }
+ } else {
+ colorFill(ptr - r, ptr + r + 1, color);
+ x = r; y = 0; T = 0;
+ px = p * x; py = 0;
+
+ while (x > y++) {
+ __WU_ALGORITHM();
+
+ colorFill(ptr - x + py, ptr + x + py, color);
+ colorFill(ptr - x - py, ptr + x - py, color);
+ colorFill(ptr - y + px, ptr + y + px, color);
+ colorFill(ptr - y - px, ptr + y - px, color);
+
+ __WU_DRAWCIRCLE(ptr, ptr, ptr, ptr, x, y, px, py, a1);
+ }
+ }
+}
+
+
+}
diff --git a/graphics/VectorRendererSpec.h b/graphics/VectorRendererSpec.h
new file mode 100644
index 0000000000..77336e329e
--- /dev/null
+++ b/graphics/VectorRendererSpec.h
@@ -0,0 +1,296 @@
+/* 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 VECTOR_RENDERER_SPEC_H
+#define VECTOR_RENDERER_SPEC_H
+
+#include "graphics/VectorRenderer.h"
+
+namespace Graphics {
+
+/**
+ * VectorRendererSpec: Specialized Vector Renderer Class
+ *
+ * This templated class implements the basic subset of vector operations for
+ * all platforms by allowing the user to provide the actual Pixel Type and
+ * pixel information structs.
+ *
+ * This class takes two template parameters:
+ *
+ * @param PixelType Defines a type which may hold the color value of a single
+ * pixel, such as "byte" or "uint16" for 8 and 16 BPP respectively.
+ *
+ * @param PixelFormat Defines the type of the PixelFormat struct which contains all
+ * the actual information of the pixels being used, as declared in "graphics/colormasks.h"
+ *
+ * TODO: Expand documentation.
+ *
+ * @see VectorRenderer
+ */
+template<typename PixelType, typename PixelFormat>
+class VectorRendererSpec : public VectorRenderer {
+ typedef VectorRenderer Base;
+
+public:
+ VectorRendererSpec() {
+ _bitmapAlphaColor = RGBToColor<PixelFormat>(255, 0, 255);
+ }
+
+ void drawLine(int x1, int y1, int x2, int y2);
+ void drawCircle(int x, int y, int r);
+ void drawSquare(int x, int y, int w, int h);
+ void drawRoundedSquare(int x, int y, int r, int w, int h);
+ void drawTriangle(int x, int y, int base, int height, TriangleOrientation orient);
+ void drawTab(int x, int y, int r, int w, int h);
+ void drawBeveledSquare(int x, int y, int w, int h, int bevel) {
+ drawBevelSquareAlg(x, y, w, h, bevel, _bevelColor, _fgColor, Base::_fillMode != kFillDisabled);
+ }
+ void drawString(const Graphics::Font *font, const Common::String &text,
+ const Common::Rect &area, GUI::Theme::TextAlign alignH,
+ GUI::Theme::TextAlignVertical alignV, int deltax, bool elipsis);
+
+ void setFgColor(uint8 r, uint8 g, uint8 b) { _fgColor = RGBToColor<PixelFormat>(r, g, b); }
+ void setBgColor(uint8 r, uint8 g, uint8 b) { _bgColor = RGBToColor<PixelFormat>(r, g, b); }
+ void setBevelColor(uint8 r, uint8 g, uint8 b) { _bevelColor = RGBToColor<PixelFormat>(r, g, b); }
+ void setGradientColors(uint8 r1, uint8 g1, uint8 b1, uint8 r2, uint8 g2, uint8 b2);
+
+ void copyFrame(OSystem *sys, const Common::Rect &r);
+ void copyWholeFrame(OSystem *sys) { copyFrame(sys, Common::Rect(0, 0, _activeSurface->w, _activeSurface->h)); }
+
+ void fillSurface();
+ void blitSurface(const Graphics::Surface *source, const Common::Rect &r);
+ void blitSubSurface(const Graphics::Surface *source, const Common::Rect &r);
+ void blitAlphaBitmap(const Graphics::Surface *source, const Common::Rect &r);
+
+ void applyScreenShading(GUI::Theme::ShadingStyle shadingStyle);
+
+protected:
+
+ /**
+ * Draws a single pixel on the surface with the given coordinates and
+ * the given color.
+ *
+ * @param x Horizontal coordinate of the pixel.
+ * @param y Vertical coordinate of the pixel.
+ * @param color Color of the pixel
+ */
+ inline void putPixel(int x, int y, PixelType color) {
+ PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x, y);
+ *ptr = color;
+ }
+
+ /**
+ * Blends a single pixel on the surface with the given coordinates, color
+ * and Alpha intensity.
+ *
+ * @param x Horizontal coordinate of the pixel.
+ * @param y Vertical coordinate of the pixel.
+ * @param color Color of the pixel
+ * @param alpha Alpha intensity of the pixel (0-255)
+ */
+ inline void blendPixel(int x, int y, PixelType color, uint8 alpha) {
+ blendPixelPtr((PixelType*)Base::_activeSurface->getBasePtr(x, y), color, alpha);
+ }
+
+ /**
+ * Blends a single pixel on the surface in the given pixel pointer, using supplied color
+ * and Alpha intensity.
+ *
+ * This is implemented to prevent blendPixel() to calculate the surface pointer on each call.
+ * Optimized drawing algorithms should call this function when possible.
+ *
+ * @see blendPixel
+ * @param ptr Pointer to the pixel to blend on top of
+ * @param color Color of the pixel
+ * @param alpha Alpha intensity of the pixel (0-255)
+ */
+ inline void blendPixelPtr(PixelType *ptr, PixelType color, uint8 alpha);
+
+ /**
+ * PRIMITIVE DRAWING ALGORITHMS
+ *
+ * Generic algorithms for drawing all kinds of aliased primitive shapes.
+ * These may be overloaded in inheriting classes to implement platform-specific
+ * optimizations or improve looks.
+ *
+ * @see VectorRendererAA
+ * @see VectorRendererAA::drawLineAlg
+ * @see VectorRendererAA::drawCircleAlg
+ */
+ virtual void drawLineAlg(int x1, int y1, int x2, int y2,
+ int dx, int dy, PixelType color);
+
+ virtual void drawCircleAlg(int x, int y, int r,
+ PixelType color, FillMode fill_m);
+
+ virtual void drawRoundedSquareAlg(int x1, int y1, int r, int w, int h,
+ PixelType color, FillMode fill_m);
+
+ virtual void drawSquareAlg(int x, int y, int w, int h,
+ PixelType color, FillMode fill_m);
+
+ virtual void drawTriangleVertAlg(int x, int y, int w, int h,
+ bool inverted, PixelType color, FillMode fill_m);
+
+ virtual void drawTriangleFast(int x, int y, int size,
+ bool inverted, PixelType color, FillMode fill_m);
+
+ virtual void drawBevelSquareAlg(int x, int y, int w, int h,
+ int bevel, PixelType top_color, PixelType bottom_color, bool fill);
+
+ virtual void drawTabAlg(int x, int y, int w, int h, int r,
+ PixelType color, VectorRenderer::FillMode fill_m,
+ int baseLeft = 0, int baseRight = 0);
+
+ virtual void drawBevelTabAlg(int x, int y, int w, int h,
+ int bevel, PixelType topColor, PixelType bottomColor,
+ int baseLeft = 0, int baseRight = 0);
+
+ /**
+ * SHADOW DRAWING ALGORITHMS
+ *
+ * Optimized versions of the primitive drawing algorithms with alpha blending
+ * for shadow drawing.
+ * There functions may be overloaded in inheriting classes to improve performance
+ * in the slowest platforms where pixel alpha blending just doesn't cut it.
+ *
+ * @param blur Intensity/size of the shadow.
+ */
+ virtual void drawSquareShadow(int x, int y, int w, int h, int blur);
+ virtual void drawRoundedSquareShadow(int x, int y, int r, int w, int h, int blur);
+ virtual void drawRoundedSquareFakeBevel(int x, int y, int r, int w, int h, int amount);
+
+ /**
+ * Calculates the color gradient on a given point.
+ * This function assumes that the gradient start/end colors have been set
+ * beforehand from the API function call.
+ *
+ * @param pos Progress of the gradient.
+ * @param max Maximum amount of the progress.
+ * @return Composite color of the gradient at the given "progress" amount.
+ */
+ inline PixelType calcGradient(uint32 pos, uint32 max);
+
+ /**
+ * Fills several pixels in a row with a given color and the specifed alpha blending.
+ *
+ * @see blendPixelPtr
+ * @see blendPixel
+ * @param first Pointer to the first pixel to fill.
+ * @param last Pointer to the last pixel to fill.
+ * @param color Color of the pixel
+ * @param alpha Alpha intensity of the pixel (0-255)
+ */
+ inline void blendFill(PixelType *first, PixelType *last, PixelType color, uint8 alpha) {
+ while (first != last) blendPixelPtr(first++, color, alpha);
+ }
+
+ /**
+ * Fills several pixels in a row with a given color.
+ *
+ * This is a replacement function for Common::set_to, using an unrolled
+ * loop to maximize performance on most architectures.
+ * This function may (and should) be overloaded in any child renderers
+ * for portable platforms with platform-specific assembly code.
+ *
+ * This fill operation is extensively used throughout the renderer, so this
+ * counts as one of the main bottlenecks. Please replace it with assembly
+ * when possible!
+ *
+ * @param first Pointer to the first pixel to fill.
+ * @param last Pointer to the last pixel to fill.
+ * @param color Color of the pixel
+ */
+ inline void colorFill(PixelType *first, PixelType *last, PixelType color);
+
+ void areaConvolution(const Common::Rect &area, const int filter[3][3], int filterDiv, int offset);
+
+ PixelType _fgColor; /** Foreground color currently being used to draw on the renderer */
+ PixelType _bgColor; /** Background color currently being used to draw on the renderer */
+
+ PixelType _gradientStart; /** Start color for the fill gradient */
+ PixelType _gradientEnd; /** End color for the fill gradient */
+
+ PixelType _bevelColor;
+ PixelType _bitmapAlphaColor;
+};
+
+
+/**
+ * VectorRendererAA: Anti-Aliased Vector Renderer Class
+ *
+ * This templated class inherits all the functionality of the VectorRendererSpec
+ * class but uses better looking yet slightly slower AA algorithms for drawing
+ * most primivitves. May be used in faster platforms.
+ *
+ * TODO: Expand documentation.
+ *
+ * @see VectorRenderer
+ * @see VectorRendererSpec
+ */
+template<typename PixelType, typename PixelFormat>
+class VectorRendererAA : public VectorRendererSpec<PixelType, PixelFormat> {
+ typedef VectorRendererSpec<PixelType, PixelFormat> Base;
+protected:
+ /**
+ * "Wu's Line Antialiasing Algorithm" as published by Xiaolin Wu, July 1991
+ * Based on the implementation found in Michael Abrash's Graphics Programming Black Book.
+ *
+ * Generic line drawing algorithm for the Antialiased renderer. Optimized with no
+ * floating point operations, assumes no special cases.
+ *
+ * @see VectorRenderer::drawLineAlg()
+ */
+ virtual void drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color);
+
+ /**
+ * "Wu's Circle Antialiasing Algorithm" as published by Xiaolin Wu, July 1991
+ * Based on the theoretical concept of the algorithm.
+ *
+ * Implementation of Wu's algorithm for circles using fixed point arithmetics.
+ * Could be quite fast.
+ *
+ * @see VectorRenderer::drawCircleAlg()
+ */
+ virtual void drawCircleAlg(int x, int y, int r, PixelType color, VectorRenderer::FillMode fill_m);
+
+ /**
+ * "Wu's Circle Antialiasing Algorithm" as published by Xiaolin Wu, July 1991,
+ * modified with corner displacement to allow drawing of squares with rounded
+ * corners.
+ *
+ * @see VectorRenderer::drawRoundedAlg()
+ */
+ virtual void drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m);
+
+ virtual void drawRoundedSquareShadow(int x, int y, int r, int w, int h, int blur) {
+ Base::drawRoundedSquareShadow(x, y, r, w, h, blur);
+// VectorRenderer::applyConvolutionMatrix(VectorRenderer::kConvolutionHardBlur,
+// Common::Rect(x, y, x + w + blur * 2, y + h + blur * 2));
+ }
+};
+
+}
+#endif
diff --git a/graphics/font.cpp b/graphics/font.cpp
index 0f67899706..404e04d18e 100644
--- a/graphics/font.cpp
+++ b/graphics/font.cpp
@@ -48,7 +48,29 @@ int NewFont::getCharWidth(byte chr) const {
return desc.width[chr - desc.firstchar];
}
-void NewFont::drawChar(Surface *dst, byte chr, int tx, int ty, uint32 color) const {
+
+template <int bytesPerPixel>
+void drawCharIntern(byte *ptr, uint pitch, const bitmap_t *src, int h, int minX, int maxX, const uint32 color) {
+ while (h-- > 0) {
+ const bitmap_t buffer = READ_UINT16(src);
+ src++;
+
+ int x = minX;
+ uint mask = 0x8000 >> minX;
+ for (; x < maxX; x++, mask >>= 1) {
+ if ((buffer & mask) != 0) {
+ if (bytesPerPixel == 1)
+ ptr[x] = color;
+ else if (bytesPerPixel == 2)
+ ((uint16 *)ptr)[x] = color;
+ }
+ }
+
+ ptr += pitch;
+ }
+}
+
+void NewFont::drawChar(Surface *dst, byte chr, const int tx, const int ty, const uint32 color) const {
assert(dst != 0);
assert(desc.bits != 0 && desc.maxwidth <= 17);
@@ -80,25 +102,14 @@ void NewFont::drawChar(Surface *dst, byte chr, int tx, int ty, uint32 color) con
const bitmap_t *tmp = desc.bits + (desc.offset ? desc.offset[chr] : (chr * desc.fbbh));
- for (int y = 0; y < bbh; y++, ptr += dst->pitch) {
- const bitmap_t buffer = READ_UINT16(tmp);
- tmp++;
- bitmap_t mask = 0x8000;
- if (ty + desc.ascent - bby - bbh + y < 0 ||
- ty + desc.ascent - bby - bbh + y >= dst->h)
- continue;
+ int y = MIN(bbh, ty + desc.ascent - bby);
+ tmp += bbh - y;
+ y -= MAX(0, ty + desc.ascent - bby - dst->h);
- for (int x = 0; x < bbw; x++, mask >>= 1) {
- if (tx + bbx + x < 0 || tx + bbx + x >= dst->w)
- continue;
- if ((buffer & mask) != 0) {
- if (dst->bytesPerPixel == 1)
- ptr[x] = color;
- else if (dst->bytesPerPixel == 2)
- ((uint16 *)ptr)[x] = color;
- }
- }
- }
+ if (dst->bytesPerPixel == 1)
+ drawCharIntern<1>(ptr, dst->pitch, tmp, y, MAX(0, -(tx + bbx)), MIN(bbw, dst->w - tx - bbx), color);
+ else if (dst->bytesPerPixel == 2)
+ drawCharIntern<2>(ptr, dst->pitch, tmp, y, MAX(0, -(tx + bbx)), MIN(bbw, dst->w - tx - bbx), color);
}
diff --git a/graphics/module.mk b/graphics/module.mk
index f658b056df..982711b608 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -17,7 +17,9 @@ MODULE_OBJS := \
scaler.o \
scaler/thumbnail_intern.o \
surface.o \
- thumbnail.o
+ thumbnail.o \
+ VectorRenderer.o \
+ VectorRendererSpec.o
ifndef DISABLE_SCALERS
MODULE_OBJS += \
diff --git a/gui/EditTextWidget.cpp b/gui/EditTextWidget.cpp
index 3b5afab669..889310d958 100644
--- a/gui/EditTextWidget.cpp
+++ b/gui/EditTextWidget.cpp
@@ -24,9 +24,10 @@
#include "gui/EditTextWidget.h"
#include "gui/dialog.h"
-#include "gui/eval.h"
#include "gui/newgui.h"
+#include "gui/ThemeEval.h"
+
namespace GUI {
EditTextWidget::EditTextWidget(GuiObject *boss, int x, int y, int w, int h, const String &text)
@@ -41,7 +42,6 @@ EditTextWidget::EditTextWidget(GuiObject *boss, const String &name, const String
: EditableWidget(boss, name) {
setFlags(WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS | WIDGET_WANT_TICKLE);
_type = kEditTextWidget;
- _hints |= THEME_HINT_USE_SHADOW;
setEditString(text);
}
@@ -52,10 +52,10 @@ void EditTextWidget::setEditString(const String &str) {
}
void EditTextWidget::reflowLayout() {
- _leftPadding = g_gui.evaluator()->getVar("EditTextWidget.leftPadding", 0);
- _rightPadding = g_gui.evaluator()->getVar("EditTextWidget.rightPadding", 0);
+ _leftPadding = g_gui.xmlEval()->getVar("Globals.EditTextWidget.Padding.Left", 0);
+ _rightPadding = g_gui.xmlEval()->getVar("Globals.EditTextWidget.Padding.Right", 0);
- _font = (Theme::FontStyle)g_gui.evaluator()->getVar("EditTextWidget.font", Theme::kFontStyleNormal);
+ _font = (Theme::FontStyle)g_gui.xmlEval()->getVar("EditTextWidget.Font", Theme::kFontStyleNormal);
EditableWidget::reflowLayout();
}
@@ -82,7 +82,7 @@ void EditTextWidget::handleMouseDown(int x, int y, int button, int clickCount) {
void EditTextWidget::drawWidget() {
- g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), _hints, Theme::kWidgetBackgroundEditText);
+ g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), 0, Theme::kWidgetBackgroundEditText);
// Draw the text
adjustOffset();
diff --git a/gui/ListWidget.cpp b/gui/ListWidget.cpp
index 80898d06c8..c17963ea95 100644
--- a/gui/ListWidget.cpp
+++ b/gui/ListWidget.cpp
@@ -27,9 +27,10 @@
#include "gui/ListWidget.h"
#include "gui/ScrollBarWidget.h"
#include "gui/dialog.h"
-#include "gui/eval.h"
#include "gui/newgui.h"
+#include "gui/ThemeEval.h"
+
namespace GUI {
ListWidget::ListWidget(GuiObject *boss, const String &name)
@@ -45,7 +46,6 @@ ListWidget::ListWidget(GuiObject *boss, const String &name)
_scrollBar->setTarget(this);
setFlags(WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS | WIDGET_WANT_TICKLE);
- setHints(THEME_HINT_SAVE_BACKGROUND | THEME_HINT_USE_SHADOW);
_type = kListWidget;
_editMode = false;
_numberingMode = kListNumberingOne;
@@ -75,7 +75,6 @@ ListWidget::ListWidget(GuiObject *boss, int x, int y, int w, int h)
_scrollBar->setTarget(this);
setFlags(WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS | WIDGET_WANT_TICKLE);
- setHints(THEME_HINT_SAVE_BACKGROUND | THEME_HINT_USE_SHADOW);
_type = kListWidget;
_editMode = false;
_numberingMode = kListNumberingOne;
@@ -361,7 +360,8 @@ void ListWidget::drawWidget() {
Common::String buffer;
// Draw a thin frame around the list.
- g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x + _w, _y + _h), _hints, Theme::kWidgetBackgroundBorder);
+ g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x + _w, _y + _h), 0, Theme::kWidgetBackgroundBorder);
+ const int scrollbarW = (_scrollBar && _scrollBar->isVisible()) ? _scrollBarWidth : 0;
// Draw the list items
for (i = 0, pos = _currentPos; i < _entriesPerPage && pos < len; i++, pos++) {
@@ -374,7 +374,8 @@ void ListWidget::drawWidget() {
if (_hasFocus)
inverted = true;
else
- g_gui.theme()->drawWidgetBackground(Common::Rect(_x, y - 1, _x + _w - 1, y + fontHeight - 1), _hints, Theme::kWidgetBackgroundBorderSmall);
+ g_gui.theme()->drawWidgetBackground(Common::Rect(_x, y - 1, _x + _w - 1, y + fontHeight - 1),
+ 0, Theme::kWidgetBackgroundBorderSmall);
}
Common::Rect r(getEditRect());
@@ -385,7 +386,8 @@ void ListWidget::drawWidget() {
char temp[10];
sprintf(temp, "%2d. ", (pos + _numberingMode));
buffer = temp;
- g_gui.theme()->drawText(Common::Rect(_x, y, _x + r.left + _leftPadding, y + fontHeight - 2), buffer, _state, Theme::kTextAlignLeft, inverted, _leftPadding);
+ g_gui.theme()->drawText(Common::Rect(_x, y, _x + r.left + _leftPadding, y + fontHeight - 2),
+ buffer, _state, Theme::kTextAlignLeft, inverted, _leftPadding);
pad = 0;
}
@@ -394,20 +396,22 @@ void ListWidget::drawWidget() {
if (_selectedItem == pos && _editMode) {
buffer = _editString;
adjustOffset();
- width = _w - r.left - _hlRightPadding - _leftPadding;
- g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight-2), buffer, _state, Theme::kTextAlignLeft, inverted, pad);
+ width = _w - r.left - _hlRightPadding - _leftPadding - scrollbarW;
+ g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight-2),
+ buffer, _state, Theme::kTextAlignLeft, inverted, pad);
} else {
int maxWidth = _textWidth[i];
buffer = _list[pos];
if (_selectedItem != pos) {
width = g_gui.getStringWidth(buffer) + pad;
if (width > _w - r.left)
- width = _w - r.left;
+ width = _w - r.left - _hlRightPadding - scrollbarW;
} else
- width = _w - r.left - _hlRightPadding;
+ width = _w - r.left - _hlRightPadding - scrollbarW;
if (width > maxWidth)
maxWidth = width;
- g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x + r.left + maxWidth, y + fontHeight-2), buffer, _state, Theme::kTextAlignLeft, inverted, pad);
+ g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x + r.left + maxWidth, y + fontHeight-2),
+ buffer, _state, Theme::kTextAlignLeft, inverted, pad);
}
_textWidth[i] = width;
@@ -480,12 +484,12 @@ void ListWidget::abortEditMode() {
void ListWidget::reflowLayout() {
Widget::reflowLayout();
- _leftPadding = g_gui.evaluator()->getVar("ListWidget.leftPadding", 0);
- _rightPadding = g_gui.evaluator()->getVar("ListWidget.rightPadding", 0);
- _topPadding = g_gui.evaluator()->getVar("ListWidget.topPadding", 0);
- _bottomPadding = g_gui.evaluator()->getVar("ListWidget.bottomPadding", 0);
- _hlLeftPadding = g_gui.evaluator()->getVar("ListWidget.hlLeftPadding", 0);
- _hlRightPadding = g_gui.evaluator()->getVar("ListWidget.hlRightPadding", 0);
+ _leftPadding = g_gui.xmlEval()->getVar("Globals.ListWidget.Padding.Left", 0);
+ _rightPadding = g_gui.xmlEval()->getVar("Globals.ListWidget.Padding.Right", 0);
+ _topPadding = g_gui.xmlEval()->getVar("Globals.ListWidget.Padding.Top", 0);
+ _bottomPadding = g_gui.xmlEval()->getVar("Globals.ListWidget.Padding.Bottom", 0);
+ _hlLeftPadding = g_gui.xmlEval()->getVar("Globals.ListWidget.hlLeftPadding", 0);
+ _hlRightPadding = g_gui.xmlEval()->getVar("Globals.ListWidget.hlRightPadding", 0);
if (g_gui.getWidgetSize() == kBigWidgetSize) {
_scrollBarWidth = kBigScrollBarWidth;
@@ -493,7 +497,19 @@ void ListWidget::reflowLayout() {
_scrollBarWidth = kNormalScrollBarWidth;
}
- _entriesPerPage = (_h - _topPadding - _bottomPadding) / kLineHeight;
+ // HACK: Once we take padding into account, there are times where
+ // integer rounding leaves a big chunk of white space in the bottom
+ // of the list.
+ // We do a rough rounding on the decimal places of Entries Per Page,
+ // to add another entry even if it goes a tad over the padding.
+ _entriesPerPage = ((_h - _topPadding - _bottomPadding) << 16) / kLineHeight;
+
+ if ((uint)(_entriesPerPage & 0xFFFF) >= 0xF000)
+ _entriesPerPage += (1 << 16);
+
+ _entriesPerPage >>= 16;
+
+ assert(_entriesPerPage > 0);
delete[] _textWidth;
_textWidth = new int[_entriesPerPage];
diff --git a/gui/PopUpWidget.cpp b/gui/PopUpWidget.cpp
index 91b7c40687..6c89e7113c 100644
--- a/gui/PopUpWidget.cpp
+++ b/gui/PopUpWidget.cpp
@@ -25,11 +25,12 @@
#include "common/system.h"
#include "common/events.h"
#include "gui/dialog.h"
-#include "gui/eval.h"
#include "gui/newgui.h"
#include "gui/PopUpWidget.h"
#include "engines/engine.h"
+#include "gui/ThemeEval.h"
+
namespace GUI {
//
@@ -71,7 +72,7 @@ protected:
};
PopUpDialog::PopUpDialog(PopUpWidget *boss, int clickX, int clickY)
- : Dialog(0, 0, 16, 16, false),
+ : Dialog(0, 0, 16, 16),
_popUpBoss(boss) {
// Copy the selection index
@@ -151,7 +152,7 @@ PopUpDialog::PopUpDialog(PopUpWidget *boss, int clickX, int clickY)
void PopUpDialog::drawDialog() {
// Draw the menu border
- g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), THEME_HINT_FIRST_DRAW | THEME_HINT_SAVE_BACKGROUND | THEME_HINT_USE_SHADOW);
+ g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), 0);
/*if (_twoColumns)
g_gui.vLine(_x + _w / 2, _y, _y + _h - 2, g_gui._color);*/
@@ -358,7 +359,6 @@ void PopUpDialog::drawMenuEntry(int entry, bool hilite) {
PopUpWidget::PopUpWidget(GuiObject *boss, const String &name, const String &label, uint labelWidth)
: Widget(boss, name), CommandSender(boss), _label(label), _labelWidth(labelWidth) {
setFlags(WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS);
- setHints(THEME_HINT_SAVE_BACKGROUND);
_type = kPopUpWidget;
_selectedItem = -1;
@@ -380,9 +380,9 @@ void PopUpWidget::handleMouseDown(int x, int y, int button, int clickCount) {
}
void PopUpWidget::reflowLayout() {
- _leftPadding = g_gui.evaluator()->getVar("PopUpWidget.leftPadding", 0);
- _rightPadding = g_gui.evaluator()->getVar("PopUpWidget.rightPadding", 0);
- _labelSpacing = g_gui.evaluator()->getVar("PopUpWidget.labelSpacing", 0);
+ _leftPadding = g_gui.xmlEval()->getVar("Globals.PopUpWidget.Padding.Left", 0);
+ _rightPadding = g_gui.xmlEval()->getVar("Globals.PopUpWidget.Padding.Right", 0);
+ _labelSpacing = g_gui.xmlEval()->getVar("Globals.PopUpWidget.labelSpacing", 10);
Widget::reflowLayout();
}
diff --git a/gui/TabWidget.cpp b/gui/TabWidget.cpp
index 7ad4edbd88..402e9075c1 100644
--- a/gui/TabWidget.cpp
+++ b/gui/TabWidget.cpp
@@ -26,7 +26,8 @@
#include "gui/TabWidget.h"
#include "gui/dialog.h"
#include "gui/newgui.h"
-#include "gui/eval.h"
+
+#include "gui/ThemeEval.h"
namespace GUI {
@@ -55,21 +56,19 @@ void TabWidget::init() {
_activeTab = -1;
_firstVisibleTab = 0;
- _tabWidth = g_gui.evaluator()->getVar("TabWidget.tabWidth");
- _tabHeight = g_gui.evaluator()->getVar("TabWidget.tabHeight");
- _titleVPad = g_gui.evaluator()->getVar("TabWidget.titleVPad");
+ _tabWidth = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Width");
+ _tabHeight = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Height");
+ _titleVPad = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Padding.Top");
- _butRP = g_gui.evaluator()->getVar("TabWidget.navButtonRightPad", 0);
- _butTP = g_gui.evaluator()->getVar("TabWidget.navButtonTopPad", 0);
- _butW = g_gui.evaluator()->getVar("TabWidget.navButtonW", 10);
- _butH = g_gui.evaluator()->getVar("TabWidget.navButtonH", 10);
+ _butRP = g_gui.xmlEval()->getVar("Globals.TabWidget.navButtonPadding.Right", 0);
+ _butTP = g_gui.xmlEval()->getVar("Globals.TabWidget.NavButton.Padding.Top", 0);
+ _butW = g_gui.xmlEval()->getVar("Globals.TabWidget.NavButton.Width", 10);
+ _butH = g_gui.xmlEval()->getVar("Globals.TabWidget.NavButton.Height", 10);
int x = _w - _butRP - _butW * 2 - 2;
int y = _butTP - _tabHeight;
_navLeft = new ButtonWidget(this, x, y, _butW, _butH, "<", kCmdLeft, 0);
- _navLeft->setHints(THEME_HINT_NO_BACKGROUND_RESTORE);
_navRight = new ButtonWidget(this, x + _butW + 2, y, _butW, _butH, ">", kCmdRight, 0);
- _navRight->setHints(THEME_HINT_NO_BACKGROUND_RESTORE);
}
TabWidget::~TabWidget() {
@@ -96,7 +95,7 @@ int TabWidget::addTab(const String &title) {
int numTabs = _tabs.size();
- if (g_gui.evaluator()->getVar("TabWidget.tabWidth") == 0) {
+ if (g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Width") == 0) {
if (_tabWidth == 0)
_tabWidth = 40;
// Determine the new tab width
@@ -216,9 +215,9 @@ void TabWidget::reflowLayout() {
}
}
- _tabHeight = g_gui.evaluator()->getVar("TabWidget.tabHeight");
- _tabWidth = g_gui.evaluator()->getVar("TabWidget.tabWidth");
- _titleVPad = g_gui.evaluator()->getVar("TabWidget.titleVPad");
+ _tabHeight = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Height");
+ _tabWidth = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Width");
+ _titleVPad = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Padding.Top");
if (_tabWidth == 0) {
_tabWidth = 40;
@@ -234,10 +233,10 @@ void TabWidget::reflowLayout() {
}
}
- _butRP = g_gui.evaluator()->getVar("TabWidget.navButtonRightPad", 0);
- _butTP = g_gui.evaluator()->getVar("TabWidget.navButtonTopPad", 0);
- _butW = g_gui.evaluator()->getVar("TabWidget.navButtonW", 10);
- _butH = g_gui.evaluator()->getVar("TabWidget.navButtonH", 10);
+ _butRP = g_gui.xmlEval()->getVar("Globals.TabWidget.NavButton.PaddingRight", 0);
+ _butTP = g_gui.xmlEval()->getVar("Globals.TabWidget.NavButton.Padding.Top", 0);
+ _butW = g_gui.xmlEval()->getVar("GlobalsTabWidget.NavButton.Width", 10);
+ _butH = g_gui.xmlEval()->getVar("Globals.TabWidget.NavButton.Height", 10);
int x = _w - _butRP - _butW * 2 - 2;
int y = _butTP - _tabHeight;
@@ -254,7 +253,7 @@ void TabWidget::drawWidget() {
for (int i = _firstVisibleTab; i < (int)_tabs.size(); ++i) {
tabs.push_back(_tabs[i].title);
}
- g_gui.theme()->drawTab(Common::Rect(_x, _y, _x+_w, _y+_h), _tabHeight, _tabWidth, tabs, _activeTab - _firstVisibleTab, _hints, _titleVPad);
+ g_gui.theme()->drawTab(Common::Rect(_x, _y, _x+_w, _y+_h), _tabHeight, _tabWidth, tabs, _activeTab - _firstVisibleTab, 0, _titleVPad);
}
void TabWidget::draw() {
diff --git a/gui/TabWidget.h b/gui/TabWidget.h
index bf316a7ac3..3dffcd2afe 100644
--- a/gui/TabWidget.h
+++ b/gui/TabWidget.h
@@ -85,6 +85,11 @@ public:
* Widgets are always added to the active tab.
*/
void setActiveTab(int tabID);
+
+ void setTabTitle(int tabID, const String &title) {
+ assert(0 <= tabID && tabID < (int)_tabs.size());
+ _tabs[tabID].title = title;
+ }
virtual void handleMouseDown(int x, int y, int button, int clickCount);
virtual bool handleKeyDown(Common::KeyState state);
diff --git a/gui/ThemeClassic.cpp b/gui/ThemeClassic.cpp
deleted file mode 100644
index be17cf0d09..0000000000
--- a/gui/ThemeClassic.cpp
+++ /dev/null
@@ -1,710 +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 "gui/ThemeClassic.h"
-#include "gui/eval.h"
-
-namespace GUI {
-ThemeClassic::ThemeClassic(OSystem *system, const Common::String &config, const Common::ConfigFile *cfg) : Theme() {
- _enableBlending = true;
- _stylefile = config;
- _system = system;
- _initOk = false;
- _enabled = false;
- _font = 0;
- _fontName.clear();
- memset(&_screen, 0, sizeof(_screen));
-#ifndef CT_NO_TRANSPARENCY
- memset(&_dialog, 0, sizeof(_dialog));
-#endif
- _font = 0;
-
- // 'classic' is always the built in one, we force it and
- // ignore all 'classic' named config files
- if (config.compareToIgnoreCase("classic (builtin)") != 0) {
- if (cfg)
- _configFile = *cfg;
- else
- loadConfigFile(_stylefile);
- }
-
- if (_configFile.hasKey("name", "theme"))
- _configFile.getKey("name", "theme", _stylename);
- else
- _stylename = _stylefile;
-}
-
-ThemeClassic::~ThemeClassic() {
- deinit();
-}
-
-bool ThemeClassic::init() {
- deinit();
- _screen.create(_system->getOverlayWidth(), _system->getOverlayHeight(), sizeof(OverlayColor));
- if (_screen.pixels) {
- _initOk = true;
- clearAll();
- resetDrawArea();
- }
-
- if (isThemeLoadingRequired()) {
- loadTheme(_defaultConfig);
- loadTheme(_configFile, false, true);
-
- setupConfig();
- }
-
- _bgcolor = _system->RGBToColor(_colors[kBGColor][0], _colors[kBGColor][1], _colors[kBGColor][2]);
- _color = _system->RGBToColor(_colors[kColor][0], _colors[kColor][1], _colors[kColor][2]);
- _shadowcolor = _system->RGBToColor(_colors[kShadowColor][0], _colors[kShadowColor][1], _colors[kShadowColor][2]);
- _textcolor = _system->RGBToColor(_colors[kTextColor][0], _colors[kTextColor][1], _colors[kTextColor][2]);
- _textcolorhi = _system->RGBToColor(_colors[kTextColorHi][0], _colors[kTextColorHi][1], _colors[kTextColorHi][2]);
- 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;
-}
-
-void ThemeClassic::deinit() {
- if (_initOk) {
- _system->hideOverlay();
- _screen.free();
- _initOk = false;
- }
-}
-
-void ThemeClassic::refresh() {
- init();
- if (_enabled)
- _system->showOverlay();
-}
-
-void ThemeClassic::enable() {
- init();
- resetDrawArea();
- _system->showOverlay();
- clearAll();
- _enabled = true;
-}
-
-void ThemeClassic::disable() {
- _system->hideOverlay();
- _enabled = false;
-}
-
-void ThemeClassic::openDialog(bool topDialog) {
-#ifndef CT_NO_TRANSPARENCY
- if (!_dialog) {
- _dialog = new DialogState;
- assert(_dialog);
- // first dialog
- _dialog->screen.create(_screen.w, _screen.h, sizeof(OverlayColor));
- }
- memcpy(_dialog->screen.pixels, _screen.pixels, _screen.pitch*_screen.h);
- if (!_enableBlending)
- _dialog->screen.fillRect(Common::Rect(0, 0, _screen.w, _screen.h), _bgcolor);
- else
- blendScreenToDialog();
-#endif
-}
-
-void ThemeClassic::closeAllDialogs() {
-#ifndef CT_NO_TRANSPARENCY
- if (_dialog) {
- _dialog->screen.free();
- delete _dialog;
- _dialog = 0;
- }
- _forceRedraw = true;
-#endif
-}
-
-void ThemeClassic::clearAll() {
- if (!_initOk)
- return;
- _system->clearOverlay();
- // FIXME: problem with the 'pitch'
- _system->grabOverlay((OverlayColor*)_screen.pixels, _screen.w);
-}
-
-void ThemeClassic::updateScreen() {
- _forceRedraw = false;
-}
-
-void ThemeClassic::resetDrawArea() {
- if (_initOk) {
- _drawArea = Common::Rect(0, 0, _screen.w, _screen.h);
- }
-}
-
-int ThemeClassic::getTabSpacing() const {
- return 2;
-}
-int ThemeClassic::getTabPadding() const {
- return 3;
-}
-
-void ThemeClassic::drawDialogBackground(const Common::Rect &r, uint16 hints, WidgetStateInfo state) {
- if (!_initOk)
- return;
-
- restoreBackground(r);
-
-#ifndef CT_NO_TRANSPARENCY
- if ((hints & THEME_HINT_SAVE_BACKGROUND) && !(hints & THEME_HINT_FIRST_DRAW) && !_forceRedraw) {
- addDirtyRect(r);
- return;
- }
-#endif
-
- box(r.left, r.top, r.width(), r.height(), _color, _shadowcolor);
- addDirtyRect(r, (hints & THEME_HINT_SAVE_BACKGROUND) != 0);
-}
-
-void ThemeClassic::drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, TextAlign align, bool inverted, int deltax, bool useEllipsis, FontStyle font) {
- if (!_initOk)
- return;
-
- if (!inverted) {
- restoreBackground(r);
- _font->drawString(&_screen, str, r.left, r.top, r.width(), getColor(state), convertAligment(align), deltax, useEllipsis);
- } else {
- _screen.fillRect(r, getColor(state));
- _font->drawString(&_screen, str, r.left, r.top, r.width(), _bgcolor, convertAligment(align), deltax, useEllipsis);
- }
-
- addDirtyRect(r);
-}
-
-void ThemeClassic::drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state) {
- if (!_initOk)
- return;
- restoreBackground(r);
- font->drawChar(&_screen, ch, r.left, r.top, getColor(state));
- addDirtyRect(r);
-}
-
-void ThemeClassic::drawWidgetBackground(const Common::Rect &r, uint16 hints, WidgetBackground background, WidgetStateInfo state) {
- if (!_initOk || background == kWidgetBackgroundNo)
- return;
-
- restoreBackground(r);
-
-#ifndef CT_NO_TRANSPARENCY
- if ((hints & THEME_HINT_SAVE_BACKGROUND) && !(hints & THEME_HINT_FIRST_DRAW) && !_forceRedraw) {
- addDirtyRect(r);
- return;
- }
-#endif
-
- switch (background) {
- case kWidgetBackgroundBorder:
- box(r.left, r.top, r.width(), r.height(), _color, _shadowcolor);
- break;
-
- //case kWidgetBackgroundPlain:
- //case kWidgetBackgroundBorderSmall:
- default:
- box(r.left, r.top, r.width(), r.height());
- break;
- };
-
- addDirtyRect(r, (hints & THEME_HINT_SAVE_BACKGROUND) != 0);
-}
-
-void ThemeClassic::drawButton(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, uint16 hints) {
- if (!_initOk)
- return;
- restoreBackground(r);
-
- drawWidgetBackground(r, 0, kWidgetBackgroundBorder, state);
-
- const int off = (r.height() - _font->getFontHeight()) / 2;
- _font->drawString(&_screen, str, r.left, r.top+off, r.width(), getColor(state), Graphics::kTextAlignCenter, 0, false);
-
- addDirtyRect(r);
-}
-
-void ThemeClassic::drawSurface(const Common::Rect &r, const Graphics::Surface &surface, WidgetStateInfo state, int alpha, bool themeTrans) {
- if (!_initOk)
- return;
-
- Common::Rect rect(r.left, r.top, r.left + surface.w, r.top + surface.h);
- rect.clip(_screen.w, _screen.h);
-
- if (!rect.isValidRect())
- return;
-
- assert(surface.bytesPerPixel == sizeof(OverlayColor));
-
- OverlayColor *src = (OverlayColor *)surface.pixels;
- OverlayColor *dst = (OverlayColor *)_screen.getBasePtr(rect.left, rect.top);
-
- int w = rect.width();
- int h = rect.height();
-
- while (h--) {
- memcpy(dst, src, surface.pitch);
- src += w;
- // FIXME: this should be pitch
- dst += _screen.w;
- }
- addDirtyRect(r);
-}
-
-void ThemeClassic::drawSlider(const Common::Rect &r, int width, WidgetStateInfo state) {
- if (!_initOk)
- return;
- Common::Rect r2 = r;
-
- restoreBackground(r);
-
- box(r.left, r.top, r.width(), r.height(), _color, _shadowcolor);
- r2.left = r.left + 2;
- r2.top = r.top + 2;
- r2.bottom = r.bottom - 2;
- r2.right = r2.left + width;
- if (r2.right > r.right - 2) {
- r2.right = r.right - 2;
- }
-
- _screen.fillRect(r2, getColor(state));
-
- addDirtyRect(r);
-}
-
-void ThemeClassic::drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, WidgetStateInfo state, TextAlign align) {
- if (!_initOk)
- return;
-
- restoreBackground(r);
-
- box(r.left, r.top, r.width(), r.height());
-
- Common::Point p0, p1;
-
- p0 = Common::Point(r.right + 1 - r.height() / 2, r.top + 4);
- p1 = Common::Point(r.right + 1 - r.height() / 2, r.bottom - 4);
-
- OverlayColor color = getColor(state);
-
- // Evil HACK to draw filled triangles
- // FIXME: The "big" version is pretty ugly.
- for (; p1.y - p0.y > 1; p0.y++, p0.x--, p1.y--, p1.x++) {
- _screen.drawLine(p0.x, p0.y, p1.x, p0.y, color);
- _screen.drawLine(p0.x, p1.y, p1.x, p1.y, color);
- }
-
- if (!sel.empty()) {
- Common::Rect text(r.left + 2, r.top + 3, r.right - 4, r.top + 3 + _font->getFontHeight());
- _font->drawString(&_screen, sel, text.left, text.top, text.width(), color, convertAligment(align), deltax, false);
- }
-
- addDirtyRect(r);
-}
-
-void ThemeClassic::drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state) {
- if (!_initOk)
- return;
-
- Common::Rect r2 = r;
- int checkBoxSize = getFontHeight();
- if (checkBoxSize > r.height()) {
- checkBoxSize = r.height();
- }
- r2.bottom = r2.top + checkBoxSize;
-
- restoreBackground(r2);
-
- box(r.left, r.top, checkBoxSize, checkBoxSize, _color, _shadowcolor);
-
- if (checked) {
- r2.top += 3;
- r2.bottom = r.top + checkBoxSize - 4;
- r2.left += 3;
- r2.right = r.left + checkBoxSize - 4;
-
- OverlayColor c = getColor(state);
-
- // Draw a cross
- _screen.drawLine(r2.left, r2.top, r2.right, r2.bottom, c);
- _screen.drawLine(r2.left, r2.bottom, r2.right, r2.top, c);
-
- if (r2.height() > 5) {
- // Thicken the lines
- _screen.drawLine(r2.left, r2.top + 1, r2.right - 1, r2.bottom, c);
- _screen.drawLine(r2.left + 1, r2.top, r2.right, r2.bottom - 1, c);
- _screen.drawLine(r2.left, r2.bottom - 1, r2.right - 1, r2.top, c);
- _screen.drawLine(r2.left + 1, r2.bottom, r2.right, r2.top + 1, c);
- }
-
- r2 = r;
- }
-
- r2.left += checkBoxSize + 10;
- _font->drawString(&_screen, str, r2.left, r2.top, r2.width(), getColor(state), Graphics::kTextAlignLeft, 0, true);
-
- addDirtyRect(r);
-}
-
-void ThemeClassic::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array<Common::String> &tabs, int active, uint16 hints, int titleVPad, WidgetStateInfo state) {
- if (!_initOk)
- return;
- restoreBackground(r);
-
- for (int i = 0; i < (int)tabs.size(); ++i) {
- if (i == active)
- continue;
- box(r.left + i * tabWidth, r.top+2, tabWidth, tabHeight-2, _color, _shadowcolor);
- _font->drawString(&_screen, tabs[i], r.left + i * tabWidth, r.top+4, tabWidth, getColor(state), Graphics::kTextAlignCenter, 0, true);
- }
-
- if (active >= 0) {
- box(r.left + active * tabWidth, r.top, tabWidth, tabHeight, _color, _shadowcolor, true);
- _font->drawString(&_screen, tabs[active], r.left + active * tabWidth, r.top+titleVPad, tabWidth, getColor(kStateHighlight), Graphics::kTextAlignCenter, 0, true);
-
- _screen.hLine(r.left, r.top + tabHeight, r.left + active * tabWidth + 1, _color);
- _screen.hLine(r.left + active * tabWidth + tabWidth - 2, r.top + tabHeight, r.right, _color);
- _screen.hLine(r.left, r.bottom - 1, r.right - 1, _shadowcolor);
- _screen.vLine(r.left, r.top + tabHeight, r.bottom - 1, _color);
- _screen.vLine(r.right - 1, r.top + tabHeight, r.bottom - 1, _shadowcolor);
- }
-
- addDirtyRect(r);
-}
-
-void ThemeClassic::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState scroll, WidgetStateInfo state) {
- if (!_initOk)
- return;
- restoreBackground(r);
- Common::Rect r2 = r;
- box(r.left, r.top, r.width(), r.height(), _color, _shadowcolor);
-
- const int UP_DOWN_BOX_HEIGHT = r.width() + 1;
- const int B = 3;
- const int arrowSize = (r.width() / 2 - B + 1);
-
- OverlayColor color = 0;
- if (scroll == kScrollbarStateSinglePage) {
- color = _color;
- } else if (scroll == kScrollbarStateUp && state == kStateHighlight) {
- color = _textcolorhi;
- } else {
- color = _textcolor;
- }
-
- // draws the 'up' button
- box(r.left, r.top, r.width(), UP_DOWN_BOX_HEIGHT, _color, _shadowcolor);
- Common::Point p0 = Common::Point(r.left + r.width() / 2, r.top + (UP_DOWN_BOX_HEIGHT - arrowSize - 1) / 2);
- Common::Point p1 = Common::Point(p0.x - arrowSize, p0.y + arrowSize);
- Common::Point p2 = Common::Point(p0.x + arrowSize, p0.y + arrowSize);
- for (; p1.x <= p2.x; ++p1.x)
- _screen.drawLine(p0.x, p0.y, p1.x, p1.y, color);
-
- if (scroll != kScrollbarStateSinglePage) {
- r2.top += sliderY;
- r2.left += 2;
- r2.right -= 2;
- r2.bottom = r2.top + sliderHeight;
- _screen.fillRect(r2, (state == kStateHighlight && scroll == kScrollbarStateSlider) ? _textcolorhi : _textcolor);
- box(r2.left, r2.top, r2.width(), r2.height());
- int y = r2.top + sliderHeight / 2;
- color = (state == kStateHighlight && scroll == kScrollbarStateSlider) ? _color : _bgcolor;
- _screen.hLine(r2.left + 1, y - 2, r2.right - 2, color);
- _screen.hLine(r2.left + 1, y, r2.right - 2, color);
- _screen.hLine(r2.left + 1, y + 2, r2.right - 2, color);
- r2 = r;
- }
-
- r2.top = r2.bottom - UP_DOWN_BOX_HEIGHT;
- if (scroll == kScrollbarStateSinglePage) {
- color = _color;
- } else if (scroll == kScrollbarStateDown && state == kStateHighlight) {
- color = _textcolorhi;
- } else {
- color = _textcolor;
- }
-
- // draws the 'down' button
- box(r2.left, r2.top, r2.width(), UP_DOWN_BOX_HEIGHT, _color, _shadowcolor);
- p0 = Common::Point(r2.left + r2.width() / 2, r2.top + (UP_DOWN_BOX_HEIGHT + arrowSize + 1) / 2);
- p1 = Common::Point(p0.x - arrowSize, p0.y - arrowSize);
- p2 = Common::Point(p0.x + arrowSize, p0.y - arrowSize);
- for (; p1.x <= p2.x; ++p1.x)
- _screen.drawLine(p0.x, p0.y, p1.x, p1.y, color);
-
- addDirtyRect(r);
-}
-
-void ThemeClassic::drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo state) {
- if (!_initOk)
- return;
-
- OverlayColor color = 0;
- if (erase) {
- color = _bgcolor;
- } else {
- color = getColor(state);
- }
-
- _screen.vLine(r.left, r.top, r.bottom - 2, color);
- addDirtyRect(r);
-}
-
-void ThemeClassic::drawLineSeparator(const Common::Rect &r, WidgetStateInfo state) {
- if (!_initOk)
- return;
- _screen.hLine(r.left - 1, r.top + r.height() / 2, r.right, _shadowcolor);
- _screen.hLine(r.left, r.top + 1 + r.height() / 2, r.right, _color);
- addDirtyRect(r);
-}
-
-// intern drawing
-
-void ThemeClassic::restoreBackground(Common::Rect r, bool special) {
- r.clip(_screen.w, _screen.h);
- r.clip(_drawArea);
-#ifdef CT_NO_TRANSPARENCY
- _screen.fillRect(r, _bgcolor);
-#else
- if (_dialog) {
- if (!_dialog->screen.pixels) {
- _screen.fillRect(r, _bgcolor);
- return;
- }
- const OverlayColor *src = (const OverlayColor*)_dialog->screen.getBasePtr(r.left, r.top);
- OverlayColor *dst = (OverlayColor*)_screen.getBasePtr(r.left, r.top);
-
- int h = r.height();
- int w = r.width();
- while (h--) {
- memcpy(dst, src, w*sizeof(OverlayColor));
- src += _dialog->screen.w;
- dst += _screen.w;
- }
- } else {
- _screen.fillRect(r, _bgcolor);
- }
-#endif
-}
-
-bool ThemeClassic::addDirtyRect(Common::Rect r, bool save, bool special) {
- // TODO: implement proper dirty rect handling
- // FIXME: problem with the 'pitch'
- r.clip(_screen.w, _screen.h);
- r.clip(_drawArea);
- _system->copyRectToOverlay((OverlayColor*)_screen.getBasePtr(r.left, r.top), _screen.w, r.left, r.top, r.width(), r.height());
-#ifndef CT_NO_TRANSPARENCY
- if (_dialog && save) {
- if (_dialog->screen.pixels) {
- OverlayColor *dst = (OverlayColor*)_dialog->screen.getBasePtr(r.left, r.top);
- const OverlayColor *src = (const OverlayColor*)_screen.getBasePtr(r.left, r.top);
- int h = r.height();
- while (h--) {
- memcpy(dst, src, r.width()*sizeof(OverlayColor));
- dst += _dialog->screen.w;
- src += _screen.w;
- }
- }
- }
-#endif
- return true;
-}
-
-void ThemeClassic::box(int x, int y, int width, int height, OverlayColor colorA, OverlayColor colorB, bool skipLastRow) {
- if (y >= 0) {
- _screen.hLine(x + 1, y, x + width - 2, colorA);
- _screen.hLine(x, y + 1, x + width - 1, colorA);
- }
- int drawY = y;
- if (drawY < 0) {
- height += drawY;
- drawY = 0;
- }
- _screen.vLine(x, drawY + 1, drawY + height - 2, colorA);
- _screen.vLine(x + 1, drawY, drawY + height - 1, colorA);
- _screen.vLine(x + width - 1, drawY + 1, drawY + height - 2, colorB);
- _screen.vLine(x + width - 2, drawY + 1, drawY + height - 1, colorB);
-
- if (y + height >= 0 && !skipLastRow) {
- _screen.hLine(x + 1, drawY + height - 2, x + width - 1, colorB);
- _screen.hLine(x + 1, drawY + height - 1, x + width - 2, colorB);
- }
-}
-
-void ThemeClassic::box(int x, int y, int w, int h) {
- _screen.hLine(x, y, x + w - 1, _color);
- _screen.hLine(x, y + h - 1, x +w - 1, _shadowcolor);
- _screen.vLine(x, y, y + h - 1, _color);
- _screen.vLine(x + w - 1, y, y + h - 1, _shadowcolor);
-}
-
-OverlayColor ThemeClassic::getColor(State state) {
- OverlayColor usedColor = _color;
- switch (state) {
- case kStateEnabled:
- usedColor = _textcolor;
- break;
-
- case kStateHighlight:
- usedColor = _textcolorhi;
- break;
-
- default:
- break;
- }
- return usedColor;
-}
-
-#ifndef CT_NO_TRANSPARENCY
-void ThemeClassic::blendScreenToDialog() {
- Common::Rect rect(0, 0, _screen.w, _screen.h);
-
- if (!rect.isValidRect())
- return;
-
- if (_system->hasFeature(OSystem::kFeatureOverlaySupportsAlpha)) {
- int a, r, g, b;
- uint8 aa, ar, ag, ab;
- _system->colorToARGB(_bgcolor, aa, ar, ag, ab);
- a = aa*3/(3+1);
- if (a < 1)
- return;
- r = ar * a;
- g = ag * a;
- b = ab * a;
-
- OverlayColor *ptr = (OverlayColor*)_dialog->screen.getBasePtr(rect.left, rect.top);
-
- int h = rect.height();
- int w = rect.width();
- while (h--) {
- for (int i = 0; i < w; i++) {
- _system->colorToARGB(ptr[i], aa, ar, ag, ab);
- int a2 = aa + a - (a*aa)/255;
- ptr[i] = _system->ARGBToColor(a2,
- ((255-a)*aa*ar/255+r)/a2,
- ((255-a)*aa*ag/255+g)/a2,
- ((255-a)*aa*ab/255+b)/a2);
- }
- ptr += _screen.w;
- }
- } else {
- int r, g, b;
- uint8 ar, ag, ab;
- _system->colorToRGB(_bgcolor, ar, ag, ab);
- r = ar * 3;
- g = ag * 3;
- b = ab * 3;
-
- OverlayColor *ptr = (OverlayColor*)_dialog->screen.getBasePtr(rect.left, rect.top);
-
- int h = rect.height();
- int w = rect.width();
-
- while (h--) {
- for (int i = 0; i < w; i++) {
- _system->colorToRGB(ptr[i], ar, ag, ab);
- ptr[i] = _system->RGBToColor((ar + r) / (3+1),
- (ag + g) / (3+1),
- (ab + b) / (3+1));
- }
- ptr += _screen.w;
- }
- }
-}
-#endif
-
-void ThemeClassic::setupConfig() {
- if (_configFile.hasSection("theme")) {
- if (loadConfig())
- return;
- }
-
- static const uint8 colors[][3] = {
- { 104, 104, 104 },
- { 64, 64, 64 },
- { 0, 0, 0, },
- { 32, 160, 32 },
- { 0, 255, 0 }
- };
-
- memcpy(_colors, colors, sizeof(colors));
-}
-
-bool ThemeClassic::loadConfig() {
- Common::String temp;
- _configFile.getKey("version", "theme", temp);
- if (atoi(temp.c_str()) != THEME_VERSION) {
- // TODO: improve this detection and handle it nicer
- warning("Theme config uses a different version (you have: '%s', needed is: '%d')", temp.c_str(), THEME_VERSION);
- _configFile.clear();
-
- // force a theme reload here
- loadTheme(_defaultConfig);
- return false;
- }
-
- temp.clear();
- _configFile.getKey("type", "theme", temp);
- if (0 != temp.compareToIgnoreCase("classic")) {
- warning("Theme config is not for the classic style theme");
- _configFile.clear();
-
- // force a theme reload here
- loadTheme(_defaultConfig);
- return false;
- }
-
- getColorFromConfig("color", _colors[kColor][0], _colors[kColor][1], _colors[kColor][2]);
- getColorFromConfig("shadowcolor", _colors[kShadowColor][0], _colors[kShadowColor][1], _colors[kShadowColor][2]);
- getColorFromConfig("bgcolor", _colors[kBGColor][0], _colors[kBGColor][1], _colors[kBGColor][2]);
- getColorFromConfig("textcolor", _colors[kTextColor][0], _colors[kTextColor][1], _colors[kTextColor][2]);
- getColorFromConfig("textcolorhi", _colors[kTextColorHi][0], _colors[kTextColorHi][1], _colors[kTextColorHi][2]);
-
- temp.clear();
- temp = _evaluator->getStringVar("font");
- if (temp.empty() || 0 == temp.compareToIgnoreCase("builtin")) {
- if (!_fontName.empty())
- delete _font;
- _fontName.clear();
- } else if (temp != _fontName) {
- if (!_fontName.empty())
- delete _font;
- _font = loadFont(temp.c_str());
- _fontName = temp;
- }
-
- _enableBlending = (_evaluator->getVar("blending") != 0);
-
- return true;
-}
-
-} // end of namespace GUI
-
diff --git a/gui/ThemeClassic.h b/gui/ThemeClassic.h
deleted file mode 100644
index 12dc8d8068..0000000000
--- a/gui/ThemeClassic.h
+++ /dev/null
@@ -1,127 +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 GUI_THEMECLASSIC_H
-#define GUI_THEMECLASSIC_H
-
-#include "gui/theme.h"
-
-namespace GUI {
-
-// enable this to disable transparency support for the classic theme
-//#define CT_NO_TRANSPARENCY
-
-class ThemeClassic : public Theme {
-public:
- ThemeClassic(OSystem *system, const Common::String &config = "classic", const Common::ConfigFile *cfg = 0);
- virtual ~ThemeClassic();
-
- bool init();
- void deinit();
-
- void refresh();
-
- void enable();
- void disable();
-
- void openDialog(bool topDialog);
- void closeAllDialogs();
-
- void clearAll();
- void updateScreen();
-
- void resetDrawArea();
-
- 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; }
-
- 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);
-
- void drawWidgetBackground(const Common::Rect &r, uint16 hints, WidgetBackground background, WidgetStateInfo state);
- void drawButton(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, uint16 hints);
- void drawSurface(const Common::Rect &r, const Graphics::Surface &surface, WidgetStateInfo state, int alpha, bool themeTrans);
- void drawSlider(const Common::Rect &r, int width, WidgetStateInfo state);
- void drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state);
- void drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array<Common::String> &tabs, int active, uint16 hints, int titleVPad, WidgetStateInfo state);
- void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState, WidgetStateInfo state);
- void drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, WidgetStateInfo state, TextAlign align);
- void drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo state);
- void drawLineSeparator(const Common::Rect &r, WidgetStateInfo state);
- void restoreBackground(Common::Rect r, bool special = false);
- bool addDirtyRect(Common::Rect r, bool save = false, bool special = false);
-
- int getTabSpacing() const;
- int getTabPadding() const;
-
-private:
- void box(int x, int y, int width, int height, OverlayColor colorA, OverlayColor colorB, bool skipLastRow = false);
- void box(int x, int y, int width, int height);
-
- OverlayColor getColor(State state);
-
- OSystem *_system;
- Graphics::Surface _screen;
-
-#ifndef CT_NO_TRANSPARENCY
- struct DialogState {
- Graphics::Surface screen;
- } *_dialog;
-
- void blendScreenToDialog();
-#endif
- bool _enableBlending;
-
- bool _forceRedraw;
- bool _initOk;
- bool _enabled;
-
- Common::String _fontName;
- const Graphics::Font *_font;
- OverlayColor _color, _shadowcolor;
- OverlayColor _bgcolor;
- OverlayColor _textcolor;
- OverlayColor _textcolorhi;
-
- enum {
- kColor = 0,
- kShadowColor = 1,
- kBGColor = 2,
- kTextColor = 3,
- kTextColorHi = 4,
- kMaxColors = 5
- };
- uint8 _colors[kMaxColors][3];
-
- void setupConfig();
- bool loadConfig();
-};
-
-} // end of namespace GUI
-
-#endif
-
diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp
new file mode 100644
index 0000000000..5ed142cb31
--- /dev/null
+++ b/gui/ThemeEngine.cpp
@@ -0,0 +1,1070 @@
+/* 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 "common/fs.h"
+#include "common/unzip.h"
+#include "graphics/imageman.h"
+#include "graphics/cursorman.h"
+#include "gui/launcher.h"
+
+#include "gui/ThemeEngine.h"
+#include "gui/ThemeEval.h"
+#include "graphics/VectorRenderer.h"
+
+#define GUI_ENABLE_BUILTIN_THEME
+
+namespace GUI {
+
+using namespace Graphics;
+
+const char *ThemeEngine::rendererModeLabels[] = {
+ "Disabled GFX",
+ "Stardard Renderer (16bpp)",
+ "Antialiased Renderer (16bpp)"
+};
+
+
+/**********************************************************
+ * 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) :
+ _vectorRenderer(0), _system(0), _graphicsMode(kGfxDisabled), _font(0),
+ _screen(0), _backBuffer(0), _bytesPerPixel(0), _initOk(false),
+ _themeOk(false), _enabled(false), _buffering(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);
+}
+
+
+/**********************************************************
+ * Theme setup/initialization
+ *********************************************************/
+bool ThemeEngine::init() {
+ // reset everything and reload the graphics
+ deinit();
+ setGraphicsMode(_graphicsMode);
+
+ if (_screen->pixels && _backBuffer->pixels) {
+ _initOk = true;
+ clearAll();
+ resetDrawArea();
+ }
+
+ if (_screen->w >= 400 && _screen->h >= 300) {
+ _font = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
+ } else {
+ _font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
+ }
+
+ if (isThemeLoadingRequired() || !_themeOk) {
+ loadTheme(_themeFileName);
+ }
+
+ return true;
+}
+
+void ThemeEngine::deinit() {
+ if (_initOk) {
+ _system->hideOverlay();
+ freeRenderer();
+ freeScreen();
+ freeBackbuffer();
+ _initOk = false;
+ }
+}
+
+void ThemeEngine::unloadTheme() {
+ if (!_themeOk)
+ return;
+
+ for (int i = 0; i < kDrawDataMAX; ++i) {
+ delete _widgets[i];
+ _widgets[i] = 0;
+ }
+
+ for (int i = 0; i < kTextDataMAX; ++i) {
+ delete _texts[i];
+ _texts[i] = 0;
+ }
+
+ for (ImagesMap::iterator i = _bitmaps.begin(); i != _bitmaps.end(); ++i)
+ ImageMan.unregisterSurface(i->_key);
+
+ if (_themeFileName.hasSuffix(".zip"))
+ ImageMan.removeArchive(_themeFileName);
+
+ Common::File::resetDefaultDirectories();
+
+ _themeEval->reset();
+ _themeOk = false;
+}
+
+void ThemeEngine::clearAll() {
+ if (!_initOk)
+ return;
+
+ _system->clearOverlay();
+ _system->grabOverlay((OverlayColor*)_screen->pixels, _screen->w);
+}
+
+void ThemeEngine::refresh() {
+ init();
+ if (_enabled) {
+ _system->showOverlay();
+
+ if (_useCursor) {
+ CursorMan.replaceCursorPalette(_cursorPal, 0, MAX_CURS_COLORS);
+ CursorMan.replaceCursor(_cursor, _cursorWidth, _cursorHeight, _cursorHotspotX, _cursorHotspotY, 255, _cursorTargetScale);
+ }
+ }
+}
+
+void ThemeEngine::enable() {
+ init();
+ resetDrawArea();
+
+ if (_useCursor)
+ setUpCursor();
+
+ _system->showOverlay();
+ clearAll();
+ _enabled = true;
+}
+
+void ThemeEngine::disable() {
+ _system->hideOverlay();
+
+ if (_useCursor) {
+ CursorMan.popCursorPalette();
+ CursorMan.popCursor();
+ }
+
+ _enabled = false;
+}
+
+template<typename PixelType>
+void ThemeEngine::screenInit(bool backBuffer) {
+ uint32 width = _system->getOverlayWidth();
+ uint32 height = _system->getOverlayHeight();
+
+ if (backBuffer) {
+ freeBackbuffer();
+ _backBuffer = new Surface;
+ _backBuffer->create(width, height, sizeof(PixelType));
+ }
+
+ freeScreen();
+ _screen = new Surface;
+ _screen->create(width, height, sizeof(PixelType));
+ _system->clearOverlay();
+}
+
+void ThemeEngine::setGraphicsMode(GraphicsMode mode) {
+ switch (mode) {
+ case kGfxStandard16bit:
+ case kGfxAntialias16bit:
+ _bytesPerPixel = sizeof(uint16);
+ screenInit<uint16>(kEnableBackCaching);
+ break;
+
+ default:
+ error("Invalid graphics mode");
+ }
+
+ freeRenderer();
+ _vectorRenderer = createRenderer(mode);
+ _vectorRenderer->setSurface(_screen);
+}
+
+bool ThemeEngine::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 ThemeEngine::drawCached(DrawData type, const Common::Rect &r) {
+ assert(_widgets[type]->_surfaceCache->bytesPerPixel == _screen->bytesPerPixel);
+ _vectorRenderer->blitSurface(_widgets[type]->_surfaceCache, r);
+}
+
+void ThemeEngine::calcBackgroundOffset(DrawData type) {
+ uint maxShadow = 0;
+ for (Common::List<Graphics::DrawStep>::const_iterator step = _widgets[type]->_steps.begin();
+ step != _widgets[type]->_steps.end(); ++step) {
+ if ((step->autoWidth || step->autoHeight) && step->shadow > maxShadow)
+ maxShadow = step->shadow;
+
+ if (step->drawingCall == &Graphics::VectorRenderer::drawCallback_BEVELSQ && step->bevel > maxShadow)
+ maxShadow = step->bevel;
+ }
+
+ _widgets[type]->_backgroundOffset = maxShadow;
+}
+
+void ThemeEngine::restoreBackground(Common::Rect r, bool special) {
+ r.clip(_screen->w, _screen->h); // AHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHA... Oh god. :(
+ _vectorRenderer->blitSurface(_backBuffer, r);
+}
+
+
+
+
+/**********************************************************
+ * Theme elements management
+ *********************************************************/
+void ThemeEngine::addDrawStep(const Common::String &drawDataId, Graphics::DrawStep step) {
+ DrawData id = getDrawDataId(drawDataId);
+
+ assert(_widgets[id] != 0);
+ _widgets[id]->_steps.push_back(step);
+}
+
+bool ThemeEngine::addTextData(const Common::String &drawDataId, const Common::String &textDataId, TextAlign alignH, TextAlignVertical alignV) {
+ DrawData id = getDrawDataId(drawDataId);
+ TextData textId = getTextDataId(textDataId);
+
+ if (id == -1 || textId == -1 || !_widgets[id])
+ return false;
+
+ _widgets[id]->_textDataId = textId;
+ _widgets[id]->_textAlignH = alignH;
+ _widgets[id]->_textAlignV = alignV;
+
+ return true;
+}
+
+bool ThemeEngine::addFont(const Common::String &fontId, const Common::String &file, int r, int g, int b) {
+ TextData textId = getTextDataId(fontId);
+
+ if (textId == -1)
+ return false;
+
+ if (_texts[textId] != 0)
+ delete _texts[textId];
+
+ _texts[textId] = new TextDrawData;
+
+ if (file == "default") {
+ _texts[textId]->_fontPtr = _font;
+ } else {
+ _texts[textId]->_fontPtr = FontMan.getFontByName(file);
+
+ if (!_texts[textId]->_fontPtr) {
+ _texts[textId]->_fontPtr = loadFont(file.c_str());
+
+ if (!_texts[textId]->_fontPtr)
+ error("Couldn't load %s font '%s'", fontId.c_str(), file.c_str());
+
+ FontMan.assignFontToName(file, _texts[textId]->_fontPtr);
+ }
+ }
+
+ _texts[textId]->_color.r = r;
+ _texts[textId]->_color.g = g;
+ _texts[textId]->_color.b = b;
+ return true;
+
+}
+
+bool ThemeEngine::addBitmap(const Common::String &filename) {
+ if (_bitmaps.contains(filename)) {
+ ImageMan.unregisterSurface(filename);
+ }
+
+ ImageMan.registerSurface(filename, 0);
+ _bitmaps[filename] = ImageMan.getSurface(filename);
+
+ return _bitmaps[filename] != 0;
+}
+
+bool ThemeEngine::addDrawData(const Common::String &data, bool cached) {
+ DrawData data_id = getDrawDataId(data);
+
+ if (data_id == -1)
+ return false;
+
+ if (_widgets[data_id] != 0)
+ delete _widgets[data_id];
+
+ _widgets[data_id] = new WidgetDrawData;
+ _widgets[data_id]->_cached = cached;
+ _widgets[data_id]->_buffer = kDrawDataDefaults[data_id].buffer;
+ _widgets[data_id]->_surfaceCache = 0;
+ _widgets[data_id]->_textDataId = -1;
+
+ return true;
+}
+
+
+/**********************************************************
+ * Theme XML loading
+ *********************************************************/
+bool ThemeEngine::loadTheme(Common::String fileName) {
+ unloadTheme();
+
+ if (fileName != "builtin") {
+ if (fileName.hasSuffix(".zip"))
+ ImageMan.addArchive(fileName);
+ else
+ Common::File::addDefaultDirectory(fileName);
+ }
+
+ if (fileName == "builtin") {
+ if (!loadDefaultXML())
+ error("Could not load default embeded theme");
+ }
+ else if (!loadThemeXML(fileName)) {
+ warning("Could not parse custom theme '%s'. Falling back to default theme", fileName.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) {
+ warning("Missing data asset: '%s'", kDrawDataDefaults[i].name);
+ } else {
+ calcBackgroundOffset((DrawData)i);
+
+ // TODO: draw the cached widget to the cache surface
+ if (_widgets[i]->_cached) {}
+ }
+ }
+
+ _themeOk = true;
+ return true;
+}
+
+bool ThemeEngine::loadDefaultXML() {
+
+ // The default XML theme is included on runtime from a pregenerated
+ // file inside the themes directory.
+ // Use the Python script "makedeftheme.py" to convert a normal XML theme
+ // into the "default.inc" file, which is ready to be included in the code.
+ bool result;
+
+#ifdef GUI_ENABLE_BUILTIN_THEME
+ const char *defaultXML =
+#include "themes/default.inc"
+ ;
+
+ if (!parser()->loadBuffer((const byte*)defaultXML, strlen(defaultXML), false))
+ return false;
+
+ _themeName = "ScummVM Classic Theme (Builtin Version)";
+ _themeFileName = "builtin";
+
+ result = parser()->parse();
+ parser()->close();
+
+ return result;
+#else
+ warning("The built-in theme is not enabled in the current build. Please load an external theme");
+ return false;
+#endif
+}
+
+bool ThemeEngine::loadThemeXML(Common::String themeName) {
+ assert(_parser);
+ _themeName.clear();
+
+ char fileNameBuffer[32];
+ Common::String stxHeader;
+ int parseCount = 0;
+ bool failed = false;
+
+#ifdef USE_ZLIB
+ Common::ZipArchive zipFile(themeName.c_str());
+ Common::ArchiveMemberList zipContents;
+
+ if (zipFile.isOpen() && zipFile.listMembers(zipContents)) {
+
+// for (uint i = 0; i < zipContents.size(); ++i) {
+ for (Common::ArchiveMemberList::iterator za = zipContents.begin(); za != zipContents.end(); ++za) {
+ if (!failed && matchString((*za)->getName().c_str(), "*.stx")) {
+ if (parser()->loadStream((*za)->open()) == false) {
+ warning("Failed to load stream for zipped file '%s'", fileNameBuffer);
+ failed = true;
+ }
+
+ if (parser()->parse() == false) {
+ warning("Theme parsing failed on zipped file '%s'.", fileNameBuffer);
+ failed = true;
+ }
+
+ parser()->close();
+ parseCount++;
+ } else if ((*za)->getName() == "THEMERC") {
+ Common::SeekableReadStream *stream = (*za)->open();
+ stxHeader = stream->readLine();
+
+ if (!themeConfigParseHeader(stxHeader.c_str(), _themeName)) {
+ warning("Corrupted 'THEMERC' file in theme '%s'", _themeFileName.c_str());
+ failed = true;
+ }
+
+ delete stream;
+ }
+ }
+ } else {
+#endif
+
+ FSNode node(themeName);
+ if (node.exists() && node.isReadable() && node.isDirectory()) {
+ FSList fslist;
+ if (!node.getChildren(fslist, FSNode::kListFilesOnly))
+ return false;
+
+ for (FSList::const_iterator i = fslist.begin(); i != fslist.end(); ++i) {
+ if (!failed && i->getName().hasSuffix(".stx")) {
+ parseCount++;
+
+ if (parser()->loadFile(*i) == false) {
+ warning("Failed to load STX file '%s'", i->getName().c_str());
+ failed = true;
+ }
+
+ if (parser()->parse() == false) {
+ warning("Failed to parse STX file '%s'", i->getName().c_str());
+ failed = true;
+ }
+
+ parser()->close();
+ } else if (i->getName() == "THEMERC") {
+ Common::File f;
+ f.open(*i);
+ stxHeader = f.readLine();
+
+ if (!themeConfigParseHeader(stxHeader.c_str(), _themeName)) {
+ warning("Corrupted 'THEMERC' file in theme '%s'", _themeFileName.c_str());
+ failed = true;
+ }
+ }
+ }
+ }
+#ifdef USE_ZLIB
+ }
+#endif
+
+ return (parseCount > 0 && _themeName.empty() == false && failed == false);
+}
+
+
+
+/**********************************************************
+ * Drawing Queue management
+ *********************************************************/
+void ThemeEngine::queueDD(DrawData type, const Common::Rect &r, uint32 dynamic) {
+ if (_widgets[type] == 0)
+ return;
+
+ Common::Rect area = r;
+ area.clip(_screen->w, _screen->h);
+
+ ThemeItemDrawData *q = new ThemeItemDrawData(this, _widgets[type], area, dynamic);
+
+ if (_buffering) {
+ if (_widgets[type]->_buffer) {
+ _bufferQueue.push_back(q);
+ } else {
+ if (kDrawDataDefaults[type].parent != kDDNone && kDrawDataDefaults[type].parent != type)
+ queueDD(kDrawDataDefaults[type].parent, r);
+
+ _screenQueue.push_back(q);
+ }
+ } else {
+ q->drawSelf(!_widgets[type]->_buffer, _widgets[type]->_buffer);
+ delete q;
+ }
+}
+
+void ThemeEngine::queueDDText(TextData type, const Common::Rect &r, const Common::String &text, bool restoreBg,
+ bool ellipsis, TextAlign alignH, TextAlignVertical alignV, int deltax) {
+
+ if (_texts[type] == 0)
+ return;
+
+ Common::Rect area = r;
+ area.clip(_screen->w, _screen->h);
+
+ ThemeItemTextData *q = new ThemeItemTextData(this, _texts[type], area, text, alignH, alignV, ellipsis, restoreBg, deltax);
+
+ if (_buffering) {
+ _screenQueue.push_back(q);
+ } else {
+ q->drawSelf(true, false);
+ delete q;
+ }
+}
+
+void ThemeEngine::queueBitmap(const Graphics::Surface *bitmap, const Common::Rect &r, bool alpha) {
+
+ Common::Rect area = r;
+ area.clip(_screen->w, _screen->h);
+
+ ThemeItemBitmap *q = new ThemeItemBitmap(this, area, bitmap, alpha);
+
+ if (_buffering) {
+ _bufferQueue.push_back(q);
+ } else {
+ q->drawSelf(true, false);
+ delete q;
+ }
+}
+
+
+
+/**********************************************************
+ * Widget drawing functions
+ *********************************************************/
+void ThemeEngine::drawButton(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, uint16 hints) {
+ if (!ready())
+ return;
+
+ DrawData dd = kDDButtonIdle;
+
+ if (state == kStateEnabled)
+ dd = kDDButtonIdle;
+ else if (state == kStateHighlight)
+ dd = kDDButtonHover;
+ else if (state == kStateDisabled)
+ dd = kDDButtonDisabled;
+
+ queueDD(dd, r);
+ queueDDText(getTextData(dd), r, str, false, false, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV);
+}
+
+void ThemeEngine::drawLineSeparator(const Common::Rect &r, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ queueDD(kDDSeparator, r);
+}
+
+void ThemeEngine::drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ Common::Rect r2 = r;
+ DrawData dd = kDDCheckboxDefault;
+
+ if (checked)
+ dd = kDDCheckboxSelected;
+
+ if (state == kStateDisabled)
+ dd = kDDCheckboxDisabled;
+
+ TextData td = (state == kStateHighlight) ? kTextDataHover : getTextData(dd);
+ const int checkBoxSize = MIN((int)r.height(), getFontHeight());
+
+ r2.bottom = r2.top + checkBoxSize;
+ r2.right = r2.left + checkBoxSize;
+
+ queueDD(dd, r2);
+
+ r2.left = r2.right + checkBoxSize;
+ r2.right = r.right;
+
+ queueDDText(td, r2, str, false, false, _widgets[kDDCheckboxDefault]->_textAlignH, _widgets[dd]->_textAlignV);
+}
+
+void ThemeEngine::drawSlider(const Common::Rect &r, int width, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ DrawData dd = kDDSliderFull;
+
+ if (state == kStateHighlight)
+ dd = kDDSliderHover;
+ else if (state == kStateDisabled)
+ dd = kDDSliderDisabled;
+
+ Common::Rect r2 = r;
+ r2.setWidth(MIN((int16)width, r.width()));
+// r2.top++; r2.bottom--; r2.left++; r2.right--;
+
+ drawWidgetBackground(r, 0, kWidgetBackgroundSlider, kStateEnabled);
+
+ if (width > r.width() * 5 / 100)
+ queueDD(dd, r2);
+}
+
+void ThemeEngine::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState scrollState, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ queueDD(kDDScrollbarBase, r);
+
+ Common::Rect r2 = r;
+ const int buttonExtra = (r.width() * 120) / 100;
+
+ r2.bottom = r2.top + buttonExtra;
+ queueDD(scrollState == kScrollbarStateUp ? kDDScrollbarButtonHover : kDDScrollbarButtonIdle, r2, Graphics::VectorRenderer::kTriangleUp);
+
+ r2.translate(0, r.height() - r2.height());
+ queueDD(scrollState == kScrollbarStateDown ? kDDScrollbarButtonHover : kDDScrollbarButtonIdle, r2, Graphics::VectorRenderer::kTriangleDown);
+
+ r2 = r;
+ r2.left += 1;
+ r2.right -= 1;
+ r2.top += sliderY;
+ r2.bottom = r2.top + sliderHeight - 1;
+
+ r2.top += r.width() / 5;
+ r2.bottom -= r.width() / 5;
+ queueDD(scrollState == kScrollbarStateSlider ? kDDScrollbarHandleHover : kDDScrollbarHandleIdle, r2);
+}
+
+void ThemeEngine::drawDialogBackground(const Common::Rect &r, DialogBackground bgtype, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ switch (bgtype) {
+ case kDialogBackgroundMain:
+ queueDD(kDDMainDialogBackground, r);
+ break;
+
+ case kDialogBackgroundSpecial:
+ queueDD(kDDSpecialColorBackground, r);
+ break;
+
+ case kDialogBackgroundPlain:
+ queueDD(kDDPlainColorBackground, r);
+ break;
+
+ case kDialogBackgroundDefault:
+ queueDD(kDDDefaultBackground, r);
+ break;
+ }
+}
+
+void ThemeEngine::drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ if (erase) {
+ restoreBackground(r);
+ addDirtyRect(r);
+ } else
+ queueDD(kDDCaret, r);
+}
+
+void ThemeEngine::drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, WidgetStateInfo state, TextAlign align) {
+ if (!ready())
+ return;
+
+ DrawData dd = (state == kStateHighlight) ? kDDPopUpHover : kDDPopUpIdle;
+
+ queueDD(dd, r);
+
+ if (!sel.empty()) {
+ Common::Rect text(r.left, r.top, r.right - 16, r.bottom);
+ queueDDText(getTextData(dd), text, sel, false, false, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV, deltax);
+ }
+}
+
+void ThemeEngine::drawSurface(const Common::Rect &r, const Graphics::Surface &surface, WidgetStateInfo state, int alpha, bool themeTrans) {
+ if (!ready())
+ return;
+
+ queueBitmap(&surface, r, themeTrans);
+}
+
+void ThemeEngine::drawWidgetBackground(const Common::Rect &r, uint16 hints, WidgetBackground background, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ switch (background) {
+ case kWidgetBackgroundBorderSmall:
+ queueDD(kDDWidgetBackgroundSmall, r);
+ break;
+
+ case kWidgetBackgroundEditText:
+ queueDD(kDDWidgetBackgroundEditText, r);
+ break;
+
+ case kWidgetBackgroundSlider:
+ queueDD(kDDWidgetBackgroundSlider, r);
+ break;
+
+ default:
+ queueDD(kDDWidgetBackgroundDefault, r);
+ break;
+ }
+}
+
+void ThemeEngine::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array<Common::String> &tabs, int active, uint16 hints, int titleVPad, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ const int tabOffset = 2;
+ tabWidth -= tabOffset;
+
+ queueDD(kDDTabBackground, Common::Rect(r.left, r.top, r.right, r.top + tabHeight));
+
+ for (int i = 0; i < (int)tabs.size(); ++i) {
+ if (i == active)
+ continue;
+
+ Common::Rect tabRect(r.left + i * (tabWidth + tabOffset), r.top, r.left + i * (tabWidth + tabOffset) + tabWidth, r.top + tabHeight);
+ queueDD(kDDTabInactive, tabRect);
+ queueDDText(getTextData(kDDTabInactive), tabRect, tabs[i], false, false, _widgets[kDDTabInactive]->_textAlignH, _widgets[kDDTabInactive]->_textAlignV);
+ }
+
+ if (active >= 0) {
+ Common::Rect tabRect(r.left + active * (tabWidth + tabOffset), r.top, r.left + active * (tabWidth + tabOffset) + tabWidth, r.top + tabHeight);
+ const uint16 tabLeft = active * (tabWidth + tabOffset);
+ const uint16 tabRight = MAX(r.right - tabRect.right, 0);
+ queueDD(kDDTabActive, tabRect, (tabLeft << 16) | (tabRight & 0xFFFF));
+ queueDDText(getTextData(kDDTabActive), tabRect, tabs[active], false, false, _widgets[kDDTabActive]->_textAlignH, _widgets[kDDTabActive]->_textAlignV);
+ }
+}
+
+void ThemeEngine::drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, TextAlign align, bool inverted, int deltax, bool useEllipsis, FontStyle font) {
+ if (!ready())
+ return;
+
+ if (inverted) {
+ queueDD(kDDTextSelectionBackground, r);
+ queueDDText(kTextDataInverted, r, str, false, useEllipsis, align, kTextAlignVCenter, deltax);
+ return;
+ }
+
+ switch (font) {
+ case kFontStyleNormal:
+ queueDDText(kTextDataNormalFont, r, str, true, useEllipsis, align, kTextAlignVCenter, deltax);
+ return;
+
+ default:
+ break;
+ }
+
+ switch (state) {
+ case kStateDisabled:
+ queueDDText(kTextDataDisabled, r, str, true, useEllipsis, align, kTextAlignVCenter, deltax);
+ return;
+
+ case kStateHighlight:
+ queueDDText(kTextDataHover, r, str, true, useEllipsis, align, kTextAlignVCenter, deltax);
+ return;
+
+ case kStateEnabled:
+ queueDDText(kTextDataDefault, r, str, true, useEllipsis, align, kTextAlignVCenter, deltax);
+ return;
+ }
+}
+
+void ThemeEngine::drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ restoreBackground(r);
+ font->drawChar(_screen, ch, r.left, r.top, 0);
+ addDirtyRect(r);
+}
+
+void ThemeEngine::debugWidgetPosition(const char *name, const Common::Rect &r) {
+ _font->drawString(_screen, name, r.left, r.top, r.width(), 0xFFFF, Graphics::kTextAlignRight, 0, true);
+ _screen->hLine(r.left, r.top, r.right, 0xFFFF);
+ _screen->hLine(r.left, r.bottom, r.right, 0xFFFF);
+ _screen->vLine(r.left, r.top, r.bottom, 0xFFFF);
+ _screen->vLine(r.right, r.top, r.bottom, 0xFFFF);
+}
+
+
+
+/**********************************************************
+ * Screen/overlay management
+ *********************************************************/
+void ThemeEngine::updateScreen() {
+ if (!_bufferQueue.empty()) {
+ _vectorRenderer->setSurface(_backBuffer);
+
+ for (Common::List<ThemeItem*>::iterator q = _bufferQueue.begin(); q != _bufferQueue.end(); ++q) {
+ (*q)->drawSelf(true, false);
+ delete *q;
+ }
+
+ _vectorRenderer->setSurface(_screen);
+ _vectorRenderer->blitSurface(_backBuffer, Common::Rect(0, 0, _screen->w, _screen->h));
+ _bufferQueue.clear();
+ }
+
+ if (!_screenQueue.empty()) {
+ _vectorRenderer->disableShadows();
+ for (Common::List<ThemeItem*>::iterator q = _screenQueue.begin(); q != _screenQueue.end(); ++q) {
+ (*q)->drawSelf(true, false);
+ delete *q;
+ }
+
+ _vectorRenderer->enableShadows();
+ _screenQueue.clear();
+ }
+
+ renderDirtyScreen();
+}
+
+void ThemeEngine::renderDirtyScreen() {
+ if (_dirtyScreen.empty())
+ return;
+
+ Common::List<Common::Rect>::const_iterator i, j;
+ for (i = _dirtyScreen.begin(); i != _dirtyScreen.end(); ++i) {
+ for (j = i; j != _dirtyScreen.end(); ++j)
+ if (j != i && i->contains(*j))
+ j = _dirtyScreen.reverse_erase(j);
+
+ _vectorRenderer->copyFrame(_system, *i);
+ }
+
+ _dirtyScreen.clear();
+}
+
+void ThemeEngine::openDialog(bool doBuffer, ShadingStyle style) {
+ if (doBuffer)
+ _buffering = true;
+
+ if (style != kShadingNone) {
+ _vectorRenderer->applyScreenShading(style);
+ addDirtyRect(Common::Rect(0, 0, _screen->w, _screen->h));
+ }
+
+ _vectorRenderer->setSurface(_backBuffer);
+ _vectorRenderer->blitSurface(_screen, Common::Rect(0, 0, _screen->w, _screen->h));
+ _vectorRenderer->setSurface(_screen);
+}
+
+void ThemeEngine::setUpCursor() {
+ CursorMan.pushCursorPalette(_cursorPal, 0, MAX_CURS_COLORS);
+ CursorMan.pushCursor(_cursor, _cursorWidth, _cursorHeight, _cursorHotspotX, _cursorHotspotY, 255, _cursorTargetScale);
+ CursorMan.showMouse(true);
+}
+
+bool ThemeEngine::createCursor(const Common::String &filename, int hotspotX, int hotspotY, int scale) {
+ if (!_system->hasFeature(OSystem::kFeatureCursorHasPalette))
+ return true;
+
+ const Surface *cursor = _bitmaps[filename];
+
+ if (!cursor)
+ return false;
+
+ _cursorHotspotX = hotspotX;
+ _cursorHotspotY = hotspotY;
+ _cursorTargetScale = scale;
+
+ _cursorWidth = cursor->w;
+ _cursorHeight = cursor->h;
+
+ uint colorsFound = 0;
+ const OverlayColor *src = (const OverlayColor*)cursor->pixels;
+
+ byte *table = new byte[65536];
+ assert(table);
+ memset(table, 0, sizeof(byte)*65536);
+
+ byte r, g, b;
+
+ uint16 transparency = RGBToColor<ColorMasks<565> >(255, 0, 255);
+
+ delete[] _cursor;
+
+ _cursor = new byte[_cursorWidth * _cursorHeight];
+ assert(_cursor);
+ memset(_cursor, 255, sizeof(byte)*_cursorWidth*_cursorHeight);
+
+ for (uint y = 0; y < _cursorHeight; ++y) {
+ for (uint x = 0; x < _cursorWidth; ++x) {
+ _system->colorToRGB(src[x], r, g, b);
+ uint16 col = RGBToColor<ColorMasks<565> >(r, g, b);
+ if (!table[col] && col != transparency) {
+ table[col] = colorsFound++;
+
+ uint index = table[col];
+ _cursorPal[index * 4 + 0] = r;
+ _cursorPal[index * 4 + 1] = g;
+ _cursorPal[index * 4 + 2] = b;
+ _cursorPal[index * 4 + 3] = 0xFF;
+
+ if (colorsFound > MAX_CURS_COLORS) {
+ warning("Cursor contains too much colors (%d, but only %d are allowed)", colorsFound, MAX_CURS_COLORS);
+ return false;
+ }
+ }
+
+ if (col != transparency) {
+ uint index = table[col];
+ _cursor[y * _cursorWidth + x] = index;
+ }
+ }
+ src += _cursorWidth;
+ }
+
+ _useCursor = true;
+ delete[] table;
+
+ return true;
+}
+
+} // end of namespace GUI.
diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h
new file mode 100644
index 0000000000..8f8b06def4
--- /dev/null
+++ b/gui/ThemeEngine.h
@@ -0,0 +1,747 @@
+/* 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 THEME_ENGINE_H
+#define THEME_ENGINE_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"
+#include "gui/ThemeEval.h"
+
+
+namespace GUI {
+
+struct WidgetDrawData;
+struct DrawDataInfo;
+class ThemeEval;
+
+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;
+
+ ~WidgetDrawData() {
+ _steps.clear();
+
+ if (_surfaceCache) {
+ _surfaceCache->free();
+ delete _surfaceCache;
+ }
+ }
+};
+
+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:
+ Common::Rect _area;
+ ThemeEngine *_engine;
+};
+
+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;
+};
+
+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;
+};
+
+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) {}
+
+ void drawSelf(bool draw, bool restore);
+
+protected:
+ const Graphics::Surface *_bitmap;
+ bool _alpha;
+};
+
+
+class ThemeEngine : public Theme {
+protected:
+ typedef Common::String String;
+ typedef GUI::Dialog Dialog;
+ typedef Common::HashMap<Common::String, Graphics::Surface*> ImagesMap;
+
+ friend class GUI::Dialog;
+ friend class GUI::GuiObject;
+
+ /** Sets whether backcaching is enabled */
+ static const bool kEnableBackCaching = true;
+
+ /**
+ * DrawData sets enumeration.
+ * Each DD set corresponds to the actual looks
+ * of a widget in a given state.
+ */
+ enum DrawData {
+ kDDMainDialogBackground,
+ kDDSpecialColorBackground,
+ kDDPlainColorBackground,
+ kDDDefaultBackground,
+ kDDTextSelectionBackground,
+
+ kDDWidgetBackgroundDefault,
+ kDDWidgetBackgroundSmall,
+ kDDWidgetBackgroundEditText,
+ kDDWidgetBackgroundSlider,
+
+ kDDButtonIdle,
+ kDDButtonHover,
+ kDDButtonDisabled,
+
+ kDDSliderFull,
+ kDDSliderHover,
+ kDDSliderDisabled,
+
+ kDDCheckboxDefault,
+ kDDCheckboxDisabled,
+ kDDCheckboxSelected,
+
+ kDDTabActive,
+ kDDTabInactive,
+ kDDTabBackground,
+
+ kDDScrollbarBase,
+ kDDScrollbarButtonIdle,
+ kDDScrollbarButtonHover,
+ kDDScrollbarHandleIdle,
+ kDDScrollbarHandleHover,
+
+ kDDPopUpIdle,
+ kDDPopUpHover,
+
+ kDDCaret,
+ kDDSeparator,
+ kDrawDataMAX,
+ kDDNone = -1
+ };
+
+ /**
+ * Default values for each DrawData item.
+ * @see kDrawDataDefaults[] for implementation.
+ */
+ static const struct DrawDataInfo {
+ DrawData id; /** The actual ID of the DrawData item. */
+ const char *name; /** The name of the DrawData item as it appears in the Theme Description files */
+ bool buffer; /** Sets whether this item is buffered on the backbuffer or drawn directly to the screen. */
+ DrawData parent; /** Parent DrawData item, for items that overlay. E.g. kButtonIdle -> kButtonHover */
+ } kDrawDataDefaults[];
+
+
+ enum TextData {
+ kTextDataNone = -1,
+ kTextDataDefault = 0,
+ kTextDataHover,
+ kTextDataDisabled,
+ kTextDataInverted,
+ kTextDataButton,
+ kTextDataButtonHover,
+ kTextDataNormalFont,
+ kTextDataMAX
+ };
+
+ static const struct TextDataInfo {
+ TextData id;
+ const char *name;
+ } kTextDataDefaults[];
+
+
+public:
+ /** Graphics mode enumeration.
+ * Each item represents a set of BPP and Renderer modes for a given
+ * surface.
+ */
+ enum GraphicsMode {
+ kGfxDisabled = 0, /** No GFX */
+ kGfxStandard16bit, /** 2BPP with the standard (aliased) renderer. */
+ kGfxAntialias16bit, /** 2BPP with the optimized AA renderer. */
+ kGfxMAX
+ };
+
+ /** Constant value to expand dirty rectangles, to make sure they are fully copied */
+ static const int kDirtyRectangleThreshold = 1;
+
+ static const char *rendererModeLabels[];
+
+ /** Default constructor */
+ ThemeEngine(Common::String fileName, GraphicsMode mode);
+
+ /** Default destructor */
+ ~ThemeEngine();
+
+ GUI::ThemeEval *themeEval() { return _themeEval; }
+
+ /**
+ * VIRTUAL METHODS
+ * This is the implementation of the GUI::Theme API to allow
+ * the ThemeEngine class to be plugged in as any other GUI
+ * theme. In fact, the renderer works like any other GUI theme,
+ * but supports extensive customization of the drawn widgets.
+ */
+ bool init();
+ void deinit();
+ void clearAll();
+
+ void refresh();
+ void enable();
+ void disable();
+
+ /**
+ * Implementation of the GUI::Theme API. Called when a
+ * new dialog is opened. Note that the boolean parameter
+ * meaning has been changed.
+ *
+ * @param enableBuffering If set to true, buffering is enabled for
+ * drawing this dialog, and will continue enabled
+ * until disabled.
+ */
+ void openDialog(bool enableBuffering, ShadingStyle shading = kShadingNone);
+
+ /**
+ * The updateScreen() method is called every frame.
+ * It processes all the drawing queues and then copies dirty rects
+ * in the current Screen surface to the overlay.
+ */
+ void updateScreen();
+
+ /** Since the rendering pipeline changes, closing all dialogs causes no effect
+ TODO: remove this from the original GUI::Theme API */
+ void closeAllDialogs() {}
+
+ /** Drawing area has been removed: it was too hackish. A workaround is on the works.
+ TODO: finish the workaround for the credits dialog
+ TODO: remove this from the original GUI::Theme API */
+ void resetDrawArea() {}
+
+
+ /**
+ * FONT MANAGEMENT METHODS
+ */
+
+ TextData fontStyleToData(FontStyle font) const {
+ switch (font) {
+ case kFontStyleNormal:
+ return kTextDataNormalFont;
+
+ default:
+ return kTextDataDefault;
+ }
+ }
+
+ const Graphics::Font *getFont(FontStyle font) const { return _texts[fontStyleToData(font)]->_fontPtr; }
+
+ int getFontHeight(FontStyle font = kFontStyleBold) const {
+ return ready() ? _texts[fontStyleToData(font)]->_fontPtr->getFontHeight() : 0;
+ }
+
+ int getStringWidth(const Common::String &str, FontStyle font) const {
+ return ready() ? _texts[fontStyleToData(font)]->_fontPtr->getStringWidth(str) : 0;
+ }
+
+ int getCharWidth(byte c, FontStyle font) const {
+ return ready() ? _texts[fontStyleToData(font)]->_fontPtr->getCharWidth(c) : 0;
+ }
+
+
+ /**
+ * WIDGET DRAWING METHODS
+ */
+ 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<Common::String> &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, DialogBackground type, 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);
+
+ /**
+ * Actual implementation of a Dirty Rect drawing routine.
+ * Dirty rectangles are queued on a list and are later merged/calculated
+ * before the actual drawing.
+ *
+ * @param r Area of the dirty rect.
+ * @param backup Deprecated.
+ * @param special Deprecated.
+ */
+ bool addDirtyRect(Common::Rect r, bool backup = false, bool special = false) {
+ _dirtyScreen.push_back(r);
+ return true;
+ }
+
+
+ /**
+ * Returns the DrawData enumeration value that represents the given string
+ * in the DrawDataDefaults enumeration.
+ * It's slow, but called sparsely.
+ *
+ * @returns The drawdata enum value, or -1 if not found.
+ * @param name The representing name, as found on Theme Description XML files.
+ * @see kDrawDataDefaults[]
+ */
+ DrawData getDrawDataId(const Common::String &name) {
+ for (int i = 0; i < kDrawDataMAX; ++i)
+ if (name.compareToIgnoreCase(kDrawDataDefaults[i].name) == 0)
+ return kDrawDataDefaults[i].id;
+
+ 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.
+ * There is no return type because DrawSteps can always be added, unless something
+ * goes horribly wrong.
+ * The specified step will be added to the Steps list of the given DrawData id.
+ *
+ * @param drawDataId The representing DrawData name, as found on Theme Description XML files.
+ * @param step The actual DrawStep struct to be added.
+ */
+ void addDrawStep(const Common::String &drawDataId, Graphics::DrawStep step);
+
+ /**
+ * Interfacefor the ThemeParser class: Parsed DrawData sets are added via this function.
+ * The goal of the function is to initialize each DrawData set before their DrawSteps can
+ * be added, hence this must be called for each DD set before addDrawStep() can be called
+ * for that given set.
+ *
+ * @param data The representing DrawData name, as found on Theme Description XML files.
+ * @param cached Whether this DD set will be cached beforehand.
+ */
+ bool addDrawData(const Common::String &data, bool cached);
+
+
+ /**
+ * Interface for the ThemeParser class: Loads a font to use on the GUI from the given
+ * filename.
+ *
+ * @param fontName Identifier name for the font.
+ * @param file Name of the font file.
+ * @param r, g, b Color of the font.
+ */
+ bool addFont(const Common::String &fontName, const Common::String &file, int r, int g, int b);
+
+
+ /**
+ * Interface for the ThemeParser class: Loads a bitmap file to use on the GUI.
+ * The filename is also used as its identifier.
+ *
+ * @param filename Name of the bitmap file.
+ */
+ bool addBitmap(const Common::String &filename);
+
+ /**
+ * Adds a new TextStep from the ThemeParser. This will be deprecated/removed once the
+ * new Font API is in place.
+ */
+ bool addTextData(const Common::String &drawDataId, const Common::String &textDataId, TextAlign alignH, TextAlignVertical alignV);
+
+ /** Interface to the new Theme XML parser */
+ ThemeParser *parser() {
+ return _parser;
+ }
+
+ /**
+ * Returns if the Theme is ready to draw stuff on screen.
+ * Must be called instead of just checking _initOk, because
+ * this checks if the renderer is initialized AND if the theme
+ * is loaded.
+ */
+ bool ready() const {
+ return _initOk && _themeOk;
+ }
+
+ /** Custom implementation of the GUI::Theme API, changed to use the XML parser. */
+ bool loadTheme(Common::String themeName);
+
+ /**
+ * Changes the active graphics mode of the GUI; may be used to either
+ * initialize the GUI or to change the mode while the GUI is already running.
+ */
+ void setGraphicsMode(GraphicsMode mode);
+
+
+ /**
+ * Finishes buffering: widgets from then on will be drawn straight on the screen
+ * without drawing queues.
+ */
+ void finishBuffering() { _buffering = false; }
+ void startBuffering() { _buffering = true; }
+
+ ThemeEval *evaluator() { return _themeEval; }
+ VectorRenderer *renderer() { return _vectorRenderer; }
+
+ bool supportsImages() const { return true; }
+ bool ownCursor() const { return _useCursor; }
+
+ Graphics::Surface *getBitmap(const Common::String &name) {
+ return _bitmaps.contains(name) ? _bitmaps[name] : 0;
+ }
+
+ const Graphics::Surface *getImageSurface(const kThemeImages n) const {
+ if (n == kImageLogo)
+ return _bitmaps.contains("logo.bmp") ? _bitmaps["logo.bmp"] : 0;
+ else if (n == kImageLogoSmall)
+ return _bitmaps.contains("logo_small.bmp") ? _bitmaps["logo_small.bmp"] : 0;
+
+ return 0;
+ }
+
+ /**
+ * Interface for the Theme Parser: Creates a new cursor by loading the given
+ * bitmap and sets it as the active cursor.
+ *
+ * @param filename File name of the bitmap to load.
+ * @param hotspotX X Coordinate of the bitmap which does the cursor click.
+ * @param hotspotY Y Coordinate of the bitmap which does the cursor click.
+ * @param scale Scale at which the bitmap is supposed to be used.
+ */
+ bool createCursor(const Common::String &filename, int hotspotX, int hotspotY, int scale);
+
+ /**
+ * Wrapper for restoring data from the Back Buffer to the screen.
+ * The actual processing is done in the VectorRenderer.
+ *
+ * @param r Area to restore.
+ * @param special Deprecated.
+ */
+ void restoreBackground(Common::Rect r, bool special = false);
+
+ /**
+ * Checks if a given DrawData set for a widget has been cached beforehand
+ * and is ready to be blit into the screen.
+ *
+ * @param type DrawData type of the widget.
+ * @param r Size of the widget which is expected to be cached.
+ */
+ bool isWidgetCached(DrawData type, const Common::Rect &r);
+
+protected:
+
+ const Common::String &getThemeName() const { return _themeName; }
+ const Common::String &getThemeFileName() const { return _themeFileName; }
+ int getGraphicsMode() const { return _graphicsMode; }
+
+ /**
+ * Initializes the drawing screen surfaces, _screen and _backBuffer.
+ * If the surfaces already exist, they are cleared and re-initialized.
+ *
+ * @param backBuffer Sets whether the _backBuffer surface should be initialized.
+ * @template PixelType C type which specifies the size of each pixel.
+ * Defaults to uint16 (2 BPP for the surfaces)
+ */
+ template<typename PixelType> void screenInit(bool backBuffer = true);
+
+ /**
+ * Loads the given theme into the ThemeEngine.
+ * Note that ThemeName is an identifier, not a filename.
+ *
+ * @param ThemeName Theme identifier.
+ * @returns True if the theme was succesfully loaded.
+ */
+ bool loadThemeXML(Common::String themeName);
+
+ /**
+ * Loads the default theme file (the embeded XML file found
+ * in ThemeDefaultXML.cpp).
+ * Called only when no other themes are available.
+ */
+ bool loadDefaultXML();
+
+ /**
+ * Unloads the currently loaded theme so another one can
+ * be loaded.
+ */
+ void unloadTheme();
+
+ /**
+ * Not implemented yet.
+ * TODO: reload themes, reload the renderer, recheck everything
+ */
+ void screenChange() {
+ error("Screen Changes are not supported yet. Fix this!");
+ }
+
+ /**
+ * Actual Dirty Screen handling function.
+ * Handles all the dirty squares in the list, merges and optimizes
+ * them when possible and draws them to the screen.
+ * Called from updateScreen()
+ */
+ void renderDirtyScreen();
+
+ /**
+ * Frees the vector renderer.
+ */
+ void freeRenderer() {
+ delete _vectorRenderer;
+ _vectorRenderer = 0;
+ }
+
+ /**
+ * Frees the Back buffer surface, only if it's available.
+ */
+ void freeBackbuffer() {
+ if (_backBuffer != 0) {
+ _backBuffer->free();
+ delete _backBuffer;
+ _backBuffer = 0;
+ }
+ }
+
+ /**
+ * Frees the main screen drawing surface, only if it's available.
+ */
+ void freeScreen() {
+ if (_screen != 0) {
+ _screen->free();
+ delete _screen;
+ _screen = 0;
+ }
+ }
+
+ TextData getTextData(DrawData ddId) {
+ return _widgets[ddId] ? (TextData)_widgets[ddId]->_textDataId : kTextDataNone;
+ }
+
+ /**
+ * Draws a cached widget directly on the screen. Currently deprecated.
+ *
+ * @param type DrawData type of the widget.
+ * @param r Position on screen to draw the widget.
+ */
+ void drawCached(DrawData type, const Common::Rect &r);
+
+ /**
+ * Calculates the background threshold offset of a given DrawData item.
+ * After fully loading all DrawSteps of a DrawData item, this function must be
+ * called in order to calculate if such draw steps would be drawn outside of
+ * the actual widget drawing zone (e.g. shadows). If this is the case, a constant
+ * value will be added when restoring the background of the widget.
+ *
+ * @param type DrawData type of the widget.
+ */
+ void calcBackgroundOffset(DrawData type);
+
+ /**
+ * Generates a DrawQueue item and enqueues it so it's drawn to the screen
+ * when the drawing queue is processed.
+ *
+ * If Buffering is enabled, the DrawQueue item will be automatically placed
+ * on its corresponding queue.
+ * If Buffering is disabled, the DrawQueue item will be processed immediately
+ * and drawn to the screen.
+ *
+ * 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(TextData type, const Common::Rect &r, const Common::String &text, bool restoreBg,
+ bool elipsis, TextAlign alignH = kTextAlignLeft, TextAlignVertical alignV = kTextAlignVTop, int deltax = 0);
+ inline void queueBitmap(const Graphics::Surface *bitmap, const Common::Rect &r, bool alpha);
+
+ /**
+ * DEBUG: Draws a white square around the given position and writes the given next to it.
+ */
+ inline void debugWidgetPosition(const char *name, const Common::Rect &r);
+
+
+ /**
+ * Default values from GUI::Theme
+ */
+ int getTabSpacing() const { return 0; }
+ int getTabPadding() const { return 3; }
+
+ OSystem *_system; /** Global system object. */
+
+ /** Vector Renderer object, does the actual drawing on screen */
+ Graphics::VectorRenderer *_vectorRenderer;
+
+ /** XML Parser, does the Theme parsing instead of the default parser */
+ GUI::ThemeParser *_parser;
+
+ /** Theme evaluator (changed from GUI::Eval to add functionality) */
+ GUI::ThemeEval *_themeEval;
+
+ /** Main screen surface. This is blitted straight into the overlay. */
+ Graphics::Surface *_screen;
+
+ /** Backbuffer surface. Stores previous states of the screen to blit back */
+ Graphics::Surface *_backBuffer;
+
+ /** Sets whether the current drawing is being buffered (stored for later
+ processing) or drawn directly to the screen. */
+ bool _buffering;
+
+ /** Bytes per pixel of the Active Drawing Surface (i.e. the screen) */
+ int _bytesPerPixel;
+
+ /** Current graphics mode */
+ GraphicsMode _graphicsMode;
+
+ /** Font info. */
+ Common::String _fontName;
+ const Graphics::Font *_font;
+
+ /** Array of all the DrawData elements than can be drawn to the screen.
+ Must be full so the renderer can work. */
+ WidgetDrawData *_widgets[kDrawDataMAX];
+
+ /** Array of all the text fonts that can be drawn. */
+ TextDrawData *_texts[kTextDataMAX];
+
+ ImagesMap _bitmaps;
+
+ /** List of all the dirty screens that must be blitted to the overlay. */
+ Common::List<Common::Rect> _dirtyScreen;
+
+ /** Queue with all the drawing that must be done to the Back Buffer */
+ Common::List<ThemeItem*> _bufferQueue;
+
+ /** Queue with all the drawing that must be done to the screen */
+ Common::List<ThemeItem*> _screenQueue;
+
+ bool _initOk; /** Class and renderer properly initialized */
+ bool _themeOk; /** Theme data successfully loaded. */
+ bool _enabled; /** Whether the Theme is currently shown on the overlay */
+
+ Common::String _themeName; /** Name of the currently loaded theme */
+ Common::String _themeFileName;
+
+ /** Custom Cursor Management */
+ void setUpCursor();
+
+ bool _useCursor;
+ int _cursorHotspotX, _cursorHotspotY;
+ int _cursorTargetScale;
+#define MAX_CURS_COLORS 255
+ byte *_cursor;
+ bool _needPaletteUpdates;
+ uint _cursorWidth, _cursorHeight;
+ byte _cursorPal[4*MAX_CURS_COLORS];
+};
+
+} // end of namespace GUI.
+
+#endif
diff --git a/gui/ThemeEval.cpp b/gui/ThemeEval.cpp
new file mode 100644
index 0000000000..112cda59a1
--- /dev/null
+++ b/gui/ThemeEval.cpp
@@ -0,0 +1,179 @@
+/* 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 "common/system.h"
+#include "common/events.h"
+#include "common/hashmap.h"
+#include "common/hash-str.h"
+#include "common/xmlparser.h"
+#include "graphics/scaler.h"
+
+#include "gui/ThemeEngine.h"
+#include "gui/ThemeParser.h"
+#include "gui/ThemeEval.h"
+
+namespace GUI {
+
+ThemeEval::~ThemeEval() {
+ reset();
+}
+
+void ThemeEval::buildBuiltinVars() {
+ _builtin["kThumbnailWidth"] = kThumbnailWidth;
+ _builtin["kThumbnailHeight"] = kThumbnailHeight1;
+ _builtin["kThumbnailHeight2"] = kThumbnailHeight2;
+
+ _builtin["kButtonWidth"] = GUI::kButtonWidth;
+ _builtin["kButtonHeight"] = GUI::kButtonHeight;
+ _builtin["kSliderWidth"] = GUI::kSliderWidth;
+ _builtin["kSliderHeight"] = GUI::kSliderHeight;
+ _builtin["kBigButtonWidth"] = GUI::kBigButtonWidth;
+ _builtin["kBigButtonHeight"] = GUI::kBigButtonHeight;
+ _builtin["kBigSliderWidth"] = GUI::kBigSliderWidth;
+ _builtin["kBigSliderWidth"] = GUI::kBigSliderWidth;
+ _builtin["kBigSliderHeight"] = GUI::kBigSliderHeight;
+
+ _builtin["kNormalWidgetSize"] = GUI::kNormalWidgetSize;
+ _builtin["kBigWidgetSize"] = GUI::kBigWidgetSize;
+}
+
+void ThemeEval::reset() {
+ _vars.clear();
+ _curDialog.clear();
+ _curLayout.clear();
+
+ for (LayoutsMap::iterator i = _layouts.begin(); i != _layouts.end(); ++i)
+ delete i->_value;
+
+ _layouts.clear();
+}
+
+bool ThemeEval::getWidgetData(const Common::String &widget, int16 &x, int16 &y, uint16 &w, uint16 &h) {
+ Common::StringTokenizer tokenizer(widget, ".");
+
+ if (widget.hasPrefix("Dialog."))
+ tokenizer.nextToken();
+
+ Common::String dialogName = "Dialog." + tokenizer.nextToken();
+ Common::String widgetName = tokenizer.nextToken();
+
+ if (!_layouts.contains(dialogName))
+ return false;
+
+ if (widgetName.empty())
+ return _layouts[dialogName]->getDialogData(x, y, w, h);
+
+ return _layouts[dialogName]->getWidgetData(widgetName, x, y, w, h);
+}
+
+
+void ThemeEval::addWidget(const Common::String &name, int w, int h, const Common::String &type, bool enabled) {
+ int typeW = -1;
+ int typeH = -1;
+
+ if (!type.empty()) {
+ typeW = getVar("Globals." + type + ".Width", -1);
+ typeH = getVar("Globals." + type + ".Height", -1);
+ }
+
+ ThemeLayoutWidget *widget = new ThemeLayoutWidget(_curLayout.top(), name,
+ typeW == -1 ? w : typeW,
+ typeH == -1 ? h : typeH);
+
+ _curLayout.top()->addChild(widget);
+ setVar(_curDialog + "." + name + ".Enabled", enabled ? 1 : 0);
+}
+
+void ThemeEval::addDialog(const Common::String &name, const Common::String &overlays, bool enabled, int inset) {
+ int16 x, y;
+ uint16 w, h;
+
+ ThemeLayout *layout = 0;
+
+ if (overlays == "screen") {
+ layout = new ThemeLayoutMain(inset, inset, g_system->getOverlayWidth() - 2 * inset, g_system->getOverlayHeight() - 2 * inset);
+ } else if (overlays == "screen_center") {
+ layout = new ThemeLayoutMain(-1, -1, -1, -1);
+ } else if (getWidgetData(overlays, x, y, w, h)) {
+ layout = new ThemeLayoutMain(x + inset, y + inset, w - 2 * inset, h - 2 * inset);
+ }
+
+ if (!layout)
+ error("Error when loading dialog position for '%s'", overlays.c_str());
+
+ if (_layouts.contains(name))
+ delete _layouts[name];
+
+ _layouts[name] = layout;
+
+ layout->setPadding(
+ getVar("Globals.Padding.Left", 0),
+ getVar("Globals.Padding.Right", 0),
+ getVar("Globals.Padding.Top", 0),
+ getVar("Globals.Padding.Bottom", 0)
+ );
+
+ _curLayout.push(layout);
+ _curDialog = name;
+ setVar(name + ".Enabled", enabled ? 1 : 0);
+}
+
+void ThemeEval::addLayout(ThemeLayout::LayoutType type, int spacing, bool center) {
+ ThemeLayout *layout = 0;
+
+ if (spacing == -1)
+ spacing = getVar("Globals.Layout.Spacing", 4);
+
+ if (type == ThemeLayout::kLayoutVertical)
+ layout = new ThemeLayoutVertical(_curLayout.top(), spacing, center);
+ else if (type == ThemeLayout::kLayoutHorizontal)
+ layout = new ThemeLayoutHorizontal(_curLayout.top(), spacing, center);
+
+ layout->setPadding(
+ getVar("Globals.Padding.Left", 0),
+ getVar("Globals.Padding.Right", 0),
+ getVar("Globals.Padding.Top", 0),
+ getVar("Globals.Padding.Bottom", 0)
+ );
+
+ _curLayout.top()->addChild(layout);
+ _curLayout.push(layout);
+}
+
+void ThemeEval::addSpace(int size) {
+ ThemeLayout *space = new ThemeLayoutSpacing(_curLayout.top(), size);
+ _curLayout.top()->addChild(space);
+}
+
+bool ThemeEval::addImportedLayout(const Common::String &name) {
+ if (!_layouts.contains(name))
+ return false;
+
+ _curLayout.top()->importLayout(_layouts[name]);
+ return true;
+}
+
+}
diff --git a/gui/ThemeEval.h b/gui/ThemeEval.h
new file mode 100644
index 0000000000..a25ff21a88
--- /dev/null
+++ b/gui/ThemeEval.h
@@ -0,0 +1,115 @@
+/* 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 GUI_THEME_EVAL
+#define GUI_THEME_EVAL
+
+#include "common/util.h"
+#include "common/system.h"
+#include "common/events.h"
+#include "common/hashmap.h"
+#include "common/hash-str.h"
+#include "common/xmlparser.h"
+
+#include "gui/ThemeEngine.h"
+#include "gui/ThemeParser.h"
+#include "gui/ThemeEval.h"
+#include "gui/ThemeLayout.h"
+
+namespace GUI {
+
+class ThemeEval {
+
+ typedef Common::HashMap<Common::String, int> VariablesMap;
+ typedef Common::HashMap<Common::String, ThemeLayout*> LayoutsMap;
+
+public:
+ ThemeEval() {
+ buildBuiltinVars();
+ }
+
+ ~ThemeEval();
+
+ void buildBuiltinVars();
+
+ int getVar(const Common::String &s) {
+ if (_vars.contains(s))
+ return _vars[s];
+
+ if (_builtin.contains(s))
+ return _builtin[s];
+
+ error("CRITICAL: Missing variable: '%s'", s.c_str());
+ return -13375; //EVAL_UNDEF_VAR
+ }
+
+ int getVar(const Common::String &s, int def) {
+ if (_vars.contains(s))
+ return _vars[s];
+
+ if (_builtin.contains(s))
+ return _builtin[s];
+
+ return def;
+ }
+
+ void setVar(const String &name, int val) { _vars[name] = val; }
+
+ bool hasVar(const Common::String &name) { return _vars.contains(name) || _builtin.contains(name); }
+
+ void addDialog(const Common::String &name, const Common::String &overlays, bool enabled = true, int inset = 0);
+ void addLayout(ThemeLayout::LayoutType type, int spacing, bool center = false);
+ void addWidget(const Common::String &name, int w, int h, const Common::String &type, bool enabled = true);
+ bool addImportedLayout(const Common::String &name);
+ void addSpace(int size);
+
+ void addPadding(int16 l, int16 r, int16 t, int16 b) { _curLayout.top()->setPadding(l, r, t, b); }
+
+ void closeLayout() { _curLayout.pop(); }
+ void closeDialog() { _curLayout.pop()->reflowLayout(); _curDialog.clear(); }
+
+ bool getWidgetData(const Common::String &widget, int16 &x, int16 &y, uint16 &w, uint16 &h);
+
+#ifdef LAYOUT_DEBUG_DIALOG
+ void debugDraw(Graphics::Surface *screen, const Graphics::Font *font) {
+ _layouts[LAYOUT_DEBUG_DIALOG]->debugDraw(screen, font);
+ }
+#endif
+
+ void reset();
+
+private:
+ VariablesMap _vars;
+ VariablesMap _builtin;
+
+ LayoutsMap _layouts;
+ Common::Stack<ThemeLayout*> _curLayout;
+ Common::String _curDialog;
+};
+
+
+}
+
+#endif
diff --git a/gui/ThemeLayout.cpp b/gui/ThemeLayout.cpp
new file mode 100644
index 0000000000..247c1c0d5e
--- /dev/null
+++ b/gui/ThemeLayout.cpp
@@ -0,0 +1,227 @@
+/* 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 "common/system.h"
+#include "common/events.h"
+#include "common/hashmap.h"
+#include "common/hash-str.h"
+#include "common/xmlparser.h"
+#include "graphics/scaler.h"
+
+#include "gui/ThemeEval.h"
+#include "gui/ThemeLayout.h"
+
+namespace GUI {
+
+void ThemeLayout::importLayout(ThemeLayout *layout) {
+ assert(layout->getLayoutType() == kLayoutMain);
+
+ if (layout->_children.size() == 0)
+ return;
+
+ layout = layout->_children[0];
+
+ if (getLayoutType() == layout->getLayoutType()) {
+ for (uint i = 0; i < layout->_children.size(); ++i)
+ _children.push_back(layout->_children[i]->buildCopy());
+ } else {
+ _children.push_back(layout->buildCopy());
+ }
+}
+
+bool ThemeLayout::getWidgetData(const Common::String &name, int16 &x, int16 &y, uint16 &w, uint16 &h) {
+ for (uint i = 0; i < _children.size(); ++i) {
+ if (_children[i]->getWidgetData(name, x, y, w, h))
+ return true;
+ }
+
+ return false;
+}
+
+int16 ThemeLayout::getParentW() {
+ ThemeLayout *p = _parent;
+ int width = 0;
+
+ while (p && p->getLayoutType() != kLayoutMain) {
+ width += p->_paddingRight + p->_paddingLeft;
+ if (p->getLayoutType() == kLayoutHorizontal) {
+ for (uint i = 0; i < p->_children.size(); ++i)
+ width += p->_children[i]->getHeight() + p->_spacing;
+ }
+ p = p->_parent;
+ }
+
+ return p->getWidth() - width;
+}
+
+int16 ThemeLayout::getParentH() {
+ ThemeLayout *p = _parent;
+ int height = 0;
+
+ while (p && p->getLayoutType() != kLayoutMain) {
+ height += p->_paddingBottom + p->_paddingTop;
+ if (p->getLayoutType() == kLayoutVertical) {
+ for (uint i = 0; i < p->_children.size(); ++i)
+ height += p->_children[i]->getHeight() + p->_spacing;
+ }
+ p = p->_parent;
+ }
+
+ return p->getHeight() - height;
+}
+
+
+bool ThemeLayoutWidget::getWidgetData(const Common::String &name, int16 &x, int16 &y, uint16 &w, uint16 &h) {
+ if (name == _name) {
+ x = _x; y = _y;
+ w = _w; h = _h;
+ return true;
+ }
+
+ return false;
+}
+
+void ThemeLayoutMain::reflowLayout() {
+ assert(_children.size() <= 1);
+
+ if (_children.size()) {
+ _children[0]->resetLayout();
+ _children[0]->setWidth(_w);
+ _children[0]->setHeight(_h);
+ _children[0]->reflowLayout();
+
+ if (_w == -1)
+ _w = _children[0]->getWidth();
+
+ if (_h == -1)
+ _h = _children[0]->getHeight();
+
+ if (_y == -1)
+ _y = (g_system->getOverlayHeight() >> 1) - (_h >> 1);
+
+ if (_x == -1)
+ _x = (g_system->getOverlayWidth() >> 1) - (_w >> 1);
+ }
+}
+
+void ThemeLayoutVertical::reflowLayout() {
+ int curX, curY;
+ int resize[8];
+ int rescount = 0;
+
+ curX = _paddingLeft;
+ curY = _paddingTop;
+ _h = _paddingTop + _paddingBottom;
+
+ for (uint i = 0; i < _children.size(); ++i) {
+
+ _children[i]->resetLayout();
+ _children[i]->reflowLayout();
+
+ if (_children[i]->getWidth() == -1)
+ _children[i]->setWidth((_w == -1 ? getParentW() : _w) - _paddingLeft - _paddingRight);
+
+ if (_children[i]->getHeight() == -1) {
+ resize[rescount++] = i;
+ _children[i]->setHeight(0);
+ }
+
+ _children[i]->setY(curY);
+
+ if (_centered && _children[i]->getWidth() < _w && _w != -1) {
+ _children[i]->setX((_w >> 1) - (_children[i]->getWidth() >> 1));
+ }
+ else
+ _children[i]->setX(curX);
+
+ curY += _children[i]->getHeight() + _spacing;
+ _w = MAX(_w, (int16)(_children[i]->getWidth() + _paddingLeft + _paddingRight));
+ _h += _children[i]->getHeight() + _spacing;
+ }
+
+ _h -= _spacing;
+
+ if (rescount) {
+ int newh = (getParentH() - _h - _paddingBottom) / rescount;
+
+ for (int i = 0; i < rescount; ++i) {
+ _children[resize[i]]->setHeight(newh);
+ _h += newh;
+ for (uint j = resize[i] + 1; j < _children.size(); ++j)
+ _children[j]->setY(newh);
+ }
+ }
+}
+
+void ThemeLayoutHorizontal::reflowLayout() {
+ int curX, curY;
+ int resize[8];
+ int rescount = 0;
+
+ curX = _paddingLeft;
+ curY = _paddingTop;
+ _w = _paddingLeft + _paddingRight;
+
+ for (uint i = 0; i < _children.size(); ++i) {
+
+ _children[i]->resetLayout();
+ _children[i]->reflowLayout();
+
+ if (_children[i]->getHeight() == -1)
+ _children[i]->setHeight((_h == -1 ? getParentH() : _h) - _paddingTop - _paddingBottom);
+
+ if (_children[i]->getWidth() == -1) {
+ resize[rescount++] = i;
+ _children[i]->setWidth(0);
+ }
+
+ _children[i]->setX(curX);
+
+ if (_centered && _children[i]->getHeight() < _h && _h != -1)
+ _children[i]->setY((_h >> 1) - (_children[i]->getHeight() >> 1));
+ else
+ _children[i]->setY(curY);
+
+ curX += (_children[i]->getWidth() + _spacing);
+ _w += _children[i]->getWidth() + _spacing;
+ _h = MAX(_h, (int16)(_children[i]->getHeight() + _paddingTop + _paddingBottom));
+ }
+
+ _w -= _spacing;
+
+ if (rescount) {
+ int neww = (getParentW() - _w - _paddingRight) / rescount;
+
+ for (int i = 0; i < rescount; ++i) {
+ _children[resize[i]]->setWidth(neww);
+ _w += neww;
+ for (uint j = resize[i] + 1; j < _children.size(); ++j)
+ _children[j]->setX(neww);
+ }
+ }
+}
+
+
+}
diff --git a/gui/ThemeLayout.h b/gui/ThemeLayout.h
new file mode 100644
index 0000000000..87078d086e
--- /dev/null
+++ b/gui/ThemeLayout.h
@@ -0,0 +1,239 @@
+/* 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 THEME_LAYOUT_H
+#define THEME_LAYOUT_H
+
+namespace GUI {
+
+class ThemeLayout {
+
+public:
+ enum LayoutType {
+ kLayoutMain,
+ kLayoutVertical,
+ kLayoutHorizontal,
+ kLayoutWidget
+ };
+
+ ThemeLayout(ThemeLayout *p, const Common::String &name) :
+ _parent(p), _name(name), _x(0), _y(0), _w(-1), _h(-1),
+ _paddingLeft(0), _paddingRight(0), _paddingTop(0), _paddingBottom(0),
+ _centered(false), _defaultW(-1), _defaultH(-1) { }
+
+ virtual ~ThemeLayout() {
+ for (uint i = 0; i < _children.size(); ++i)
+ delete _children[i];
+ }
+
+ virtual void reflowLayout() = 0;
+
+ virtual void resetLayout() { _x = 0; _y = 0; _w = _defaultW; _h = _defaultH; }
+
+ void addChild(ThemeLayout *child) { _children.push_back(child); }
+
+ void setPadding(int8 left, int8 right, int8 top, int8 bottom) {
+ _paddingLeft = left;
+ _paddingRight = right;
+ _paddingTop = top;
+ _paddingBottom = bottom;
+ }
+
+ void setSpacing(int8 spacing) {
+ _spacing = spacing;
+ }
+
+ int16 getParentX() { return _parent ? _parent->_x : 0; }
+ int16 getParentY() { return _parent ? _parent->_y : 0; }
+ int16 getParentW();
+ int16 getParentH();
+ int16 getX() { return _x; }
+ int16 getY() { return _y; }
+ int16 getWidth() { return _w; }
+ int16 getHeight() { return _h; }
+
+ void setX(int newX) {
+ _x += newX;
+ for (uint i = 0; i < _children.size(); ++i)
+ _children[i]->setX(newX);
+ }
+
+ void setY(int newY) {
+ _y += newY;
+ for (uint i = 0; i < _children.size(); ++i)
+ _children[i]->setY(newY);
+ }
+
+ void setWidth(int16 width) { _w = width; }
+ void setHeight(int16 height) { _h = height; }
+
+#ifdef LAYOUT_DEBUG_DIALOG
+ void debugDraw(Graphics::Surface *screen, const Graphics::Font *font) {
+ uint16 color = 0xFFFF;
+ font->drawString(screen, getName(), _x, _y, _w, color, Graphics::kTextAlignRight, 0, true);
+ screen->hLine(_x, _y, _x + _w, color);
+ screen->hLine(_x, _y + _h, _x + _w , color);
+ screen->vLine(_x, _y, _y + _h, color);
+ screen->vLine(_x + _w, _y, _y + _h, color);
+
+ for (uint i = 0; i < _children.size(); ++i)
+ _children[i]->debugDraw(screen, font);
+ }
+#endif
+
+ virtual LayoutType getLayoutType() = 0;
+ virtual const char *getName() { return _name.c_str(); }
+
+ virtual bool getWidgetData(const Common::String &name, int16 &x, int16 &y, uint16 &w, uint16 &h);
+
+ virtual bool getDialogData(int16 &x, int16 &y, uint16 &w, uint16 &h) {
+ assert(getLayoutType() == kLayoutMain);
+ x = _x; y = _y;
+ w = _w; h = _h;
+ return true;
+ }
+
+ virtual ThemeLayout *buildCopy() = 0;
+ void importLayout(ThemeLayout *layout);
+
+protected:
+ int16 _x, _y, _w, _h;
+ int16 _defaultW, _defaultH;
+ int8 _paddingTop, _paddingBottom, _paddingLeft, _paddingRight;
+ int8 _spacing;
+ Common::Array<ThemeLayout*> _children;
+ ThemeLayout *_parent;
+ bool _centered;
+ Common::String _name;
+};
+
+class ThemeLayoutMain : public ThemeLayout {
+public:
+ ThemeLayoutMain(int16 x, int16 y, int16 w, int16 h) : ThemeLayout(0, "") {
+ _w = _defaultW = w;
+ _h = _defaultH = h;
+ _x = _defaultX = x;
+ _y = _defaultY = y;
+ }
+ void reflowLayout();
+
+ void resetLayout() {
+ ThemeLayout::resetLayout();
+ _x = _defaultX;
+ _y = _defaultY;
+ }
+
+ const char *getName() { return "Global Layout"; }
+ LayoutType getLayoutType() { return kLayoutMain; }
+
+ ThemeLayout *buildCopy() { assert(!"Do not copy Main Layouts!"); return 0; }
+
+protected:
+ int16 _defaultX;
+ int16 _defaultY;
+};
+
+class ThemeLayoutVertical : public ThemeLayout {
+public:
+ ThemeLayoutVertical(ThemeLayout *p, int spacing, bool center) :
+ ThemeLayout(p, "") {
+ _spacing = spacing;
+ _centered = center;
+ }
+
+ void reflowLayout();
+ const char *getName() { return "Vertical Layout"; }
+ LayoutType getLayoutType() { return kLayoutVertical; }
+
+
+ ThemeLayout *buildCopy() {
+ ThemeLayoutVertical *n = new ThemeLayoutVertical(*this);
+
+ for (uint i = 0; i < n->_children.size(); ++ i)
+ n->_children[i] = n->_children[i]->buildCopy();
+
+ return n;
+ }
+};
+
+class ThemeLayoutHorizontal : public ThemeLayout {
+public:
+ ThemeLayoutHorizontal(ThemeLayout *p, int spacing, bool center) :
+ ThemeLayout(p, "") {
+ _spacing = spacing;
+ _centered = center;
+ }
+
+ void reflowLayout();
+ const char *getName() { return "Horizontal Layout"; }
+ LayoutType getLayoutType() { return kLayoutHorizontal; }
+
+ ThemeLayout *buildCopy() {
+ ThemeLayoutHorizontal *n = new ThemeLayoutHorizontal(*this);
+
+ for (uint i = 0; i < n->_children.size(); ++ i)
+ n->_children[i] = n->_children[i]->buildCopy();
+
+ return n;
+ }
+};
+
+class ThemeLayoutWidget : public ThemeLayout {
+public:
+ ThemeLayoutWidget(ThemeLayout *p, const Common::String &name, int16 w, int16 h) : ThemeLayout(p, name) {
+ _w = _defaultW = w;
+ _h = _defaultH = h;
+ }
+
+ bool getWidgetData(const Common::String &name, int16 &x, int16 &y, uint16 &w, uint16 &h);
+ void reflowLayout() {}
+ LayoutType getLayoutType() { return kLayoutWidget; }
+
+ ThemeLayout *buildCopy() { return new ThemeLayoutWidget(*this); }
+};
+
+class ThemeLayoutSpacing : public ThemeLayout {
+public:
+ ThemeLayoutSpacing(ThemeLayout *p, int size) : ThemeLayout(p, "") {
+ if (p->getLayoutType() == kLayoutHorizontal) {
+ _w = _defaultW = size;
+ _h = _defaultH = 1;
+ } else if (p->getLayoutType() == kLayoutVertical) {
+ _w = _defaultW = 1;
+ _h = _defaultH = size;
+ }
+ }
+
+ bool getWidgetData(const Common::String &name, int16 &x, int16 &y, uint16 &w, uint16 &h) { return false; }
+ void reflowLayout() {}
+ LayoutType getLayoutType() { return kLayoutWidget; }
+ const char *getName() { return "SPACE"; }
+
+ ThemeLayout *buildCopy() { return new ThemeLayoutSpacing(*this); }
+};
+
+}
+
+#endif
diff --git a/gui/ThemeModern.cpp b/gui/ThemeModern.cpp
deleted file mode 100644
index fa8c29e616..0000000000
--- a/gui/ThemeModern.cpp
+++ /dev/null
@@ -1,1596 +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 DISABLE_FANCY_THEMES
-
-#include "gui/ThemeModern.h"
-#include "gui/eval.h"
-
-#include "graphics/imageman.h"
-#include "graphics/imagedec.h"
-#include "graphics/colormasks.h"
-#include "graphics/cursorman.h"
-
-#include "common/config-manager.h"
-#include "common/file.h"
-
-#define kShadowTr0 8
-#define kShadowTr1 16
-#define kShadowTr2 32
-#define kShadowTr3 64
-#define kShadowTr35 96
-#define kShadowTr4 128
-#define kShadowTr5 192
-
-using Graphics::Surface;
-
-/** Specifies the currently active 16bit pixel format, 555 or 565. */
-extern int gBitFormat;
-
-namespace GUI {
-
-// TODO: This should be moved to ThemeModern
-OverlayColor getColorAlpha(OverlayColor col1, OverlayColor col2, int alpha);
-OverlayColor calcGradient(OverlayColor start, OverlayColor end, int pos, int max, uint factor);
-void getStateColor(OverlayColor &s, OverlayColor &e, OverlayColor enabledS, OverlayColor enabledE, OverlayColor highlightS, OverlayColor highlightE, Theme::WidgetStateInfo state);
-
-#pragma mark -
-
-ThemeModern::ThemeModern(OSystem *system, const Common::String &stylefile, const Common::ConfigFile *cfg) : Theme(), _system(system), _screen(), _initOk(false),
-_forceRedraw(false), _lastUsedBitMask(0), _fonts(), _cursor(0), _imageHandles(), _images(0), _colors(), _gradientFactors() {
- _stylefile = stylefile;
- _initOk = false;
- _enabled = false;
- _useCursor = false;
- memset(&_screen, 0, sizeof(_screen));
- memset(&_dialog, 0, sizeof(_dialog));
- memset(&_colors, 0, sizeof(_colors));
- memset(&_gradientFactors, 0, sizeof(_gradientFactors));
-
- _screen.create(_system->getOverlayWidth(), _system->getOverlayHeight(), sizeof(OverlayColor));
- if (_screen.pixels) {
- _initOk = true;
- clearAll();
- }
-
- if (cfg) {
- _configFile = *cfg;
- } else {
- if (!loadConfigFile(stylefile)) {
- warning("Can not find theme config file '%s'", (stylefile + ".ini").c_str());
- return;
- }
- }
-
- ImageMan.addArchive(stylefile + ".zip");
-
- Common::String temp;
- _configFile.getKey("version", "theme", temp);
- if (atoi(temp.c_str()) != THEME_VERSION) {
- // TODO: improve this detection and handle it nicer
- warning("Theme config uses a different version (you have: '%s', needed is: '%d')", temp.c_str(), THEME_VERSION);
- return;
- }
-
- temp.clear();
- _configFile.getKey("type", "theme", temp);
- if (0 != temp.compareToIgnoreCase("modern")) {
- warning("Theme config is not for the modern style theme");
- return;
- }
-
- if (_configFile.hasKey("name", "theme"))
- _configFile.getKey("name", "theme", _stylename);
- else
- _stylename = _stylefile;
-
- _images = new const Graphics::Surface*[kImageHandlesMax];
- assert(_images);
-
- _lastUsedBitMask = gBitFormat;
-}
-
-ThemeModern::~ThemeModern() {
- deleteFonts();
- deinit();
- delete[] _images;
- delete[] _cursor;
- _images = 0;
- for (int i = 0; i < kImageHandlesMax; ++i) {
- ImageMan.unregisterSurface(_imageHandles[i]);
- }
- ImageMan.removeArchive(_stylefile + ".zip");
-}
-
-bool ThemeModern::init() {
- if (!_images)
- return false;
-
- deinit();
- _screen.create(_system->getOverlayWidth(), _system->getOverlayHeight(), sizeof(OverlayColor));
- if (_screen.pixels) {
- _initOk = true;
- clearAll();
- resetDrawArea();
- }
-
- if (isThemeLoadingRequired()) {
- loadTheme(_defaultConfig);
- loadTheme(_configFile, false, true); // Don't reset
-
- processExtraValues();
- }
-
- for (int i = 0; i < kImageHandlesMax; ++i) {
- if (!_images[i]) {
- return false;
- }
- }
-
- return true;
-}
-
-void ThemeModern::deinit() {
- if (_initOk) {
- _system->hideOverlay();
- _screen.free();
- _initOk = false;
- }
-}
-
-void ThemeModern::refresh() {
- init();
- resetupGuiRenderer();
- if (_enabled) {
- _system->showOverlay();
- CursorMan.replaceCursorPalette(_cursorPal, 0, MAX_CURS_COLORS);
- CursorMan.replaceCursor(_cursor, _cursorWidth, _cursorHeight, _cursorHotspotX, _cursorHotspotY, 255, _cursorTargetScale);
- }
-}
-
-void ThemeModern::enable() {
- init();
- resetupGuiRenderer();
- resetDrawArea();
- if (_useCursor)
- setUpCursor();
- _system->showOverlay();
- clearAll();
- _enabled = true;
-}
-
-void ThemeModern::disable() {
- _system->hideOverlay();
- if (_useCursor) {
- CursorMan.popCursorPalette();
- CursorMan.popCursor();
- }
- _enabled = false;
-}
-
-void ThemeModern::openDialog(bool topDialog) {
- if (!_dialog) {
- _dialog = new DialogState;
- assert(_dialog);
- // first dialog
- _dialog->screen.create(_screen.w, _screen.h, sizeof(OverlayColor));
- }
-
- if (_dialogShadingCallback && topDialog) {
- OverlayColor *col = (OverlayColor*)_screen.pixels;
- for (int y = 0; y < _screen.h; ++y) {
- for (int x = 0; x < _screen.w; ++x) {
- col[x] = (this->*(_dialogShadingCallback))(col[x]);
- }
- col += _screen.w;
- }
- }
-
- memcpy(_dialog->screen.pixels, _screen.pixels, _screen.pitch*_screen.h);
-
- if ((_dialogShadingCallback) && topDialog)
- addDirtyRect(Common::Rect(0, 0, _screen.w, _screen.h), false, false);
-}
-
-void ThemeModern::closeAllDialogs() {
- if (_dialog) {
- _dialog->screen.free();
- delete _dialog;
- _dialog = 0;
- }
- _forceRedraw = true;
-}
-
-void ThemeModern::clearAll() {
- if (!_initOk)
- return;
- _system->clearOverlay();
- // FIXME: problem with the 'pitch'
- _system->grabOverlay((OverlayColor*)_screen.pixels, _screen.w);
-}
-
-void ThemeModern::updateScreen() {
- // TODO: see ThemeModern::addDirtyRect
- _forceRedraw = false;
-}
-
-void ThemeModern::setDrawArea(const Common::Rect &r) {
- if (_initOk) {
- _drawArea = r;
- _shadowDrawArea = Common::Rect(r.left-_shadowLeftWidth, r.top-_shadowTopHeight, r.right+_shadowRightWidth, r.bottom+_shadowBottomHeight);
- _drawArea.clip(_screen.w, _screen.h);
- _shadowDrawArea.clip(_screen.w, _screen.h);
- }
-}
-
-void ThemeModern::resetDrawArea() {
- if (_initOk) {
- _drawArea = Common::Rect(0, 0, _screen.w, _screen.h);
- _shadowDrawArea = _drawArea;
- }
-}
-
-#define surface(x) (_images[x])
-
-void ThemeModern::drawDialogBackground(const Common::Rect &r, uint16 hints, WidgetStateInfo state) {
- if (!_initOk)
- return;
-
- Common::Rect r2 = shadowRect(r, kShadowFull);
-
- if ((hints & THEME_HINT_SAVE_BACKGROUND) && !(hints & THEME_HINT_FIRST_DRAW) && !_forceRedraw) {
- restoreBackground(r2, true);
- addDirtyRect(r2);
- return;
- }
-
- if (hints & THEME_HINT_MAIN_DIALOG) {
- colorFade(r, _colors[kMainDialogStart], _colors[kMainDialogEnd], _gradientFactors[kMainDialogFactor]);
- } else if (hints & THEME_HINT_SPECIAL_COLOR) {
- drawShadow(r, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd), kShadowFull);
-
- drawRectMasked(r, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd),
- 256, _colors[kMainDialogStart], _colors[kMainDialogEnd], _gradientFactors[kDialogSpecialFactor]);
- } else if (hints & THEME_HINT_PLAIN_COLOR) {
- drawShadow(r, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd), kShadowFull);
-
- drawRectMasked(r, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd),
- 256, _colors[kDialogEnd], _colors[kDialogEnd], _gradientFactors[kDialogFactor]);
- } else {
- drawShadow(r, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd), kShadowFull);
-
- drawRectMasked(r, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd),
- 256, _colors[kDialogStart], _colors[kDialogEnd], _gradientFactors[kDialogFactor]);
- }
-
- addDirtyRect(r2, (hints & THEME_HINT_SAVE_BACKGROUND) != 0, true);
-}
-
-void ThemeModern::drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, TextAlign align, bool inverted, int deltax, bool useEllipsis, FontStyle font) {
- if (!_initOk)
- return;
-
- uint32 color;
-
- restoreBackground(r);
-
- if (inverted) {
- _screen.fillRect(r, _colors[kTextInvertedBackground]);
- color = _colors[kTextInvertedColor];
- } else {
- color = getColor(state);
- }
-
- getFont(font)->drawString(&_screen, str, r.left, r.top, r.width(), color, convertAligment(align), deltax, useEllipsis);
- addDirtyRect(r);
-}
-
-void ThemeModern::drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state) {
- if (!_initOk)
- return;
- restoreBackground(r);
- font->drawChar(&_screen, ch, r.left, r.top, getColor(state));
- addDirtyRect(r);
-}
-
-void ThemeModern::drawWidgetBackground(const Common::Rect &r, uint16 hints, WidgetBackground background, WidgetStateInfo state) {
- if (!_initOk)
- return;
-
- Common::Rect r2;
-
- ImageHandles corner, top, left, bkgd;
- ShadowStyles shadow;
- ColorHandles start, end;
- GradientFactors factor;
-
- switch (background) {
- case kWidgetBackgroundBorderSmall:
- corner = kWidgetSmallBkgdCorner;
- top = kWidgetSmallBkgdTop;
- left = kWidgetSmallBkgdLeft;
- bkgd = kWidgetSmallBkgd;
- shadow = kShadowSmall;
- start = kWidgetBackgroundSmallStart;
- end = kWidgetBackgroundSmallEnd;
- factor = kWidgetSmallFactor;
- break;
- case kWidgetBackgroundEditText:
- corner = kEditTextBkgdCorner;
- top = kEditTextBkgdTop;
- left = kEditTextBkgdLeft;
- bkgd = kEditTextBkgd;
- shadow = kShadowEmboss;
- start = kEditTextBackgroundStart;
- end = kEditTextBackgroundEnd;
- factor = kEditTextFactor;
- break;
- case kWidgetBackgroundSlider:
- corner = kSliderBkgdCorner;
- top = kSliderBkgdTop;
- left = kSliderBkgdLeft;
- bkgd = kSliderBkgd;
- shadow = kShadowEmboss;
- start = kSliderBackgroundStart;
- end = kSliderBackgroundEnd;
- factor = kSliderBackground;
- break;
- default:
- corner = kWidgetBkgdCorner;
- top = kWidgetBkgdTop;
- left = kWidgetBkgdLeft;
- bkgd = kWidgetBkgd;
- shadow = kShadowFull;
- if (hints & THEME_HINT_PLAIN_COLOR)
- start = kWidgetBackgroundEnd;
- else
- start = kWidgetBackgroundStart;
- end = kWidgetBackgroundEnd;
- factor = kWidgetFactor;
- break;
- }
-
- if ((hints & THEME_HINT_SAVE_BACKGROUND) && !(hints & THEME_HINT_FIRST_DRAW) && !_forceRedraw) {
- restoreBackground((hints & THEME_HINT_USE_SHADOW) ? r2 : r);
- addDirtyRect((hints & THEME_HINT_USE_SHADOW) ? r2 : r);
- return;
- }
-
- if ((hints & THEME_HINT_USE_SHADOW)) {
- r2 = shadowRect(r, shadow);
- restoreBackground(r2);
- // shadow
- drawShadow(r, surface(corner), surface(top), surface(left), surface(bkgd), shadow);
- }
-
- drawRectMasked(r, surface(corner), surface(top), surface(left), surface(bkgd),
- (state == kStateDisabled) ? -30 : 256, _colors[start], _colors[end],
- _gradientFactors[factor]);
-
- addDirtyRect((hints & THEME_HINT_USE_SHADOW) ? r2 : r, (hints & THEME_HINT_SAVE_BACKGROUND) != 0);
-}
-
-void ThemeModern::drawButton(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, uint16 hints) {
- if (!_initOk)
- return;
-
- Common::Rect r2 = shadowRect(r, kShadowButton);
-
- if (!(hints & THEME_HINT_NO_BACKGROUND_RESTORE) || state == kStateDisabled)
- restoreBackground(r2);
-
- // shadow
- drawShadow(r, surface(kButtonBkgdCorner), surface(kButtonBkgdTop), surface(kButtonBkgdLeft), surface(kButtonBkgd), kShadowButton);
-
- OverlayColor start, end;
- int alpha = 256;
-
- getStateColor(start, end, _colors[kButtonBackgroundStart], _colors[kButtonBackgroundEnd],
- _colors[kButtonBackgroundHighlightStart], _colors[kButtonBackgroundHighlightEnd], state);
-
- if (state != kStateHighlight)
- alpha = (state == kStateDisabled) ? -30 : 256;
-
- drawRectMasked(r, surface(kButtonBkgdCorner), surface(kButtonBkgdTop), surface(kButtonBkgdLeft), surface(kButtonBkgd),
- alpha, start, end, _gradientFactors[kButtonFactor]);
-
- const int off = (r.height() - getFontHeight()) / 2;
-
- OverlayColor col = 0;
- switch (state) {
- case kStateEnabled:
- col = _colors[kButtonTextEnabled];
- break;
-
- case kStateHighlight:
- col = _colors[kButtonTextHighlight];
- break;
-
- default:
- col = _colors[kButtonTextDisabled];
- break;
- };
-
- getFont()->drawString(&_screen, str, r.left, r.top + off, r.width(), col, Graphics::kTextAlignCenter, 0, true);
-
- addDirtyRect(r2);
-}
-
-void ThemeModern::drawSurface(const Common::Rect &r, const Graphics::Surface &surface, WidgetStateInfo state, int alpha, bool themeTrans) {
- if (!_initOk)
- return;
-
- Common::Rect rect(r.left, r.top, r.left + surface.w, r.top + surface.h);
- rect.clip(_screen.w, _screen.h);
-
- if (!rect.isValidRect())
- return;
-
- assert(surface.bytesPerPixel == sizeof(OverlayColor));
-
- if (alpha != 256)
- restoreBackground(rect);
-
- if (themeTrans)
- drawSurface(rect, &surface, false, false, alpha);
- else {
- OverlayColor *dst = (OverlayColor*)_screen.getBasePtr(rect.left, rect.top);
- const OverlayColor *src = (OverlayColor*)surface.pixels;
-
- int h = rect.height();
- if (alpha == 256) {
- while (h--) {
- memcpy(dst, src, surface.pitch);
- dst += _screen.w;
- src += surface.w;
- }
- } else {
- int w = rect.width();
- while (h--) {
- for (int i = 0; i < w; ++i) {
- *dst = getColorAlpha(*src, *dst, alpha);
- }
- dst += _screen.w;
- src += surface.w;
- }
- }
- }
-
- addDirtyRect(rect);
-}
-
-void ThemeModern::drawSlider(const Common::Rect &rr, int width, WidgetStateInfo state) {
- if (!_initOk)
- return;
-
- Common::Rect r = rr;
-
- r.left++;
- r.right++;
-
- drawWidgetBackground(r, THEME_HINT_USE_SHADOW, kWidgetBackgroundSlider, kStateEnabled);
-
- Common::Rect r2 = r;
- r2.left = r.left;
- r2.top = r.top;
- r2.bottom = r.bottom-1;
- r2.right = r2.left + width-1;
- if (r2.right > r.right) {
- r2.right = r.right;
- }
-
- drawShadow(r2, surface(kButtonBkgdCorner), surface(kButtonBkgdTop), surface(kButtonBkgdLeft), surface(kButtonBkgd), kShadowButton);
-
- OverlayColor start, end;
- int alpha = 256;
-
- getStateColor(start, end, _colors[kSliderStart], _colors[kSliderEnd], _colors[kSliderHighStart], _colors[kSliderHighEnd], state);
-
- if (state != kStateHighlight)
- alpha = (state == kStateDisabled) ? -30 : 256;
-
- drawRectMasked(r2, surface(kSliderCorner), surface(kSliderTop), surface(kSliderLeft), surface(kSliderBkgd),
- alpha, start, end, _gradientFactors[kSliderFactor]);
-
- addDirtyRect(r);
-}
-
-void ThemeModern::drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, WidgetStateInfo state, TextAlign align) {
- if (!_initOk)
- return;
-
- Common::Rect r2 = shadowRect(r, kShadowSmall);
- restoreBackground(r2);
-
- OverlayColor start = _colors[kPopUpWidgetStart], end = _colors[kPopUpWidgetEnd];
- if (state == kStateHighlight) {
- start = _colors[kPopUpWidgetHighlightStart];
- end = _colors[kPopUpWidgetHighlightEnd];
- }
-
- drawShadow(r, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd), kShadowPopUp);
-
- drawRectMasked(r, surface(kPopUpWidgetBkgdCorner), surface(kPopUpWidgetBkgdTop), surface(kPopUpWidgetBkgdLeft), surface(kPopUpWidgetBkgd),
- (state == kStateDisabled) ? -30 : 256, start, end, _gradientFactors[kPopUpWidgetFactor]);
-
- const Graphics::Surface *arrow = surface(kWidgetArrow);
-
- int yOff = r.height() / 2 - arrow->h;
- if (yOff < 0)
- yOff = 0;
-
- Common::Rect arrowRect(r.right - 4 - arrow->w, r.top + yOff, r.right - 4, r.top + yOff + arrow->h);
- arrowRect.clip(r);
-
- drawSurface(arrowRect, arrow, false, false, (state == kStateDisabled) ? -30 : 256);
-
- arrowRect.top += arrow->h;
- arrowRect.bottom += arrow->h;
- arrowRect.clip(r);
- drawSurface(arrowRect, arrow, true, false, (state == kStateDisabled) ? -30 : 256);
-
- if (!sel.empty()) {
- Common::Rect text(r.left + 2, r.top + 3, r.right - 4, r.top + 3 + getFont()->getFontHeight());
- getFont()->drawString(&_screen, sel, text.left, text.top, text.width(), getColor(state), convertAligment(align), deltax, false);
- }
-
- addDirtyRect(r2);
-}
-
-void ThemeModern::drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state) {
- if (!_initOk)
- return;
- Common::Rect r2 = r;
-
- const Graphics::Surface *checkBox = surface(checked ? kCheckboxChecked : kCheckboxEmpty);
- int checkBoxSize = checkBox->w;
-
- restoreBackground(Common::Rect(r.left, r.top, r.left+checkBox->w, r.top+checkBox->h));
-
- drawSurface(Common::Rect(r.left, r.top, r.left+checkBox->w, r.top+checkBox->h), checkBox, false, false, (state == kStateDisabled) ? 128 : 256);
-
- r2.left += checkBoxSize + 5;
- getFont()->drawString(&_screen, str, r2.left, r2.top, r2.width(), getColor(state), Graphics::kTextAlignLeft, 0, false);
-
- addDirtyRect(r);
-}
-
-void ThemeModern::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array<Common::String> &tabs, int active, uint16 hints, int titleVPad, WidgetStateInfo state) {
- if (!_initOk)
- return;
-
- restoreBackground(r);
-
- // whole tab background
- drawRectMasked(r, surface(kTabBkgdCorner), surface(kTabBkgdTop), surface(kTabBkgdLeft), surface(kTabBkgd),
- /*(state == kStateDisabled) ? -30 : */256, _colors[kTabBackgroundStart], _colors[kTabBackgroundEnd],
- _gradientFactors[kTabFactor]);
-
- OverlayColor tabEnd = calcGradient(_colors[kTabActiveStart], _colors[kTabActiveEnd], tabHeight, r.height()-1, _gradientFactors[kTabFactor]);
-
- const int tabOffset = 1;
-
- // tab shadows
- for (int i = 0; i < (int)tabs.size(); ++i) {
- Common::Rect tabRect(r.left + i * (tabWidth + tabOffset), r.top, r.left + i * (tabWidth + tabOffset) + tabWidth, r.top + tabHeight);
- drawShadow(tabRect, surface(kTabBkgdCorner), surface(kTabBkgdTop), surface(kTabBkgdLeft), surface(kTabBkgd),
- kShadowSmall, true);
- }
-
- // inactive tabs
- for (int i = 0; i < (int)tabs.size(); ++i) {
- if (i == active)
- continue;
-
- Common::Rect tabRect(r.left + i * (tabWidth + tabOffset), r.top, r.left + i * (tabWidth + tabOffset) + tabWidth, r.top + tabHeight + 5);
- drawRectMasked(tabRect, surface(kTabBkgdCorner), surface(kTabBkgdTop), surface(kTabBkgdLeft), surface(kTabBkgd),
- 256, _colors[kTabInactiveStart], _colors[kTabInactiveEnd], _gradientFactors[kTabFactor], true);
-
- getFont()->drawString(&_screen, tabs[i], tabRect.left, tabRect.top+titleVPad, tabRect.width(), getColor(kStateEnabled), Graphics::kTextAlignCenter, 0, true);
- }
-
- // area shadow
- Common::Rect widgetBackground = Common::Rect(r.left, r.top + tabHeight - 1, r.right, r.top
- + tabHeight + 20);
- drawShadow(widgetBackground, surface(kTabBkgdCorner), surface(kTabBkgdTop), surface(kTabBkgdLeft), surface(kTabBkgd),
- kShadowSmall);
-
- // area itself
- widgetBackground = Common::Rect(r.left, r.top + tabHeight, r.right, r.bottom);
- drawRectMasked(widgetBackground, surface(kTabBkgdCorner), surface(kTabBkgdTop), surface(kTabBkgdLeft), surface(kTabBkgd),
- /*(state == kStateDisabled) ? -30 : */256, tabEnd, _colors[kTabActiveEnd],
- _gradientFactors[kTabFactor]);
- addDirtyRect(widgetBackground, true);
-
- // active tab
- if (active >= 0) {
- Common::Rect tabRect(r.left + active * (tabWidth + tabOffset), r.top, r.left + active * (tabWidth + tabOffset) + tabWidth, r.top + tabHeight + 5);
-
- Common::Rect shadowRect2(tabRect.left, r.top, tabRect.right, tabRect.bottom - 6);
- drawShadow(shadowRect2, surface(kTabBkgdCorner), surface(kTabBkgdTop), surface(kTabBkgdLeft), surface(kTabBkgd), kShadowSmall, false, true);
-
- drawRectMasked(tabRect, surface(kTabBkgdCorner), surface(kTabBkgdTop), surface(kTabBkgdLeft), surface(kTabBkgd),
- 256, _colors[kTabActiveStart], tabEnd, _gradientFactors[kTabFactor], true);
-
-
- getFont()->drawString(&_screen, tabs[active], tabRect.left, tabRect.top+titleVPad, tabRect.width(), getColor(kStateEnabled), Graphics::kTextAlignCenter, 0, true);
- }
-
- addDirtyRect(Common::Rect(r.left, r.top-2, r.right, r.bottom));
-}
-
-void ThemeModern::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState scrollState, WidgetStateInfo state) {
- if (!_initOk)
- return;
- const int UP_DOWN_BOX_HEIGHT = r.width() + 1;
- Common::Rect r2 = r;
-
- // draws the scrollbar background
- drawRectMasked(r2, surface(kScrollbarBkgdCorner), surface(kScrollbarBkgdTop), surface(kScrollbarBkgdLeft), surface(kScrollbarBkgd), 256,
- _colors[kScrollbarBackgroundStart], _colors[kScrollbarBackgroundEnd], _gradientFactors[kScrollbarBkgdFactor]);
-
- // draws the 'up' button
- OverlayColor buttonStart = _colors[kScrollbarButtonStart];
- OverlayColor buttonEnd = _colors[kScrollbarButtonEnd];
-
- if (scrollState == kScrollbarStateUp)
- getStateColor(buttonStart, buttonEnd, buttonStart, buttonEnd, _colors[kScrollbarButtonHighlightStart], _colors[kScrollbarButtonHighlightEnd], state);
-
- r2.bottom = r2.top + UP_DOWN_BOX_HEIGHT;
- drawRectMasked(r2, surface(kScrollbarBkgdCorner), surface(kScrollbarBkgdTop), surface(kScrollbarBkgdLeft), surface(kScrollbarBkgd), 256,
- buttonStart, buttonEnd, _gradientFactors[kScrollbarBkgdFactor]);
-
- const Graphics::Surface *arrow = surface(kWidgetArrow);
- r2.left += 1 + (r2.width() - arrow->w) / 2;
- r2.right = r2.left + arrow->w;
- r2.top += (r2.height() - arrow->h) / 2;
- r2.bottom = r2.top + arrow->h;
- drawSurface(r2, arrow, false, false, 256);
-
- // draws the slider
- OverlayColor sliderStart = _colors[kScrollbarSliderStart];
- OverlayColor sliderEnd = _colors[kScrollbarSliderEnd];
-
- if (scrollState == kScrollbarStateSlider)
- getStateColor(sliderStart, sliderEnd, sliderStart, sliderEnd, _colors[kScrollbarSliderHighlightStart], _colors[kScrollbarSliderHighlightEnd], state);
-
- r2 = r;
- r2.left += 1;
- r2.right -= 1;
- r2.top += sliderY;
- r2.bottom = r2.top + sliderHeight - 1;
-
- drawShadow(r2, surface(kSliderCorner), surface(kSliderTop), surface(kSliderLeft), surface(kSliderBkgd), kShadowSmall);
-
- r2.left += 1;
- r2.right -= 1;
-
- r2.bottom = r2.top + sliderHeight / 2 + surface(kScrollbarCorner)->h + 4;
- drawRectMasked(r2, surface(kScrollbarCorner), surface(kScrollbarTop), surface(kScrollbarLeft), surface(kScrollbarBkgd), 256,
- sliderStart, sliderEnd, _gradientFactors[kScrollbarFactor]);
- r2.top += sliderHeight / 2;
- r2.bottom += sliderHeight / 2 - surface(kScrollbarCorner)->h - 4;
- drawRectMasked(r2, surface(kScrollbarCorner), surface(kScrollbarTop), surface(kScrollbarLeft), surface(kScrollbarBkgd), 256,
- sliderEnd, sliderStart, _gradientFactors[kScrollbarFactor]);
-
- // draws the 'down' button
- buttonStart = _colors[kScrollbarButtonStart];
- buttonEnd = _colors[kScrollbarButtonEnd];
-
- if (scrollState == kScrollbarStateDown)
- getStateColor(buttonStart, buttonEnd, buttonStart, buttonEnd, _colors[kScrollbarButtonHighlightStart], _colors[kScrollbarButtonHighlightEnd], state);
-
- r2 = r;
- r2.top = r2.bottom - UP_DOWN_BOX_HEIGHT;
- drawRectMasked(r2, surface(kScrollbarBkgdCorner), surface(kScrollbarBkgdTop), surface(kScrollbarBkgdLeft), surface(kScrollbarBkgd), 256,
- buttonStart, buttonEnd, _gradientFactors[kScrollbarBkgdFactor]);
-
- r2.left += 1 + (r2.width() - arrow->w) / 2;
- r2.right = r2.left + arrow->w;
- r2.top += (r2.height() - arrow->h) / 2;
- r2.bottom = r2.top + arrow->h;
- drawSurface(r2, arrow, true, false, 256);
-
- addDirtyRect(r);
-}
-
-void ThemeModern::drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo state) {
- if (!_initOk)
- return;
-
- restoreBackground(r);
- if (!erase) {
- _screen.vLine(r.left, r.top, r.bottom-1, _colors[kCaretColor]);
- } else if (r.top >= 0) {
- // FIXME: hack to restore the caret background correctly
- const OverlayColor search = _colors[kTextInvertedBackground];
- const OverlayColor *src = (const OverlayColor*)_screen.getBasePtr(r.left-1, r.top-1);
- int height = r.height() + 2;
- if (r.top + height > _screen.h) {
- height = _screen.h - r.top;
- }
- bool drawInvBackground = false;
- while (height--) {
- if (src[0] == search || src[1] == search || src[2] == search) {
- drawInvBackground = true;
- }
- src += _screen.w;
- }
- if (drawInvBackground) {
- _screen.vLine(r.left, r.top, r.bottom-1, search);
- }
- }
- addDirtyRect(r);
-}
-
-void ThemeModern::drawLineSeparator(const Common::Rect &r, WidgetStateInfo state) {
- if (!_initOk)
- return;
- _screen.hLine(r.left - 1, r.top + r.height() / 2, r.right, _system->RGBToColor(0, 0, 0));
- addDirtyRect(r);
-}
-
-int ThemeModern::getTabSpacing() const {
- return 0;
-}
-int ThemeModern::getTabPadding() const {
- return 3;
-}
-
-#pragma mark - intern drawing
-
-void ThemeModern::restoreBackground(Common::Rect r, bool special) {
- r.clip(_screen.w, _screen.h);
- if (special) {
- r.clip(_shadowDrawArea);
- } else {
- r.clip(_drawArea);
- }
- if (_dialog) {
- if (!_dialog->screen.pixels) {
- return;
- }
- const OverlayColor *src = (const OverlayColor*)_dialog->screen.getBasePtr(r.left, r.top);
- OverlayColor *dst = (OverlayColor*)_screen.getBasePtr(r.left, r.top);
-
- int h = r.height();
- int w = r.width();
- while (h--) {
- memcpy(dst, src, w*sizeof(OverlayColor));
- src += _dialog->screen.w;
- dst += _screen.w;
- }
- }
-}
-
-bool ThemeModern::addDirtyRect(Common::Rect r, bool backup, bool special) {
- // TODO: implement proper dirty rect handling
- // FIXME: problem with the 'pitch'
- r.clip(_screen.w, _screen.h);
- if (special) {
- r.clip(_shadowDrawArea);
- } else {
- r.clip(_drawArea);
- }
- _system->copyRectToOverlay((OverlayColor*)_screen.getBasePtr(r.left, r.top), _screen.w, r.left, r.top, r.width(), r.height());
- if (_dialog && backup) {
- if (_dialog->screen.pixels) {
- OverlayColor *dst = (OverlayColor*)_dialog->screen.getBasePtr(r.left, r.top);
- const OverlayColor *src = (const OverlayColor*)_screen.getBasePtr(r.left, r.top);
- int h = r.height();
- while (h--) {
- memcpy(dst, src, r.width()*sizeof(OverlayColor));
- dst += _dialog->screen.w;
- src += _screen.w;
- }
- }
- }
- return true;
-}
-
-void ThemeModern::colorFade(const Common::Rect &r, OverlayColor start, OverlayColor end, uint factor) {
- OverlayColor *ptr = (OverlayColor*)_screen.getBasePtr(r.left, r.top);
- const int h = r.height();
- const int w = r.width();
- const int lastRow = r.height() - 1;
- const int ptrAdd = _screen.w - r.width();
- for (int l = 0; l < h; ++l) {
- OverlayColor col = calcGradient(start, end, l, lastRow, factor);
- for (int i = 0; i < w; ++i) {
- *ptr++ = col;
- }
- ptr += ptrAdd;
- }
-}
-
-void ThemeModern::drawRect(const Common::Rect &r, const Surface *corner, const Surface *top, const Surface *left, const Surface *fill, int alpha, bool skipLastRow) {
- drawRectMasked(r, corner, top, left, fill, alpha, _system->RGBToColor(255, 255, 255), _system->RGBToColor(255, 255, 255), 1, skipLastRow);
-}
-
-void ThemeModern::drawRectMasked(const Common::Rect &r, const Graphics::Surface *corner, const Graphics::Surface *top,
- const Graphics::Surface *left, const Graphics::Surface *fill, int alpha,
- OverlayColor start, OverlayColor end, uint factor, bool skipLastRow, bool skipTopRow) {
- int drawWidth = MIN(corner->w, MIN(top->w, MIN(left->w, fill->w)));
- int drawHeight = MIN(corner->h, MIN(top->h, MIN(left->h, fill->h)));
- int partsH = r.height() / drawHeight;
- int partsW = r.width() / drawWidth;
- int yPos = r.top;
-
- int specialHeight = 0;
- int specialWidth = 0;
-
- if (drawHeight*2 > r.height()) {
- drawHeight = r.height() / 2;
- partsH = 2;
- } else {
- specialHeight = r.height() % drawHeight;
- if (specialHeight != 0)
- ++partsH;
- }
-
- if (drawWidth*2 > r.width()) {
- drawWidth = r.width() / 2;
- partsW = 2;
- } else {
- specialWidth = r.width() % drawWidth;
- if (specialWidth != 0)
- ++partsW;
- }
-
- for (int y = 0; y < partsH; ++y) {
- int xPos = r.left;
- bool upDown = (y == partsH - 1);
-
- // calculate the correct drawing height
- int usedHeight = drawHeight;
- if (specialHeight && y == 1) {
- usedHeight = specialHeight;
- }
-
- OverlayColor startCol = calcGradient(start, end, yPos-r.top, r.height()-1, factor);
- OverlayColor endCol = calcGradient(start, end, yPos-r.top+usedHeight, r.height()-1, factor);
-
- for (int i = 0; i < partsW; ++i) {
- // calculate the correct drawing width
- int usedWidth = drawWidth;
- if (specialWidth && i == 1) {
- usedWidth = specialWidth;
- }
-
- // draw the right surface
- if (!i || i == partsW - 1) {
- if ((!y && !skipTopRow) || (y == partsH - 1 && !skipLastRow)) {
- drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), corner, upDown, (i == partsW - 1), alpha, startCol, endCol);
- } else {
- drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), left, upDown, (i == partsW - 1), alpha, startCol, endCol);
- }
- } else if (!y || (y == partsH - 1 && !skipLastRow)) {
- drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), top, upDown, false, alpha, startCol, endCol);
- } else {
- drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), fill, false, false, alpha, startCol, endCol);
- }
- xPos += usedWidth;
- }
-
- yPos += usedHeight;
- }
-}
-
-Common::Rect ThemeModern::shadowRect(const Common::Rect &r, uint32 shadowStyle) {
- switch (shadowStyle) {
- case kShadowButton:
- return Common::Rect(r.left - 1, r.top - 1, r.right + 1, r.bottom + 1);
-
- case kShadowEmboss:
- return Common::Rect(r.left - 1, r.top - 1, r.right + 1, r.bottom + 1);
-
- case kShadowPopUp:
- return Common::Rect(r.left - 1, r.top - 1, r.right + 3, r.bottom + 3);
-
- case kShadowFull:
- return Common::Rect(r.left - 2, r.top - 2, r.right + 4, r.bottom + 4);
-
- default:
- return Common::Rect(r.left - _shadowLeftWidth/2, r.top - _shadowTopHeight/2, r.right + _shadowRightWidth/2 + 1, r.bottom + _shadowBottomHeight/2 + 1);
- }
-
- return Common::Rect();
-}
-
-void ThemeModern::drawShadow(const Common::Rect &r, const Graphics::Surface *corner, const Graphics::Surface *top,
- const Graphics::Surface *left, const Graphics::Surface *fill, uint32 shadowStyle, bool skipLastRow, bool skipTopRow) {
- switch (shadowStyle) {
- case kShadowFull: {
- Common::Rect r2(r.left-1, r.top-1, r.right + 4, r.bottom + 4);
- Common::Rect r3(r.left, r.top+1, r.right + 3, r.bottom + 3);
- Common::Rect r4(r.left, r.top+1, r.right + 2, r.bottom + 2);
- Common::Rect r5(r.left, r.top, r.right + 1, r.bottom + 1);
-
- drawShadowRect(r2, r, corner, top, left, fill, kShadowTr0, skipLastRow, skipTopRow);
- drawShadowRect(r3, r, corner, top, left, fill, kShadowTr1, skipLastRow, skipTopRow);
- drawShadowRect(r4, r, corner, top, left, fill, kShadowTr2, skipLastRow, skipTopRow);
- drawShadowRect(r5, r, corner, top, left, fill, kShadowTr3, skipLastRow, skipTopRow);
- //drawShadowRect(r5, r, corner, top, left, fill, kShadowTr35, skipLastRow);
- } break;
-
- case kShadowSmall: {
- Common::Rect r3(r.left - _shadowLeftWidth/2, r.top - _shadowTopHeight/2, r.right + _shadowRightWidth/2, r.bottom + _shadowBottomHeight/2);
- Common::Rect r4(r.left - _shadowLeftWidth/2 + 1, r.top - _shadowTopHeight/2 + 1, r.right + _shadowRightWidth/2-1, r.bottom + _shadowBottomHeight/2-1);
-
- drawShadowRect(r3, r, corner, top, left, fill, kShadowTr1, skipLastRow, skipTopRow);
- drawShadowRect(r4, r, corner, top, left, fill, kShadowTr2, skipLastRow, skipTopRow);
- } break;
-
- case kShadowButton: {
- Common::Rect r2(r.left-1, r.top - 1, r.right, r.bottom);
- Common::Rect r4(r.left, r.top, r.right + 1, r.bottom + 1);
-
- drawShadowRect(r2, r, corner, top, left, fill, -kShadowTr35-256, skipLastRow, skipTopRow);
- drawShadowRect(r4, r, corner, top, left, fill, kShadowTr4, skipLastRow, skipTopRow);
- } break;
-
- case kShadowEmboss: {
- Common::Rect r2(r.left - 1, r.top - 1, r.right, r.bottom);
- Common::Rect r4(r.left + 1, r.top + 1, r.right + 1, r.bottom + 1);
-
- drawShadowRect(r2, r, corner, top, left, fill, kShadowTr5, skipLastRow, skipTopRow);
- drawShadowRect(r4, r, corner, top, left, fill, kShadowTr1, skipLastRow, skipTopRow);
- } break;
-
- case kShadowPopUp: {
- Common::Rect r2(r.left, r.top, r.right + 3, r.bottom + 3);
- Common::Rect r25(r.left-1, r.top-1, r.right + 2, r.bottom + 2);
- Common::Rect r3(r.left - 1, r.top-1, r.right, r.bottom);
- Common::Rect r4(r.left, r.top, r.right + 1, r.bottom + 1);
-
- drawShadowRect(r2, r, corner, top, left, fill, kShadowTr1, skipLastRow, skipTopRow);
- drawShadowRect(r25, r, corner, top, left, fill, kShadowTr2, skipLastRow, skipTopRow);
- drawShadowRect(r4, r, corner, top, left, fill, kShadowTr3, skipLastRow, skipTopRow);
- drawShadowRect(r3, r, corner, top, left, fill, -kShadowTr35-256, skipLastRow, skipTopRow);
- } break;
-
- default:
- break;
- }
-}
-
-void ThemeModern::drawShadowRect(const Common::Rect &r, const Common::Rect &area, const Graphics::Surface *corner,
- const Graphics::Surface *top, const Graphics::Surface *left, const Graphics::Surface *fill,
- int alpha, bool skipLastRow, bool skipTopRow) {
- int drawWidth = MIN(corner->w, MIN(top->w, MIN(left->w, fill->w)));
- int drawHeight = MIN(corner->h, MIN(top->h, MIN(left->h, fill->h)));
- int partsH = r.height() / drawHeight;
- int partsW = r.width() / drawWidth;
- int yPos = r.top;
-
- int yDrawTilesTop = 1 + (ABS(area.top - r.top) % drawHeight);
- int xDrawTilesLeft = 1 + (ABS(area.left - r.left) % drawWidth);
- int yDrawTilesBottom = 1 + (ABS(area.bottom - r.bottom) % drawHeight);
- int xDrawTilesRight = 1 + (ABS(area.right - r.right) % drawWidth);
-
- int specialHeight = 0;
- int specialWidth = 0;
-
- if (drawHeight*2 > r.height()) {
- drawHeight = r.height() / 2;
- partsH = 2;
- } else {
- specialHeight = r.height() % drawHeight;
- if (specialHeight != 0)
- ++partsH;
- }
-
- if (drawWidth*2 > r.width()) {
- drawWidth = r.width() / 2;
- partsW = 2;
- } else {
- specialWidth = r.width() % drawWidth;
- if (specialWidth != 0)
- ++partsW;
- }
-
- OverlayColor startCol = g_system->RGBToColor(0, 0, 0);
- OverlayColor endCol = g_system->RGBToColor(0, 0, 0);
-
- for (int y = 0; y < partsH; ++y) {
- // calculate the correct drawing height
- int usedHeight = drawHeight;
- if (specialHeight && y == 1) {
- usedHeight = specialHeight;
- }
-
- int xPos = r.left;
- bool upDown = (y == partsH - 1);
-
- for (int i = 0; i < partsW; ++i) {
- // calculate the correct drawing width
- int usedWidth = drawWidth;
- if (specialWidth && i == 1) {
- usedWidth = specialWidth;
- }
-
- if (i >= xDrawTilesLeft && i <= partsW - xDrawTilesRight && y >= yDrawTilesTop && y <= partsH - yDrawTilesBottom) {
- xPos += usedWidth;
- continue;
- }
-
- // draw the right surface
- if (!i || i == partsW - 1) {
- if ((!y && !skipTopRow) || (y == partsH - 1 && !skipLastRow)) {
- drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), corner, upDown, (i == partsW - 1), alpha, startCol, endCol);
- } else {
- drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), left, upDown, (i == partsW - 1), alpha, startCol, endCol);
- }
- } else if (!y || (y == partsH - 1 && !skipLastRow)) {
- drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), top, upDown, false, alpha, startCol, endCol);
- } else {
- drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), fill, upDown, false, alpha, startCol, endCol);
- }
- xPos += usedWidth;
- }
- yPos += usedHeight;
- }
-}
-
-void ThemeModern::drawSurface(const Common::Rect &r, const Surface *surf, bool upDown, bool leftRight, int alpha) {
- drawSurfaceMasked(r, surf, upDown, leftRight, alpha, _system->RGBToColor(255, 255, 255), _system->RGBToColor(255, 255, 255));
-}
-
-void ThemeModern::drawSurfaceMasked(const Common::Rect &r, const Graphics::Surface *surf, bool upDown, bool leftRight,
- int alpha, OverlayColor start, OverlayColor end, uint factor) {
- OverlayColor *dst = (OverlayColor*)_screen.getBasePtr(r.left, r.top);
- const OverlayColor *src = 0;
-
- const OverlayColor transparency = _colors[kColorTransparency];
- int drawWidth = (r.width() < surf->w) ? r.width() : surf->w;
- if (r.left + drawWidth > _screen.w)
- drawWidth = _screen.w - r.left;
-
- int srcAdd = 0;
- if (upDown) {
- src = (const OverlayColor*)surf->pixels + (surf->h - 1) * surf->w;
- srcAdd = -surf->w;
- } else {
- src = (const OverlayColor*)surf->pixels;
- srcAdd = surf->w;
- }
-
- int h = r.height();
- if (r.top + h > _screen.h)
- h = _screen.h - r.top;
-
- while (dst < _screen.pixels) {
- dst += _screen.w;
- src += srcAdd;
- --h;
- }
-
- if (h <= 0)
- return;
-
-#define NO_EFFECT(x) ((x) & rowColor)
-#define ALPHA_EFFECT(x) (getColorAlpha((x) & rowColor, *dst, alpha))
-#define DARKEN_EFFECT(x) (calcDimColor((x) & rowColor))
-
-#define LEFT_RIGHT_OFFSET(x) (drawWidth-x-1)
-#define NORMAL_OFFSET(x) (x)
-
-#define blitSurface(a, b) \
- const int dstAdd = _screen.w - drawWidth; \
- const int lastRow = r.height() - 1; \
- for (int i = 0; i < h; ++i) { \
- OverlayColor rowColor = calcGradient(start, end, i, lastRow, factor); \
- for (int x = 0; x < drawWidth; ++x, ++dst) { \
- OverlayColor col = src[a(x)]; \
- if (col != transparency) { \
- col = b(col); \
- *dst = col; \
- } \
- } \
- dst += dstAdd; \
- src += srcAdd; \
- }
- if (alpha >= 256) {
- if (leftRight) {
- blitSurface(LEFT_RIGHT_OFFSET, NO_EFFECT);
- } else {
- blitSurface(NORMAL_OFFSET, NO_EFFECT);
- }
- } else if (alpha < 0 && alpha >= -256) {
- int backUp = _dimPercentValue;
- _dimPercentValue = 256 * (100 - (-alpha)) / 100;
-
- if (leftRight) {
- blitSurface(LEFT_RIGHT_OFFSET, DARKEN_EFFECT);
- } else {
- blitSurface(NORMAL_OFFSET, DARKEN_EFFECT);
- }
-
- _dimPercentValue = backUp;
- } else {
- if (leftRight) {
- blitSurface(LEFT_RIGHT_OFFSET, ALPHA_EFFECT);
- } else {
- blitSurface(NORMAL_OFFSET, ALPHA_EFFECT);
- }
- }
-#undef blitSurface
-
-#undef NORMAL_OFFSET
-#undef LEFT_RIGHT_OFFSET
-
-#undef DARKEN_EFFECT
-#undef ALPHA_EFFECT
-#undef NO_EFFECT
-}
-
-OverlayColor ThemeModern::getColor(State state) {
- switch (state) {
- case kStateDisabled:
- return _colors[kColorStateDisabled];
-
- case kStateHighlight:
- return _colors[kColorStateHighlight];
-
- default:
- break;
- };
- return _colors[kColorStateEnabled];
-}
-
-const Graphics::Surface *ThemeModern::getImageSurface(const kThemeImages n) const {
- if (n == kImageLogo)
- return _images[kThemeLogo];
- else if (n == kImageLogoSmall)
- return _images[kThemeLogoSmall];
- else
- return 0;
-}
-
-void ThemeModern::resetupGuiRenderer() {
- if (_lastUsedBitMask == gBitFormat || !_initOk) {
- // ok same format no need to reload
- return;
- }
-
- _lastUsedBitMask = gBitFormat;
-
- int i;
- for (i = 0; i < kImageHandlesMax; ++i) {
- ImageMan.unregisterSurface(_imageHandles[i]);
- }
-
- for (i = 0; i < kImageHandlesMax; ++i) {
- ImageMan.registerSurface(_imageHandles[i], 0);
- _images[i] = ImageMan.getSurface(_imageHandles[i]);
- }
-
- setupColors();
-}
-
-void ThemeModern::setupColors() {
- // load the colors from the config file
- getColorFromConfig("main_dialog_start", _colors[kMainDialogStart]);
- getColorFromConfig("main_dialog_end", _colors[kMainDialogEnd]);
-
- getColorFromConfig("dialog_start", _colors[kDialogStart]);
- getColorFromConfig("dialog_end", _colors[kDialogEnd]);
-
- getColorFromConfig("color_state_disabled", _colors[kColorStateDisabled]);
- getColorFromConfig("color_state_highlight", _colors[kColorStateHighlight]);
- getColorFromConfig("color_state_enabled", _colors[kColorStateEnabled]);
- getColorFromConfig("color_transparency", _colors[kColorTransparency]);
-
- getColorFromConfig("text_inverted_background", _colors[kTextInvertedBackground]);
- getColorFromConfig("text_inverted_color", _colors[kTextInvertedColor]);
-
- getColorFromConfig("widget_bkgd_start", _colors[kWidgetBackgroundStart]);
- getColorFromConfig("widget_bkgd_end", _colors[kWidgetBackgroundEnd]);
- getColorFromConfig("widget_bkgd_small_start", _colors[kWidgetBackgroundSmallStart]);
- getColorFromConfig("widget_bkgd_small_end", _colors[kWidgetBackgroundSmallEnd]);
-
- getColorFromConfig("button_bkgd_start", _colors[kButtonBackgroundStart]);
- getColorFromConfig("button_bkgd_end", _colors[kButtonBackgroundEnd]);
- getColorFromConfig("button_bkgd_highlight_start", _colors[kButtonBackgroundHighlightStart]);
- getColorFromConfig("button_bkgd_highlight_end", _colors[kButtonBackgroundHighlightEnd]);
- getColorFromConfig("button_text_enabled", _colors[kButtonTextEnabled]);
- getColorFromConfig("button_text_disabled", _colors[kButtonTextDisabled]);
- getColorFromConfig("button_text_highlight", _colors[kButtonTextHighlight]);
-
- getColorFromConfig("slider_background_start", _colors[kSliderBackgroundStart]);
- getColorFromConfig("slider_background_end", _colors[kSliderBackgroundEnd]);
- getColorFromConfig("slider_start", _colors[kSliderStart]);
- getColorFromConfig("slider_end", _colors[kSliderEnd]);
- getColorFromConfig("slider_highlight_start", _colors[kSliderHighStart]);
- getColorFromConfig("slider_highlight_end", _colors[kSliderHighEnd]);
-
- getColorFromConfig("tab_background_start", _colors[kTabBackgroundStart]);
- getColorFromConfig("tab_background_end", _colors[kTabBackgroundEnd]);
-
- getColorFromConfig("tab_active_start", _colors[kTabActiveStart]);
- getColorFromConfig("tab_active_end", _colors[kTabActiveEnd]);
- getColorFromConfig("tab_inactive_start", _colors[kTabInactiveStart]);
- getColorFromConfig("tab_inactive_end", _colors[kTabInactiveEnd]);
-
- getColorFromConfig("scrollbar_background_start", _colors[kScrollbarBackgroundStart]);
- getColorFromConfig("scrollbar_background_end", _colors[kScrollbarBackgroundEnd]);
- getColorFromConfig("scrollbar_button_start", _colors[kScrollbarButtonStart]);
- getColorFromConfig("scrollbar_button_end", _colors[kScrollbarButtonEnd]);
- getColorFromConfig("scrollbar_slider_start", _colors[kScrollbarSliderStart]);
- getColorFromConfig("scrollbar_slider_end", _colors[kScrollbarSliderEnd]);
- getColorFromConfig("scrollbar_button_highlight_start", _colors[kScrollbarButtonHighlightStart]);
- getColorFromConfig("scrollbar_button_highlight_end", _colors[kScrollbarButtonHighlightEnd]);
- getColorFromConfig("scrollbar_slider_highlight_start", _colors[kScrollbarSliderHighlightStart]);
- getColorFromConfig("scrollbar_slider_highlight_end", _colors[kScrollbarSliderHighlightEnd]);
-
- getColorFromConfig("caret_color", _colors[kCaretColor]);
-
- getColorFromConfig("popupwidget_start", _colors[kPopUpWidgetStart]);
- getColorFromConfig("popupwidget_end", _colors[kPopUpWidgetEnd]);
- getColorFromConfig("popupwidget_highlight_start", _colors[kPopUpWidgetHighlightStart]);
- getColorFromConfig("popupwidget_highlight_end", _colors[kPopUpWidgetHighlightEnd]);
-
- getColorFromConfig("edittext_background_start", _colors[kEditTextBackgroundStart]);
- getColorFromConfig("edittext_background_end", _colors[kEditTextBackgroundEnd]);
-}
-
-#define FONT_NAME_NORMAL "newgui_normal"
-#define FONT_NAME_BOLD "newgui_bold"
-#define FONT_NAME_ITALIC "newgui_italic"
-#define FONT_NAME_FIXED_NORMAL "newgui_fixed_normal"
-#define FONT_NAME_FIXED_BOLD "newgui_fixed_bold"
-#define FONT_NAME_FIXED_ITALIC "newgui_fixed_italic"
-
-void ThemeModern::setupFonts() {
- if (_screen.w >= 400 && _screen.h >= 270) {
- setupFont("fontfile_bold", FONT_NAME_BOLD, kFontStyleBold);
- setupFont("fontfile_normal", FONT_NAME_NORMAL, kFontStyleNormal);
- setupFont("fontfile_italic", FONT_NAME_ITALIC, kFontStyleItalic);
-
- setupFont("fontfile_fixed_bold", FONT_NAME_FIXED_BOLD, kFontStyleFixedBold);
- setupFont("fontfile_fixed_normal", FONT_NAME_FIXED_NORMAL, kFontStyleFixedNormal);
- setupFont("fontfile_fixed_italic", FONT_NAME_FIXED_ITALIC, kFontStyleFixedItalic);
- } else {
- _fonts[kFontStyleBold] = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
- _fonts[kFontStyleNormal] = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
- _fonts[kFontStyleItalic] = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
- }
-}
-
-void ThemeModern::deleteFonts() {
- const Graphics::Font *normal = FontMan.getFontByName(FONT_NAME_NORMAL);
- const Graphics::Font *bold = FontMan.getFontByName(FONT_NAME_BOLD);
- const Graphics::Font *italic = FontMan.getFontByName(FONT_NAME_ITALIC);
-
- delete normal;
- delete bold;
- delete italic;
-
- FontMan.removeFontName(FONT_NAME_NORMAL);
- FontMan.removeFontName(FONT_NAME_BOLD);
- FontMan.removeFontName(FONT_NAME_ITALIC);
-}
-
-void ThemeModern::setupFont(const Common::String &key, const Common::String &name, FontStyle style) {
- if (_evaluator->getVar(key) == EVAL_STRING_VAR) {
- _fonts[style] = FontMan.getFontByName(name);
-
- if (!_fonts[style]) {
- Common::String temp(_evaluator->getStringVar(key));
-
- _fonts[style] = loadFont(temp.c_str());
- if (!_fonts[style])
- error("Couldn't load %s font '%s'", key.c_str(), temp.c_str());
-
- FontMan.assignFontToName(name, _fonts[style]);
- }
- } else {
- _fonts[style] = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
- }
-}
-
-#pragma mark -
-
-void ThemeModern::processExtraValues() {
- // TODO: think of unloading all old graphic files first, instead of just
- // loading new ones if needed when this is processed?
-
- // load the pixmap filenames from the config file
-#define loadRectData(type, str) \
- _imageHandles[k##type##Corner] = _evaluator->getStringVar("pix_"str"_corner"); \
- _imageHandles[k##type##Top] = _evaluator->getStringVar("pix_"str"_top"); \
- _imageHandles[k##type##Left] = _evaluator->getStringVar("pix_"str"_left"); \
- _imageHandles[k##type] = _evaluator->getStringVar("pix_"str"_bkgd")
-
- loadRectData(DialogBkgd, "dialog");
- loadRectData(WidgetBkgd, "widget");
- loadRectData(WidgetSmallBkgd, "widget_small");
- loadRectData(TabBkgd, "tab");
- loadRectData(SliderBkgd, "slider_bkgd");
- loadRectData(Slider, "slider");
- loadRectData(ScrollbarBkgd, "scrollbar_bkgd");
- loadRectData(Scrollbar, "scrollbar");
- loadRectData(ButtonBkgd, "button");
- loadRectData(PopUpWidgetBkgd, "popupwidget");
- loadRectData(EditTextBkgd, "edittext_bkgd");
-
-#undef loadRectData
-
- _imageHandles[kCheckboxEmpty] = _evaluator->getStringVar("pix_checkbox_empty");
- _imageHandles[kCheckboxChecked] = _evaluator->getStringVar("pix_checkbox_checked");
-
- _imageHandles[kWidgetArrow] = _evaluator->getStringVar("pix_widget_arrow");
-
- _imageHandles[kThemeLogo] = _evaluator->getStringVar("pix_theme_logo");
- _imageHandles[kThemeLogoSmall] = _evaluator->getStringVar("pix_theme_logo_small");
-
- _imageHandles[kGUICursor] = _evaluator->getStringVar("pix_cursor_image");
-
- for (int i = 0; i < kImageHandlesMax; ++i) {
- ImageMan.registerSurface(_imageHandles[i], 0);
- _images[i] = ImageMan.getSurface(_imageHandles[i]);
- }
-
- // load the gradient factors from the config file
- _gradientFactors[kMainDialogFactor] = _evaluator->getVar("gradient_dialog_main", 1);
- _gradientFactors[kDialogFactor] = _evaluator->getVar("gradient_dialog", 1);
- _gradientFactors[kDialogSpecialFactor] = _evaluator->getVar("gradient_dialog_special", 1);
-
- _gradientFactors[kWidgetSmallFactor] = _evaluator->getVar("gradient_widget_small", 1);
- _gradientFactors[kWidgetFactor] = _evaluator->getVar("gradient_widget", 1);
-
- _gradientFactors[kButtonFactor] = _evaluator->getVar("gradient_button", 1);
-
- _gradientFactors[kSliderFactor] = _evaluator->getVar("gradient_slider", 1);
- _gradientFactors[kSliderBackground] = _evaluator->getVar("gradient_silder_bkgd", 1);
-
- _gradientFactors[kTabFactor] = _evaluator->getVar("gradient_tab", 1);
-
- _gradientFactors[kScrollbarFactor] = _evaluator->getVar("gradient_scrollbar", 1);
- _gradientFactors[kScrollbarBkgdFactor] = _evaluator->getVar("gradient_scrollbar_background", 1);
-
- _gradientFactors[kPopUpWidgetFactor] = _evaluator->getVar("gradient_popupwidget", 1);
-
- _gradientFactors[kEditTextFactor] = _evaluator->getVar("gradient_edittext", 1);
-
- // load values with default values from the config file
- _shadowLeftWidth = _evaluator->getVar("shadow_left_width", 2);
- _shadowRightWidth = _evaluator->getVar("shadow_right_width", 4);
- _shadowTopHeight = _evaluator->getVar("shadow_top_height", 2);
- _shadowBottomHeight = _evaluator->getVar("shadow_bottom_height", 4);
-
- _cursorHotspotX = _evaluator->getVar("cursor_hotspot_x", 0);
- _cursorHotspotY = _evaluator->getVar("cursor_hotspot_y", 0);
-
- _cursorTargetScale = _evaluator->getVar("cursor_targetScale", 1);
-
- // inactive dialog shading stuff
-
- ShadingStyle shading = (ShadingStyle)_evaluator->getVar("inactive_dialog_shading", kShadingNone);
-
- switch (shading) {
- case kShadingNone:
- _dialogShadingCallback = 0;
- break;
-
- case kShadingLuminance:
- _dialogShadingCallback = &ThemeModern::calcLuminance;
- break;
-
- case kShadingDim:
- _dimPercentValue = _evaluator->getVar("shading_dim_percent", -1);
-
- if (_dimPercentValue < 0) {
- _dimPercentValue = 0;
- } else if (_dimPercentValue > 100) {
- _dimPercentValue = 100;
- }
-
- if (_dimPercentValue != 0) {
- _dimPercentValue = 256 * (100 - _dimPercentValue) / 100;
- _dialogShadingCallback = &ThemeModern::calcDimColor;
- }
- break;
-
- default:
- warning("no valid 'inactive_dialog_shading' specified");
- }
-
- setupFonts();
-
- // load the colors from the config file
- setupColors();
-
- // creates cursor image
- if (_system->hasFeature(OSystem::kFeatureCursorHasPalette)) {
- createCursor();
- }
-}
-
-#pragma mark -
-
-OverlayColor ThemeModern::calcLuminance(OverlayColor col) {
- uint8 r, g, b;
- _system->colorToRGB(col, r, g, b);
-
- // A better (but slower) formula to calculate the luminance would be:
- //uint lum = (byte)((0.299 * r + 0.587 * g + 0.114 * b) + 0.5);
- // Note that the approximation below will only produce values between
- // (and including) 0 and 221.
- uint lum = (r >> 2) + (g >> 1) + (b >> 3);
-
- return _system->RGBToColor(lum, lum, lum);
-}
-
-OverlayColor ThemeModern::calcDimColor(OverlayColor col) {
- uint8 r, g, b;
- _system->colorToRGB(col, r, g, b);
-
- r = r * _dimPercentValue >> 8;
- g = g * _dimPercentValue >> 8;
- b = b * _dimPercentValue >> 8;
-
- return _system->RGBToColor(r, g, b);
-}
-
-#pragma mark -
-
-void ThemeModern::setUpCursor() {
- CursorMan.pushCursorPalette(_cursorPal, 0, MAX_CURS_COLORS);
- CursorMan.pushCursor(_cursor, _cursorWidth, _cursorHeight, _cursorHotspotX, _cursorHotspotY, 255, _cursorTargetScale);
- CursorMan.showMouse(true);
-}
-
-void ThemeModern::createCursor() {
- const Surface *cursor = _images[kGUICursor];
-
- _cursorWidth = cursor->w;
- _cursorHeight = cursor->h;
-
- uint colorsFound = 0;
- const OverlayColor *src = (const OverlayColor*)cursor->pixels;
-
- byte *table = new byte[65536];
- assert(table);
- memset(table, 0, sizeof(byte)*65536);
-
- byte r, g, b;
-
- _system->colorToRGB(_colors[kColorTransparency], r, g, b);
- uint16 transparency = RGBToColor<ColorMasks<565> >(r, g, b);
-
- delete[] _cursor;
-
- _cursor = new byte[_cursorWidth * _cursorHeight];
- assert(_cursor);
- memset(_cursor, 255, sizeof(byte)*_cursorWidth*_cursorHeight);
-
- for (uint y = 0; y < _cursorHeight; ++y) {
- for (uint x = 0; x < _cursorWidth; ++x) {
- _system->colorToRGB(src[x], r, g, b);
- uint16 col = RGBToColor<ColorMasks<565> >(r, g, b);
- if (!table[col] && col != transparency) {
- table[col] = colorsFound++;
-
- uint index = table[col];
- _cursorPal[index * 4 + 0] = r;
- _cursorPal[index * 4 + 1] = g;
- _cursorPal[index * 4 + 2] = b;
- _cursorPal[index * 4 + 3] = 0xFF;
-
- if (colorsFound > MAX_CURS_COLORS)
- error("Cursor contains too much colors (%d, but only %d are allowed)", colorsFound, MAX_CURS_COLORS);
- }
-
- if (col != transparency) {
- uint index = table[col];
- _cursor[y * _cursorWidth + x] = index;
- }
- }
- src += _cursorWidth;
- }
-
- _useCursor = true;
- delete[] table;
-}
-
-#pragma mark -
-
-template<class T>
-inline OverlayColor getColorAlphaImpl(OverlayColor col1, OverlayColor col2, int alpha) {
- OverlayColor output = 0;
- output |= ((alpha * ((col1 & T::kRedMask) - (col2 & T::kRedMask)) >> 8) + (col2 & T::kRedMask)) & T::kRedMask;
- output |= ((alpha * ((col1 & T::kGreenMask) - (col2 & T::kGreenMask)) >> 8) + (col2 & T::kGreenMask)) & T::kGreenMask;
- output |= ((alpha * ((col1 & T::kBlueMask) - (col2 & T::kBlueMask)) >> 8) + (col2 & T::kBlueMask)) & T::kBlueMask;
- output |= ~(T::kRedMask | T::kGreenMask | T::kBlueMask);
- return output;
-}
-
-// broken implementation!
-template<class T>
-inline OverlayColor getColorAlphaImp2(OverlayColor col1, OverlayColor col2, int alpha) {
- OverlayColor output = 0;
- output |= ((alpha * ((~col1 & T::kRedMask) - (col2 & T::kRedMask)) >> 8) + (col2 & T::kRedMask)) & T::kRedMask;
- output |= ((alpha * ((~col1 & T::kGreenMask) - (col2 & T::kGreenMask)) >> 8) + (col2 & T::kGreenMask)) & T::kGreenMask;
- output |= ((alpha * ((~col1 & T::kBlueMask) - (col2 & T::kBlueMask)) >> 8) + (col2 & T::kBlueMask)) & T::kBlueMask;
- output |= ~(T::kRedMask | T::kGreenMask | T::kBlueMask);
- return output;
-}
-
-OverlayColor getColorAlpha(OverlayColor col1, OverlayColor col2, int alpha) {
- if (alpha >= 0) {
- if (gBitFormat == 565) {
- return getColorAlphaImpl<ColorMasks<565> >(col1, col2, alpha);
- } else {
- return getColorAlphaImpl<ColorMasks<555> >(col1, col2, alpha);
- }
- } else {
- if (gBitFormat == 565) {
- return getColorAlphaImp2<ColorMasks<565> >(col1, col2, -alpha - 256);
- } else {
- return getColorAlphaImp2<ColorMasks<555> >(col1, col2, -alpha - 256);
- }
- }
-}
-
-template<class T>
-inline OverlayColor calcGradient(OverlayColor start, OverlayColor end, int pos) {
- OverlayColor output = 0;
- output |= (start + ((((end & T::kRedMask) - (start & T::kRedMask))) * pos >> 12)) & T::kRedMask;
- output |= (start + ((((end & T::kGreenMask) - (start & T::kGreenMask))) * pos >> 12)) & T::kGreenMask;
- output |= (start + ((((end & T::kBlueMask) - (start & T::kBlueMask))) * pos >> 12)) & T::kBlueMask;
- output |= ~(T::kRedMask | T::kGreenMask | T::kBlueMask);
- return output;
-}
-
-OverlayColor calcGradient(OverlayColor start, OverlayColor end, int pos, int max, uint factor = 1) {
- pos *= factor;
- if (pos >= max)
- return end;
-
- pos = (0x1000 * pos) / max;
-
- if (gBitFormat == 565) {
- return calcGradient<ColorMasks<565> >(start, end, pos);
- } else {
- return calcGradient<ColorMasks<555> >(start, end, pos);
- }
-}
-
-void getStateColor(OverlayColor &s, OverlayColor &e,
- OverlayColor enabledS, OverlayColor enabledE,
- OverlayColor highlightS, OverlayColor highlightE,
- Theme::WidgetStateInfo state) {
- if (state == Theme::kStateHighlight) {
- s = highlightS;
- e = highlightE;
- } else {
- s = enabledS;
- e = enabledE;
- }
-}
-
-} // end of namespace GUI
-
-#endif
diff --git a/gui/ThemeModern.h b/gui/ThemeModern.h
deleted file mode 100644
index d64d18242e..0000000000
--- a/gui/ThemeModern.h
+++ /dev/null
@@ -1,341 +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 GUI_THEMEMODERN_H
-#define GUI_THEMEMODERN_H
-
-#ifndef DISABLE_FANCY_THEMES
-
-#include "gui/theme.h"
-
-namespace GUI {
-
-class ThemeModern : public Theme {
-public:
- ThemeModern(OSystem *system, const Common::String &stylefile, const Common::ConfigFile *cfg = 0);
- virtual ~ThemeModern();
-
- bool init();
- void deinit();
-
- void refresh();
-
- bool ownCursor() const { return _useCursor; }
-
- void enable();
- void disable();
-
- void openDialog(bool topDialog);
- void closeAllDialogs();
-
- void clearAll();
- void updateScreen();
-
- void setDrawArea(const Common::Rect &r);
- void resetDrawArea();
-
- const Graphics::Font *getFont(FontStyle font = kFontStyleBold) const { return _fonts[font]; }
- int getFontHeight(FontStyle font = kFontStyleBold) const { if (_fonts[font]) return _fonts[font]->getFontHeight(); return 0; }
- int getStringWidth(const Common::String &str, FontStyle font = kFontStyleBold) const { if (_fonts[font]) return _fonts[font]->getStringWidth(str); return 0; }
- int getCharWidth(byte c, FontStyle font = kFontStyleBold) const { if (_fonts[font]) return _fonts[font]->getCharWidth(c); return 0; }
-
- 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);
-
- void drawWidgetBackground(const Common::Rect &r, uint16 hints, WidgetBackground background, WidgetStateInfo state);
- void drawButton(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, uint16 hints);
- void drawSurface(const Common::Rect &r, const Graphics::Surface &surface, WidgetStateInfo state, int alpha, bool themeTrans);
- void drawSlider(const Common::Rect &r, int width, WidgetStateInfo state);
- void drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state);
- void drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array<Common::String> &tabs, int active, uint16 hints, int titleVPad, WidgetStateInfo state);
- void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState, WidgetStateInfo state);
- void drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, WidgetStateInfo state, TextAlign align);
- void drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo state);
- void drawLineSeparator(const Common::Rect &r, WidgetStateInfo state);
-
- void restoreBackground(Common::Rect r, bool special = false);
- bool addDirtyRect(Common::Rect r, bool backup = false, bool special = false);
-
- int getTabSpacing() const;
- int getTabPadding() const;
-
- bool supportsImages() const { return true; }
- const Graphics::Surface *getImageSurface(const kThemeImages n) const;
-private:
- void colorFade(const Common::Rect &r, OverlayColor start, OverlayColor end, uint factor = 1);
- void drawRect(const Common::Rect &r, const Graphics::Surface *corner, const Graphics::Surface *top,
- const Graphics::Surface *left, const Graphics::Surface *fill, int alpha, bool skipLastRow = false);
- void drawRectMasked(const Common::Rect &r, const Graphics::Surface *corner, const Graphics::Surface *top,
- const Graphics::Surface *left, const Graphics::Surface *fill, int alpha,
- OverlayColor start, OverlayColor end, uint factor = 1, bool skipLastRow = false, bool skipTopRow = false);
- void drawSurface(const Common::Rect &r, const Graphics::Surface *surf, bool upDown, bool leftRight, int alpha);
- void drawSurfaceMasked(const Common::Rect &r, const Graphics::Surface *surf, bool upDown, bool leftRight, int alpha,
- OverlayColor start, OverlayColor end, uint factor = 1);
-
- enum ShadowStyles {
- kShadowFull = 0,
- kShadowSmall = 1,
- kShadowButton = 2,
- kShadowEmboss = 3,
- kShadowPopUp = 4
- };
-
- Common::Rect shadowRect(const Common::Rect &r, uint32 shadowStyle);
- void drawShadow(const Common::Rect &r, const Graphics::Surface *corner, const Graphics::Surface *top,
- const Graphics::Surface *left, const Graphics::Surface *fill, uint32 shadowStyle, bool skipLastRow = false,
- bool skipTopRow = false);
- void drawShadowRect(const Common::Rect &r, const Common::Rect &area, const Graphics::Surface *corner,
- const Graphics::Surface *top, const Graphics::Surface *left, const Graphics::Surface *fill,
- int alpha, bool skipLastRow = false, bool skipTopRow = false);
-
- int _shadowLeftWidth, _shadowRightWidth;
- int _shadowTopHeight, _shadowBottomHeight;
-
- OSystem *_system;
- Graphics::Surface _screen;
- Common::Rect _shadowDrawArea;
-
- bool _initOk;
- bool _forceRedraw;
- bool _enabled;
-
- int _lastUsedBitMask;
- void resetupGuiRenderer();
- void setupColors();
-
- OverlayColor getColor(State state);
-
- struct DialogState {
- Graphics::Surface screen;
- } *_dialog;
-
- void setupFonts();
- void deleteFonts();
-
- void setupFont(const Common::String &key, const Common::String &name, FontStyle style);
-
- const Graphics::Font *_fonts[kFontStyleMax];
-
-private:
- void processExtraValues();
-
- enum ImageHandles {
- kDialogBkgdCorner = 0,
- kDialogBkgdTop = 1,
- kDialogBkgdLeft = 2,
- kDialogBkgd = 3,
-
- kWidgetBkgdCorner = 4,
- kWidgetBkgdTop = 5,
- kWidgetBkgdLeft = 6,
- kWidgetBkgd = 7,
-
- kCheckboxEmpty = 8,
- kCheckboxChecked = 9,
-
- kWidgetArrow = 10,
-
- kTabBkgdCorner = 11,
- kTabBkgdTop = 12,
- kTabBkgdLeft = 13,
- kTabBkgd = 14,
-
- kSliderBkgdCorner = 15,
- kSliderBkgdTop = 16,
- kSliderBkgdLeft = 17,
- kSliderBkgd = 18,
-
- kSliderCorner = 19,
- kSliderTop = 20,
- kSliderLeft = 21,
- kSlider = 22,
-
- kScrollbarBkgdCorner = 23,
- kScrollbarBkgdTop = 24,
- kScrollbarBkgdLeft = 25,
- kScrollbarBkgd = 26,
-
- kScrollbarCorner = 27,
- kScrollbarTop = 28,
- kScrollbarLeft = 29,
- kScrollbar = 30,
-
- kButtonBkgdCorner = 31,
- kButtonBkgdTop = 32,
- kButtonBkgdLeft = 33,
- kButtonBkgd = 34,
-
- kWidgetSmallBkgdCorner = 35,
- kWidgetSmallBkgdTop = 36,
- kWidgetSmallBkgdLeft = 37,
- kWidgetSmallBkgd = 38,
-
- kThemeLogo = 39,
- kThemeLogoSmall = 40,
-
- kPopUpWidgetBkgdCorner = 41,
- kPopUpWidgetBkgdTop = 42,
- kPopUpWidgetBkgdLeft = 43,
- kPopUpWidgetBkgd = 44,
-
- kEditTextBkgdCorner = 45,
- kEditTextBkgdTop = 46,
- kEditTextBkgdLeft = 47,
- kEditTextBkgd = 48,
-
- kGUICursor = 49,
-
- kImageHandlesMax
- };
-
-private:
- int _dimPercentValue;
- typedef OverlayColor (ThemeModern::*InactiveDialogCallback)(OverlayColor col);
- InactiveDialogCallback _dialogShadingCallback;
-
- OverlayColor calcLuminance(OverlayColor col);
- OverlayColor calcDimColor(OverlayColor col);
-
- bool _useCursor;
- void setUpCursor();
- void createCursor();
- int _cursorHotspotX, _cursorHotspotY;
- int _cursorTargetScale;
-#define MAX_CURS_COLORS 255
- byte *_cursor;
- bool _needPaletteUpdates;
- uint _cursorWidth, _cursorHeight;
- byte _cursorPal[4*MAX_CURS_COLORS];
-
-private:
- Common::String _imageHandles[kImageHandlesMax];
- const Graphics::Surface **_images;
-
- enum ColorHandles {
- kMainDialogStart = 0,
- kMainDialogEnd = 1,
-
- kDialogStart = 2,
- kDialogEnd = 3,
-
- kColorStateDisabled = 4,
- kColorStateHighlight = 5,
- kColorStateEnabled = 6,
- kColorTransparency = 7,
-
- kTextInvertedBackground = 8,
- kTextInvertedColor = 9,
-
- kWidgetBackgroundStart = 10,
- kWidgetBackgroundEnd = 11,
- kWidgetBackgroundSmallStart = 12,
- kWidgetBackgroundSmallEnd = 13,
-
- kButtonBackgroundStart = 14,
- kButtonBackgroundEnd = 15,
- kButtonTextEnabled = 16,
- kButtonTextDisabled = 17,
- kButtonTextHighlight = 18,
-
- kSliderBackgroundStart = 19,
- kSliderBackgroundEnd = 20,
- kSliderStart = 21,
- kSliderEnd = 22,
-
- kTabBackgroundStart = 23,
- kTabBackgroundEnd = 24,
-
- kScrollbarBackgroundStart = 25,
- kScrollbarBackgroundEnd = 26,
- kScrollbarButtonStart = 27,
- kScrollbarButtonEnd = 28,
- kScrollbarSliderStart = 29,
- kScrollbarSliderEnd = 30,
-
- kCaretColor = 31,
-
- kSliderHighStart = 32,
- kSliderHighEnd = 33,
-
- kButtonBackgroundHighlightStart = 34,
- kButtonBackgroundHighlightEnd = 35,
-
- kScrollbarButtonHighlightStart = 36,
- kScrollbarButtonHighlightEnd = 37,
- kScrollbarSliderHighlightStart = 38,
- kScrollbarSliderHighlightEnd = 39,
-
- kPopUpWidgetStart = 40,
- kPopUpWidgetEnd = 41,
- kPopUpWidgetHighlightStart = 42,
- kPopUpWidgetHighlightEnd = 43,
-
- kEditTextBackgroundStart = 44,
- kEditTextBackgroundEnd = 45,
-
- kTabActiveStart = 46,
- kTabActiveEnd = 47,
- kTabInactiveStart = 48,
- kTabInactiveEnd = 49,
-
- kColorHandlesMax
- };
-
- OverlayColor _colors[kColorHandlesMax];
-
- enum GradientFactors {
- kMainDialogFactor = 0,
- kDialogFactor = 1,
- kDialogSpecialFactor = 2,
-
- kWidgetSmallFactor = 3,
- kWidgetFactor = 4,
-
- kButtonFactor = 5,
-
- kSliderFactor = 6,
- kSliderBackground = 7,
-
- kTabFactor = 7,
-
- kScrollbarFactor = 8,
- kScrollbarBkgdFactor = 9,
-
- kPopUpWidgetFactor = 10,
-
- kEditTextFactor = 11,
-
- kMaxGradientFactors
- };
-
- uint _gradientFactors[kMaxGradientFactors];
-};
-
-} // end of namespace GUI
-
-#endif
-
-#endif
-
diff --git a/gui/ThemeParser.cpp b/gui/ThemeParser.cpp
new file mode 100644
index 0000000000..52fb90b2a6
--- /dev/null
+++ b/gui/ThemeParser.cpp
@@ -0,0 +1,793 @@
+/* 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 "common/system.h"
+#include "common/events.h"
+#include "common/hashmap.h"
+#include "common/hash-str.h"
+#include "common/xmlparser.h"
+
+#include "gui/ThemeEngine.h"
+#include "gui/ThemeParser.h"
+#include "gui/newgui.h"
+#include "graphics/VectorRenderer.h"
+
+namespace GUI {
+
+using namespace Graphics;
+using namespace Common;
+
+ThemeParser::ThemeParser(ThemeEngine *parent) : XMLParser() {
+
+ _drawFunctions["circle"] = &Graphics::VectorRenderer::drawCallback_CIRCLE;
+ _drawFunctions["square"] = &Graphics::VectorRenderer::drawCallback_SQUARE;
+ _drawFunctions["roundedsq"] = &Graphics::VectorRenderer::drawCallback_ROUNDSQ;
+ _drawFunctions["bevelsq"] = &Graphics::VectorRenderer::drawCallback_BEVELSQ;
+ _drawFunctions["line"] = &Graphics::VectorRenderer::drawCallback_LINE;
+ _drawFunctions["triangle"] = &Graphics::VectorRenderer::drawCallback_TRIANGLE;
+ _drawFunctions["fill"] = &Graphics::VectorRenderer::drawCallback_FILLSURFACE;
+ _drawFunctions["tab"] = &Graphics::VectorRenderer::drawCallback_TAB;
+ _drawFunctions["void"] = &Graphics::VectorRenderer::drawCallback_VOID;
+ _drawFunctions["bitmap"] = &Graphics::VectorRenderer::drawCallback_BITMAP;
+ _drawFunctions["cross"] = &Graphics::VectorRenderer::drawCallback_CROSS;
+
+ _defaultStepGlobal = defaultDrawStep();
+ _defaultStepLocal = 0;
+ _theme = parent;
+}
+
+void ThemeParser::cleanup() {
+ delete _defaultStepGlobal;
+ delete _defaultStepLocal;
+
+ _defaultStepGlobal = defaultDrawStep();
+ _defaultStepLocal = 0;
+ _palette.clear();
+}
+
+Graphics::DrawStep *ThemeParser::defaultDrawStep() {
+ Graphics::DrawStep *step = new DrawStep;
+
+ step->fgColor.set = false;
+ step->bgColor.set = false;
+ step->gradColor1.set = false;
+ step->gradColor2.set = false;
+
+ step->xAlign = Graphics::DrawStep::kVectorAlignManual;
+ step->yAlign = Graphics::DrawStep::kVectorAlignManual;
+ step->x = 0;
+ step->y = 0;
+ step->w = 0;
+ step->h = 0;
+
+ step->extraData = 0;
+ step->factor = 1;
+ step->autoWidth = true;
+ step->autoHeight = true;
+ step->fillMode = Graphics::VectorRenderer::kFillDisabled;
+ step->scale = (1 << 16);
+ step->shadow = 0;
+ step->bevel = 0;
+ step->stroke = 0;
+ step->radius = 0xFF;
+
+ return step;
+}
+
+Graphics::DrawStep *ThemeParser::newDrawStep() {
+ assert(_defaultStepGlobal);
+ Graphics::DrawStep *step = 0 ; //new DrawStep;
+
+ if (_defaultStepLocal) {
+ step = new DrawStep(*_defaultStepLocal);
+ } else {
+ step = new DrawStep(*_defaultStepGlobal);
+ }
+
+ return step;
+}
+
+bool ThemeParser::parserCallback_defaults(ParserNode *node) {
+ ParserNode *parentNode = getParentNode(node);
+ Graphics::DrawStep *step = 0;
+
+ if (parentNode->name == "render_info") {
+ step = _defaultStepGlobal;
+ } else if (parentNode->name == "drawdata") {
+ if (_defaultStepLocal == 0)
+ _defaultStepLocal = new DrawStep(*_defaultStepLocal);
+
+ step = _defaultStepLocal;
+ } else {
+ return parserError("<default> key out of scope. Must be inside <drawdata> or <render_info> keys.");
+ }
+
+ return parseDrawStep(node, step, false);
+}
+
+bool ThemeParser::parserCallback_font(ParserNode *node) {
+ int red, green, blue;
+
+ if (resolutionCheck(node->values["resolution"]) == false) {
+ node->ignore = true;
+ return true;
+ }
+
+ if (_palette.contains(node->values["color"]))
+ getPaletteColor(node->values["color"], red, green, blue);
+ else if (!parseIntegerKey(node->values["color"].c_str(), 3, &red, &green, &blue))
+ return parserError("Error when parsing color value for font definition.");
+
+ if (!_theme->addFont(node->values["id"], node->values["file"], red, green, blue))
+ return parserError("Error when loading Font in theme engine.");
+
+ return true;
+}
+
+bool ThemeParser::parserCallback_fonts(ParserNode *node) {
+ return true;
+}
+
+bool ThemeParser::parserCallback_cursor(ParserNode *node) {
+ if (resolutionCheck(node->values["resolution"]) == false) {
+ node->ignore = true;
+ return true;
+ }
+
+ int spotx, spoty, scale;
+
+ if (!parseIntegerKey(node->values["hotspot"].c_str(), 2, &spotx, &spoty))
+ return parserError("Error when parsing cursor Hot Spot coordinates.");
+
+ if (!parseIntegerKey(node->values["scale"].c_str(), 1, &scale))
+ return parserError("Error when parsing cursor scale.");
+
+ if (!_theme->createCursor(node->values["file"], spotx, spoty, scale))
+ return parserError("Error when creating Bitmap Cursor.");
+
+ return true;
+}
+
+bool ThemeParser::parserCallback_bitmap(ParserNode *node) {
+ if (resolutionCheck(node->values["resolution"]) == false) {
+ node->ignore = true;
+ return true;
+ }
+
+ if (!_theme->addBitmap(node->values["filename"]))
+ return parserError("Error when loading Bitmap file '%s'", node->values["filename"].c_str());
+
+ return true;
+}
+
+bool ThemeParser::parserCallback_text(ParserNode *node) {
+ GUI::Theme::TextAlign alignH;
+ GUI::Theme::TextAlignVertical alignV;
+
+ if (node->values["horizontal_align"] == "left")
+ alignH = GUI::Theme::kTextAlignLeft;
+ else if (node->values["horizontal_align"] == "right")
+ alignH = GUI::Theme::kTextAlignRight;
+ else if (node->values["horizontal_align"] == "center")
+ alignH = GUI::Theme::kTextAlignCenter;
+ else return parserError("Invalid value for text alignment.");
+
+ if (node->values["vertical_align"] == "top")
+ alignV = GUI::Theme::kTextAlignVTop;
+ else if (node->values["vertical_align"] == "center")
+ alignV = GUI::Theme::kTextAlignVCenter;
+ else if (node->values["vertical_align"] == "bottom")
+ alignV = GUI::Theme::kTextAlignVBottom;
+ else return parserError("Invalid value for text alignment.");
+
+ if (!_theme->addTextData(getParentNode(node)->values["id"], node->values["font"], alignH, alignV))
+ return parserError("Error when adding Text Data for '%s'.", getParentNode(node)->values["id"].c_str());
+
+ return true;
+}
+
+bool ThemeParser::parserCallback_render_info(ParserNode *node) {
+ if (resolutionCheck(node->values["resolution"]) == false)
+ node->ignore = true;
+
+ return true;
+}
+
+bool ThemeParser::parserCallback_layout_info(ParserNode *node) {
+ if (resolutionCheck(node->values["resolution"]) == false)
+ node->ignore = true;
+
+ return true;
+}
+
+bool ThemeParser::parserCallback_palette(ParserNode *node) {
+ return true;
+}
+
+bool ThemeParser::parserCallback_color(ParserNode *node) {
+ Common::String name = node->values["name"];
+
+ if (_palette.contains(name))
+ return parserError("Color '%s' has already been defined.", name.c_str());
+
+ int red, green, blue;
+
+ if (parseIntegerKey(node->values["rgb"].c_str(), 3, &red, &green, &blue) == false ||
+ red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255)
+ return parserError("Error when parsing RGB values for palette color '%s'", name.c_str());\
+
+ _palette[name].r = red;
+ _palette[name].g = green;
+ _palette[name].b = blue;
+
+ return true;
+}
+
+
+bool ThemeParser::parserCallback_drawstep(ParserNode *node) {
+ Graphics::DrawStep *drawstep = newDrawStep();
+
+ Common::String functionName = node->values["func"];
+
+ if (_drawFunctions.contains(functionName) == false)
+ return parserError("%s is not a valid drawing function name", functionName.c_str());
+
+ drawstep->drawingCall = _drawFunctions[functionName];
+
+ if (!parseDrawStep(node, drawstep, true))
+ return false;
+
+ _theme->addDrawStep(getParentNode(node)->values["id"], *drawstep);
+ delete drawstep;
+
+ return true;
+}
+
+bool ThemeParser::parserCallback_drawdata(ParserNode *node) {
+ bool cached = false;
+
+ if (resolutionCheck(node->values["resolution"]) == false) {
+ node->ignore = true;
+ return true;
+ }
+
+ if (node->values.contains("cache")) {
+ if (node->values["cache"] == "true")
+ cached = true;
+ else if (node->values["cache"] == "false")
+ cached = false;
+ else return parserError("'Parsed' value must be either true or false.");
+ }
+
+ if (_theme->addDrawData(node->values["id"], cached) == false)
+ return parserError("Error when adding Draw Data set: Invalid DrawData name.");
+
+ if (_defaultStepLocal) {
+ delete _defaultStepLocal;
+ _defaultStepLocal = 0;
+ }
+
+ return true;
+}
+
+bool ThemeParser::parseDrawStep(ParserNode *stepNode, Graphics::DrawStep *drawstep, bool functionSpecific) {
+ int red, green, blue, x;
+ Common::String val;
+
+/**
+ * Helper macro to sanitize and assign an integer value from a key
+ * to the draw step.
+ *
+ * @param struct_name Name of the field of a DrawStep struct that must be
+ * assigned.
+ * @param key_name Name as STRING of the key identifier as it appears in the
+ * theme description format.
+ * @param force Sets if the key is optional or necessary.
+ */
+#define __PARSER_ASSIGN_INT(struct_name, key_name, force) \
+ if (stepNode->values.contains(key_name)) { \
+ if (!parseIntegerKey(stepNode->values[key_name].c_str(), 1, &x)) \
+ return parserError("Error when parsing key value for '%s'.", key_name); \
+ \
+ drawstep->struct_name = x; \
+ } else if (force) { \
+ return parserError("Missing necessary key '%s'.", key_name); \
+ }
+
+/**
+ * Helper macro to sanitize and assign a RGB value from a key to the draw
+ * step. RGB values have the following syntax: "R, G, B".
+ *
+ * @param struct_name Name of the field of a DrawStep struct that must be
+ * assigned.
+ * @param key_name Name as STRING of the key identifier as it appears in the
+ * theme description format.
+ */
+#define __PARSER_ASSIGN_RGB(struct_name, key_name) \
+ if (stepNode->values.contains(key_name)) { \
+ val = stepNode->values[key_name]; \
+ if (_palette.contains(val)) { \
+ red = _palette[val].r; \
+ green = _palette[val].g; \
+ blue = _palette[val].b; \
+ } else if (parseIntegerKey(val.c_str(), 3, &red, &green, &blue) == false || \
+ red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255) \
+ return parserError("Error when parsing color struct '%s'", val.c_str());\
+ \
+ drawstep->struct_name.r = red; \
+ drawstep->struct_name.g = green; \
+ drawstep->struct_name.b = blue; \
+ drawstep->struct_name.set = true; \
+ }
+
+ __PARSER_ASSIGN_INT(stroke, "stroke", false);
+ __PARSER_ASSIGN_INT(bevel, "bevel", false);
+ __PARSER_ASSIGN_INT(shadow, "shadow", false);
+ __PARSER_ASSIGN_INT(factor, "gradient_factor", false);
+
+ __PARSER_ASSIGN_RGB(fgColor, "fg_color");
+ __PARSER_ASSIGN_RGB(bgColor, "bg_color");
+ __PARSER_ASSIGN_RGB(gradColor1, "gradient_start");
+ __PARSER_ASSIGN_RGB(gradColor2, "gradient_end");
+ __PARSER_ASSIGN_RGB(bevelColor, "bevel_color");
+
+ if (functionSpecific) {
+ assert(stepNode->values.contains("func"));
+ Common::String functionName = stepNode->values["func"];
+
+ if (functionName == "bitmap") {
+ if (!stepNode->values.contains("file"))
+ return parserError("Need to specify a filename for Bitmap blitting.");
+
+ drawstep->blitSrc = _theme->getBitmap(stepNode->values["file"]);
+
+ if (!drawstep->blitSrc)
+ return parserError("The given filename hasn't been loaded into the GUI.");
+ }
+
+ if (functionName == "roundedsq" || functionName == "circle" || functionName == "tab") {
+ if (stepNode->values.contains("radius") && stepNode->values["radius"] == "auto") {
+ drawstep->radius = 0xFF;
+ } else {
+ __PARSER_ASSIGN_INT(radius, "radius", true);
+ }
+ }
+
+ if (functionName == "triangle") {
+ drawstep->extraData = VectorRenderer::kTriangleUp;
+
+ if (stepNode->values.contains("orientation")) {
+ val = stepNode->values["orientation"];
+
+ if ( val == "top")
+ drawstep->extraData = VectorRenderer::kTriangleUp;
+ else if (val == "bottom")
+ drawstep->extraData = VectorRenderer::kTriangleDown;
+ else if (val == "left")
+ drawstep->extraData = VectorRenderer::kTriangleLeft;
+ else if (val == "right")
+ drawstep->extraData = VectorRenderer::kTriangleRight;
+ else
+ return parserError("'%s' is not a valid value for triangle orientation.", val.c_str());
+ }
+ }
+
+ if (stepNode->values.contains("size")) {
+ warning("The <size> keyword has been deprecated. Use <width> and <height> instead");
+ }
+
+ if (stepNode->values.contains("width") && stepNode->values["width"] != "auto") {
+ drawstep->autoWidth = false;
+
+ val = stepNode->values["width"];
+ if (parseIntegerKey(val.c_str(), 1, &x))
+ drawstep->w = x;
+ else if (val == "height")
+ drawstep->w = -1;
+ else return parserError("Invalid value for vector width.");
+
+ if (stepNode->values.contains("xpos")) {
+ val = stepNode->values["xpos"];
+
+ if (parseIntegerKey(val.c_str(), 1, &x))
+ drawstep->x = x;
+ else if (val == "center")
+ drawstep->xAlign = Graphics::DrawStep::kVectorAlignCenter;
+ else if (val == "left")
+ drawstep->xAlign = Graphics::DrawStep::kVectorAlignLeft;
+ else if (val == "right")
+ drawstep->xAlign = Graphics::DrawStep::kVectorAlignRight;
+ else
+ return parserError("Invalid value for X Position");
+ } else {
+ return parserError("When width is not set to 'auto', a <xpos> tag must be included.");
+ }
+ }
+
+ if (stepNode->values.contains("height") && stepNode->values["height"] != "auto") {
+ drawstep->autoHeight = false;
+
+ val = stepNode->values["height"];
+ if (parseIntegerKey(val.c_str(), 1, &x))
+ drawstep->h = x;
+ else if (val == "width")
+ drawstep->h = -1;
+ else return parserError("Invalid value for vector height.");
+
+ if (stepNode->values.contains("ypos")) {
+ val = stepNode->values["ypos"];
+
+ if (parseIntegerKey(val.c_str(), 1, &x))
+ drawstep->y = x;
+ else if (val == "center")
+ drawstep->yAlign = Graphics::DrawStep::kVectorAlignCenter;
+ else if (val == "top")
+ drawstep->yAlign = Graphics::DrawStep::kVectorAlignTop;
+ else if (val == "bottom")
+ drawstep->yAlign = Graphics::DrawStep::kVectorAlignBottom;
+ else
+ return parserError("Invalid value for Y Position");
+ } else {
+ return parserError("When height is not set to 'auto', a <ypos> tag must be included.");
+ }
+ }
+
+ if (drawstep->h == -1 && drawstep->w == -1)
+ return parserError("Cross-reference in Vector Size: Height is set to width and width is set to height.");
+ }
+
+ if (stepNode->values.contains("fill")) {
+ val = stepNode->values["fill"];
+ if (val == "none")
+ drawstep->fillMode = VectorRenderer::kFillDisabled;
+ else if (val == "foreground")
+ drawstep->fillMode = VectorRenderer::kFillForeground;
+ else if (val == "background")
+ drawstep->fillMode = VectorRenderer::kFillBackground;
+ else if (val == "gradient")
+ drawstep->fillMode = VectorRenderer::kFillGradient;
+ else
+ return parserError("'%s' is not a valid fill mode for a shape.", stepNode->values["fill"].c_str());
+ }
+
+#undef __PARSER_ASSIGN_INT
+#undef __PARSER_ASSIGN_RGB
+
+ return true;
+}
+
+bool ThemeParser::parserCallback_def(ParserNode *node) {
+ if (resolutionCheck(node->values["resolution"]) == false) {
+ node->ignore = true;
+ return true;
+ }
+
+ Common::String var = "Globals." + node->values["var"];
+ int value;
+
+ if (_theme->themeEval()->hasVar(node->values["value"]) == true)
+ value = _theme->themeEval()->getVar(node->values["value"]);
+
+ else if (!parseIntegerKey(node->values["value"].c_str(), 1, &value))
+ return parserError("Invalid definition for '%s'.", var.c_str());
+
+ _theme->themeEval()->setVar(var, value);
+ return true;
+}
+
+bool ThemeParser::parserCallback_widget(ParserNode *node) {
+ Common::String var;
+
+ if (getParentNode(node)->name == "globals") {
+
+ if (resolutionCheck(node->values["resolution"]) == false) {
+ node->ignore = true;
+ return true;
+ }
+
+ var = "Globals." + node->values["name"] + ".";
+ if (!parseCommonLayoutProps(node, var))
+ return parserError("Error when parsing Layout properties of '%s'.", var.c_str());
+
+ } else {
+ var = node->values["name"];
+ int width = -1;
+ int height = -1;
+ bool enabled = true;
+
+ if (node->values.contains("enabled")) {
+ if (node->values["enabled"] == "false")
+ enabled = false;
+ else if (node->values["enabled"] != "true")
+ return parserError("Invalid value for Widget enabling (expecting true/false)");
+ }
+
+ if (node->values.contains("width")) {
+ if (_theme->themeEval()->hasVar(node->values["width"]) == true)
+ width = _theme->themeEval()->getVar(node->values["width"]);
+
+ else if (!parseIntegerKey(node->values["width"].c_str(), 1, &width))
+ return parserError("Corrupted width value in key for %s", var.c_str());
+ }
+
+ if (node->values.contains("height")) {
+ if (_theme->themeEval()->hasVar(node->values["height"]) == true)
+ height = _theme->themeEval()->getVar(node->values["height"]);
+
+ else if (!parseIntegerKey(node->values["height"].c_str(), 1, &height))
+ return parserError("Corrupted height value in key for %s", var.c_str());
+ }
+
+ _theme->themeEval()->addWidget(var, width, height, node->values["type"], enabled);
+ }
+
+ return true;
+}
+
+bool ThemeParser::parserCallback_dialog(ParserNode *node) {
+ Common::String var = "Dialog." + node->values["name"];
+ bool enabled = true;
+ int inset = 0;
+
+ if (resolutionCheck(node->values["resolution"]) == false) {
+ node->ignore = true;
+ return true;
+ }
+
+ if (node->values.contains("enabled")) {
+ if (node->values["enabled"] == "false")
+ enabled = false;
+ else if (node->values["enabled"] != "true")
+ return parserError("Invalid value for Dialog enabling (expecting true/false)");
+ }
+
+ if (node->values.contains("inset")) {
+ if (!parseIntegerKey(node->values["inset"].c_str(), 1, &inset))
+ return false;
+ }
+
+ _theme->themeEval()->addDialog(var, node->values["overlays"], enabled, inset);
+
+ if (node->values.contains("shading")) {
+ int shading = 0;
+ if (node->values["shading"] == "dim")
+ shading = 1;
+ else if (node->values["shading"] == "luminance")
+ shading = 2;
+ else return parserError("Invalid value for Dialog background shading.");
+
+ _theme->themeEval()->setVar(var + ".Shading", shading);
+ }
+
+ return true;
+}
+
+bool ThemeParser::parserCallback_import(ParserNode *node) {
+
+ if (!_theme->themeEval()->addImportedLayout(node->values["layout"]))
+ return parserError("Error when importing external layout");
+ return true;
+}
+
+bool ThemeParser::parserCallback_layout(ParserNode *node) {
+ int spacing = -1;
+
+ if (node->values.contains("spacing")) {
+ if (!parseIntegerKey(node->values["spacing"].c_str(), 1, &spacing))
+ return false;
+ }
+
+ if (node->values["type"] == "vertical")
+ _theme->themeEval()->addLayout(GUI::ThemeLayout::kLayoutVertical, spacing, node->values["center"] == "true");
+
+ else if (node->values["type"] == "horizontal")
+ _theme->themeEval()->addLayout(GUI::ThemeLayout::kLayoutHorizontal, spacing, node->values["center"] == "true");
+
+ if (node->values.contains("padding")) {
+ int paddingL, paddingR, paddingT, paddingB;
+
+ if (!parseIntegerKey(node->values["padding"].c_str(), 4, &paddingL, &paddingR, &paddingT, &paddingB))
+ return false;
+
+ _theme->themeEval()->addPadding(paddingL, paddingR, paddingT, paddingB);
+ }
+
+ return true;
+}
+
+bool ThemeParser::parserCallback_space(ParserNode *node) {
+ int size = -1;
+
+ if (node->values.contains("size")) {
+ if (_theme->themeEval()->hasVar(node->values["size"]))
+ size = _theme->themeEval()->getVar(node->values["size"]);
+
+ else if (!parseIntegerKey(node->values["size"].c_str(), 1, &size))
+ return parserError("Invalid value for Spacing size.");
+ }
+
+ _theme->themeEval()->addSpace(size);
+ return true;
+}
+
+bool ThemeParser::closedKeyCallback(ParserNode *node) {
+ if (node->name == "layout")
+ _theme->themeEval()->closeLayout();
+ else if (node->name == "dialog")
+ _theme->themeEval()->closeDialog();
+
+ return true;
+}
+
+bool ThemeParser::parseCommonLayoutProps(ParserNode *node, const Common::String &var) {
+ if (node->values.contains("size")) {
+ int width, height;
+
+ if (!parseIntegerKey(node->values["size"].c_str(), 2, &width, &height)) {
+ Common::StringTokenizer tokenizer(node->values["size"], " ,");
+ Common::String wtoken, htoken;
+ char *parseEnd;
+
+ wtoken = tokenizer.nextToken();
+
+ if (_theme->themeEval()->hasVar(wtoken)) {
+ width = _theme->themeEval()->getVar(wtoken);
+ } else {
+ width = strtol(wtoken.c_str(), &parseEnd, 10);
+
+ if (*parseEnd != 0 && !(*parseEnd == '%' && *(parseEnd + 1) == 0))
+ return false;
+
+ if (wtoken.lastChar() == '%')
+ width = g_system->getOverlayWidth() * width / 100;
+ }
+
+ htoken = tokenizer.nextToken();
+
+ if (_theme->themeEval()->hasVar(htoken)) {
+ height = _theme->themeEval()->getVar(htoken);
+ } else {
+ height = strtol(htoken.c_str(), &parseEnd, 10);
+
+ if (*parseEnd != 0 && !(*parseEnd == '%' && *(parseEnd + 1) == 0))
+ return false;
+
+ if (htoken.lastChar() == '%')
+ height = g_system->getOverlayHeight() * height / 100;
+ }
+
+ if (!tokenizer.empty())
+ return false;
+ }
+
+
+ _theme->themeEval()->setVar(var + "Width", width);
+ _theme->themeEval()->setVar(var + "Height", height);
+ }
+
+ if (node->values.contains("pos")) {
+ int x, y;
+
+ if (!parseIntegerKey(node->values["pos"].c_str(), 2, &x, &y)) {
+ Common::StringTokenizer tokenizer(node->values["pos"], " ,");
+ Common::String xpos, ypos;
+ char *parseEnd;
+
+ xpos = tokenizer.nextToken();
+
+ if (xpos == "center") {
+ if (!_theme->themeEval()->hasVar(var + "Width"))
+ return false;
+
+ x = (g_system->getOverlayWidth() / 2) - (_theme->themeEval()->getVar(var + "Width") / 2);
+
+ } else if (_theme->themeEval()->hasVar(xpos)) {
+ x = _theme->themeEval()->getVar(xpos);
+ } else {
+ x = strtol(xpos.c_str(), &parseEnd, 10);
+
+ if (*parseEnd != 0 && !(*parseEnd == 'r' && *(parseEnd + 1) == 0))
+ return false;
+
+ if (xpos.lastChar() == 'r')
+ x = g_system->getOverlayWidth() - x;
+ }
+
+ ypos = tokenizer.nextToken();
+
+ if (ypos == "center") {
+ if (!_theme->themeEval()->hasVar(var + "Height"))
+ return false;
+
+ y = (g_system->getOverlayHeight() / 2) - (_theme->themeEval()->getVar(var + "Height") / 2);
+
+ } else if (_theme->themeEval()->hasVar(ypos)) {
+ y = _theme->themeEval()->getVar(ypos);
+ } else {
+ y = strtol(ypos.c_str(), &parseEnd, 10);
+
+ if (*parseEnd != 0 && !(*parseEnd == 'b' && *(parseEnd + 1) == 0))
+ return false;
+
+ if (ypos.lastChar() == 'b')
+ y = g_system->getOverlayHeight() - y;
+ }
+
+ if (!tokenizer.empty())
+ return false;
+ }
+
+ _theme->themeEval()->setVar(var + "X", x);
+ _theme->themeEval()->setVar(var + "Y", y);
+ }
+
+ if (node->values.contains("padding")) {
+ int paddingL, paddingR, paddingT, paddingB;
+
+ if (!parseIntegerKey(node->values["padding"].c_str(), 4, &paddingL, &paddingR, &paddingT, &paddingB))
+ return false;
+
+ _theme->themeEval()->setVar(var + "Padding.Left", paddingL);
+ _theme->themeEval()->setVar(var + "Padding.Right", paddingR);
+ _theme->themeEval()->setVar(var + "Padding.Top", paddingT);
+ _theme->themeEval()->setVar(var + "Padding.Bottom", paddingB);
+ }
+
+ return true;
+}
+
+bool ThemeParser::resolutionCheck(const Common::String &resolution) {
+ if (resolution.empty())
+ return true;
+
+ Common::StringTokenizer globTokenizer(resolution, ", ");
+ Common::String cur, w, h;
+ bool definedRes = false;
+
+ while (!globTokenizer.empty()) {
+ bool ignore = false;
+ cur = globTokenizer.nextToken();
+
+ if (cur[0] == '-') {
+ ignore = true;
+ cur.deleteChar(0);
+ } else {
+ definedRes = true;
+ }
+
+ Common::StringTokenizer resTokenizer(cur, "x");
+ w = resTokenizer.nextToken();
+ h = resTokenizer.nextToken();
+
+ if ((w == "X" || atoi(w.c_str()) == g_system->getOverlayWidth()) &&
+ (h == "Y" || atoi(h.c_str()) == g_system->getOverlayHeight()))
+ return !ignore;
+ }
+
+ return !definedRes;
+}
+
+}
diff --git a/gui/ThemeParser.h b/gui/ThemeParser.h
new file mode 100644
index 0000000000..67da93ff6c
--- /dev/null
+++ b/gui/ThemeParser.h
@@ -0,0 +1,278 @@
+/* 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 THEME_PARSER_H
+#define THEME_PARSER_H
+
+#include "common/scummsys.h"
+#include "graphics/surface.h"
+#include "common/system.h"
+
+#include "common/hashmap.h"
+#include "common/hash-str.h"
+#include "common/stack.h"
+#include "common/xmlparser.h"
+
+#include "graphics/VectorRenderer.h"
+#include "gui/ThemeEngine.h"
+
+namespace GUI {
+
+using namespace Graphics;
+using namespace Common;
+class ThemeEngine;
+
+class ThemeParser : public XMLParser {
+ typedef void (VectorRenderer::*DrawingFunctionCallback)(const Common::Rect &, const DrawStep &);
+
+public:
+ ThemeParser(GUI::ThemeEngine *parent);
+
+ virtual ~ThemeParser() {
+ delete _defaultStepGlobal;
+ delete _defaultStepLocal;
+ _palette.clear();
+ _drawFunctions.clear();
+ }
+
+ bool getPaletteColor(const Common::String &name, int &r, int &g, int &b) {
+ if (!_palette.contains(name))
+ return false;
+
+ r = _palette[name].r;
+ g = _palette[name].g;
+ b = _palette[name].b;
+
+ return true;
+ }
+
+protected:
+ ThemeEngine *_theme;
+
+ CUSTOM_XML_PARSER(ThemeParser) {
+ XML_KEY(render_info)
+ XML_PROP(resolution, false)
+ XML_KEY(palette)
+ XML_KEY(color)
+ XML_PROP(name, true)
+ XML_PROP(rgb, true)
+ KEY_END()
+ KEY_END()
+
+ XML_KEY(fonts)
+ XML_KEY(font)
+ XML_PROP(id, true)
+ XML_PROP(file, true)
+ XML_PROP(color, true)
+ XML_PROP(resolution, false)
+ KEY_END()
+ KEY_END()
+
+ XML_KEY(bitmaps)
+ XML_KEY(bitmap)
+ XML_PROP(filename, true)
+ XML_PROP(resolution, false)
+ KEY_END()
+ KEY_END()
+
+ XML_KEY(cursor)
+ XML_PROP(file, true)
+ XML_PROP(hotspot, true)
+ XML_PROP(scale, true)
+ XML_PROP(resolution, false)
+ KEY_END()
+
+ XML_KEY(defaults)
+ XML_PROP(stroke, false)
+ XML_PROP(shadow, false)
+ XML_PROP(bevel, false)
+ XML_PROP(factor, false)
+ XML_PROP(fg_color, false)
+ XML_PROP(bg_color, false)
+ XML_PROP(gradient_start, false)
+ XML_PROP(gradient_end, false)
+ XML_PROP(bevel_color, false)
+ XML_PROP(gradient_factor, false)
+ XML_PROP(fill, false)
+ KEY_END()
+
+ XML_KEY(drawdata)
+ XML_PROP(id, true)
+ XML_PROP(cache, false)
+ XML_PROP(resolution, false)
+
+ XML_KEY(defaults)
+ XML_PROP(stroke, false)
+ XML_PROP(shadow, false)
+ XML_PROP(bevel, false)
+ XML_PROP(factor, false)
+ XML_PROP(fg_color, false)
+ XML_PROP(bg_color, false)
+ XML_PROP(gradient_start, false)
+ XML_PROP(gradient_end, false)
+ XML_PROP(bevel_color, false)
+ XML_PROP(gradient_factor, false)
+ XML_PROP(fill, false)
+ KEY_END()
+
+ XML_KEY(drawstep)
+ XML_PROP(func, true)
+ XML_PROP(stroke, false)
+ XML_PROP(shadow, false)
+ XML_PROP(bevel, false)
+ XML_PROP(factor, false)
+ XML_PROP(fg_color, false)
+ XML_PROP(bg_color, false)
+ XML_PROP(gradient_start, false)
+ XML_PROP(gradient_end, false)
+ XML_PROP(gradient_factor, false)
+ XML_PROP(bevel_color, false)
+ XML_PROP(fill, false)
+ XML_PROP(radius, false)
+ XML_PROP(width, false)
+ XML_PROP(height, false)
+ XML_PROP(xpos, false)
+ XML_PROP(ypos, false)
+ XML_PROP(orientation, false)
+ XML_PROP(file, false)
+ KEY_END()
+
+ XML_KEY(text)
+ XML_PROP(font, true)
+ XML_PROP(vertical_align, true)
+ XML_PROP(horizontal_align, true)
+ KEY_END()
+ KEY_END()
+
+ KEY_END() // render_info end
+
+ XML_KEY(layout_info)
+ XML_PROP(resolution, false)
+ XML_KEY(globals)
+ XML_PROP(resolution, false)
+ XML_KEY(def)
+ XML_PROP(var, true)
+ XML_PROP(value, true)
+ XML_PROP(resolution, false)
+ KEY_END()
+
+ XML_KEY(widget)
+ XML_PROP(name, true)
+ XML_PROP(size, false)
+ XML_PROP(pos, false)
+ XML_PROP(padding, false)
+ XML_PROP(resolution, false)
+ KEY_END()
+ KEY_END()
+
+ XML_KEY(dialog)
+ XML_PROP(name, true)
+ XML_PROP(overlays, true)
+ XML_PROP(shading, false)
+ XML_PROP(enabled, false)
+ XML_PROP(resolution, false)
+ XML_PROP(inset, false)
+ XML_KEY(layout)
+ XML_PROP(type, true)
+ XML_PROP(center, false)
+ XML_PROP(padding, false)
+ XML_PROP(spacing, false)
+
+ XML_KEY(import)
+ XML_PROP(layout, true)
+ KEY_END()
+
+ XML_KEY(widget)
+ XML_PROP(name, true)
+ XML_PROP(width, false)
+ XML_PROP(height, false)
+ XML_PROP(type, false)
+ XML_PROP(enabled, false)
+ KEY_END()
+
+ XML_KEY(space)
+ XML_PROP(size, false)
+ KEY_END()
+
+ XML_KEY_RECURSIVE(layout)
+ KEY_END()
+ KEY_END()
+ KEY_END()
+
+ } PARSER_END();
+
+ /** Render info callbacks */
+ bool parserCallback_render_info(ParserNode *node);
+ bool parserCallback_defaults(ParserNode *node);
+ bool parserCallback_font(ParserNode *node);
+ bool parserCallback_fonts(ParserNode *node);
+ bool parserCallback_text(ParserNode *node);
+ bool parserCallback_palette(ParserNode *node);
+ bool parserCallback_color(ParserNode *node);
+ bool parserCallback_drawstep(ParserNode *node);
+ bool parserCallback_drawdata(ParserNode *node);
+ bool parserCallback_bitmaps(ParserNode *node) { return true; }
+ bool parserCallback_bitmap(ParserNode *node);
+ bool parserCallback_cursor(ParserNode *node);
+
+
+ /** Layout info callbacks */
+ bool parserCallback_layout_info(ParserNode *node);
+ bool parserCallback_globals(ParserNode *node) { return true; }
+ bool parserCallback_def(ParserNode *node);
+ bool parserCallback_widget(ParserNode *node);
+ bool parserCallback_dialog(ParserNode *node);
+ bool parserCallback_layout(ParserNode *node);
+ bool parserCallback_space(ParserNode *node);
+ bool parserCallback_import(ParserNode *node);
+
+ bool closedKeyCallback(ParserNode *node);
+
+ bool resolutionCheck(const Common::String &resolution);
+
+ void cleanup();
+
+ Graphics::DrawStep *newDrawStep();
+ Graphics::DrawStep *defaultDrawStep();
+ bool parseDrawStep(ParserNode *stepNode, Graphics::DrawStep *drawstep, bool functionSpecific);
+ bool parseCommonLayoutProps(ParserNode *node, const Common::String &var);
+
+ Graphics::DrawStep *_defaultStepGlobal;
+ Graphics::DrawStep *_defaultStepLocal;
+
+ Common::HashMap<Common::String, DrawingFunctionCallback, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _drawFunctions;
+
+ struct PaletteColor {
+ uint8 r, g, b;
+ };
+
+ Common::HashMap<Common::String, PaletteColor, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _palette;
+};
+
+
+
+}
+
+#endif
diff --git a/gui/about.cpp b/gui/about.cpp
index 99469b9ae4..1c1e3a3355 100644
--- a/gui/about.cpp
+++ b/gui/about.cpp
@@ -29,10 +29,11 @@
#include "common/system.h"
#include "common/util.h"
#include "gui/about.h"
-#include "gui/eval.h"
#include "gui/newgui.h"
#include "gui/widget.h"
+#include "gui/ThemeEval.h"
+
namespace GUI {
enum {
@@ -85,9 +86,9 @@ AboutDialog::AboutDialog()
const int screenW = g_system->getOverlayWidth();
const int screenH = g_system->getOverlayHeight();
- _xOff = g_gui.evaluator()->getVar("aboutXOff");
- _yOff = g_gui.evaluator()->getVar("aboutYOff");
- int outerBorder = g_gui.evaluator()->getVar("aboutOuterBorder");
+ _xOff = g_gui.xmlEval()->getVar("Globals.About.XOffset", 5);
+ _yOff = g_gui.xmlEval()->getVar("Globals.About.YOffset", 5);
+ int outerBorder = g_gui.xmlEval()->getVar("Globals.About.OuterBorder");
_w = screenW - 2 * outerBorder;
_h = screenH - 2 * outerBorder;
@@ -203,7 +204,7 @@ void AboutDialog::close() {
}
void AboutDialog::drawDialog() {
- g_gui.theme()->setDrawArea(Common::Rect(_x, _y, _x+_w, _y+_h));
+// g_gui.theme()->setDrawArea(Common::Rect(_x, _y, _x+_w, _y+_h));
Dialog::drawDialog();
// Draw text
@@ -265,10 +266,10 @@ void AboutDialog::drawDialog() {
while (*str && *str == ' ')
str++;
- g_gui.theme()->drawText(Common::Rect(_x + _xOff, y, _x + _w - _xOff, y + g_gui.theme()->getFontHeight()), str, state, align, false, 0, false);
+ if (y > _y && y + g_gui.theme()->getFontHeight() < _y + _h)
+ g_gui.theme()->drawText(Common::Rect(_x + _xOff, y, _x + _w - _xOff, y + g_gui.theme()->getFontHeight()), str, state, align, false, 0, false);
y += _lineHeight;
}
- g_gui.theme()->resetDrawArea();
}
void AboutDialog::handleTickle() {
@@ -316,9 +317,9 @@ void AboutDialog::reflowLayout() {
const int screenW = g_system->getOverlayWidth();
const int screenH = g_system->getOverlayHeight();
- _xOff = g_gui.evaluator()->getVar("aboutXOff");
- _yOff = g_gui.evaluator()->getVar("aboutYOff");
- int outerBorder = g_gui.evaluator()->getVar("aboutOuterBorder");
+ _xOff = g_gui.xmlEval()->getVar("Globals.About.XOffset", 5);
+ _yOff = g_gui.xmlEval()->getVar("Globals.About.YOffset", 5);
+ int outerBorder = g_gui.xmlEval()->getVar("Globals.About.OuterBorder");
_w = screenW - 2 * outerBorder;
_h = screenH - 2 * outerBorder;
diff --git a/gui/browser.cpp b/gui/browser.cpp
index e417a03688..36969d9c54 100644
--- a/gui/browser.cpp
+++ b/gui/browser.cpp
@@ -133,29 +133,29 @@ int BrowserDialog::runModal() {
*/
BrowserDialog::BrowserDialog(const char *title, bool dirBrowser)
- : Dialog("browser") {
+ : Dialog("Browser") {
_isDirBrowser = dirBrowser;
_fileList = NULL;
_currentPath = NULL;
// Headline - TODO: should be customizable during creation time
- new StaticTextWidget(this, "browser_headline", title);
+ new StaticTextWidget(this, "Browser.Headline", title);
// Current path - TODO: handle long paths ?
- _currentPath = new StaticTextWidget(this, "browser_path", "DUMMY");
+ _currentPath = new StaticTextWidget(this, "Browser.Path", "DUMMY");
// Add file list
- _fileList = new ListWidget(this, "browser_list");
+ _fileList = new ListWidget(this, "Browser.List");
_fileList->setNumberingMode(kListNumberingOff);
_fileList->setEditable(false);
- _fileList->setHints(THEME_HINT_PLAIN_COLOR);
+ _backgroundType = GUI::Theme::kDialogBackgroundPlain;
// Buttons
- new ButtonWidget(this, "browser_up", "Go up", kGoUpCmd, 0);
- new ButtonWidget(this, "browser_cancel", "Cancel", kCloseCmd, 0);
- new ButtonWidget(this, "browser_choose", "Choose", kChooseCmd, 0);
+ new ButtonWidget(this, "Browser.Up", "Go up", kGoUpCmd, 0);
+ new ButtonWidget(this, "Browser.Cancel", "Cancel", kCloseCmd, 0);
+ new ButtonWidget(this, "Browser.Choose", "Choose", kChooseCmd, 0);
}
void BrowserDialog::open() {
diff --git a/gui/console.cpp b/gui/console.cpp
index 728724d76f..58c7404a19 100644
--- a/gui/console.cpp
+++ b/gui/console.cpp
@@ -24,7 +24,7 @@
#include "gui/console.h"
#include "gui/ScrollBarWidget.h"
-#include "gui/eval.h"
+#include "gui/ThemeEval.h"
#include "engines/engine.h"
#include "base/version.h"
@@ -97,17 +97,14 @@ ConsoleDialog::ConsoleDialog(float widthPercent, float heightPercent)
void ConsoleDialog::init() {
const int screenW = g_system->getOverlayWidth();
const int screenH = g_system->getOverlayHeight();
- int f = g_gui.evaluator()->getVar("Console.font");
- if (f == EVAL_UNDEF_VAR)
- _font = FontMan.getFontByUsage(Graphics::FontManager::kConsoleFont);
- else
- _font = g_gui.theme()->getFont((Theme::FontStyle)f);
+ _font = FontMan.getFontByUsage((Graphics::FontManager::FontUsage)
+ g_gui.xmlEval()->getVar("Console.Font", Graphics::FontManager::kConsoleFont));
- _leftPadding = g_gui.evaluator()->getVar("Console.leftPadding", 0);
- _rightPadding = g_gui.evaluator()->getVar("Console.rightPadding", 0);
- _topPadding = g_gui.evaluator()->getVar("Console.topPadding", 0);
- _bottomPadding = g_gui.evaluator()->getVar("Console.bottomPadding", 0);
+ _leftPadding = g_gui.xmlEval()->getVar("Globals.Console.Padding.Left", 0);
+ _rightPadding = g_gui.xmlEval()->getVar("Globals.Console.Padding.Right", 0);
+ _topPadding = g_gui.xmlEval()->getVar("Globals.Console.Padding.Top", 0);
+ _bottomPadding = g_gui.xmlEval()->getVar("Globals.Console.Padding.Bottom", 0);
// Calculate the real width/height (rounded to char/line multiples)
_w = (uint16)(_widthPercent * screenW);
@@ -122,8 +119,6 @@ void ConsoleDialog::init() {
scrollBarWidth = kNormalScrollBarWidth;
_scrollBar->resize(_w - scrollBarWidth - 1, 0, scrollBarWidth, _h);
- _drawingHints = THEME_HINT_FIRST_DRAW | THEME_HINT_SAVE_BACKGROUND;
-
_pageWidth = (_w - scrollBarWidth - 2 - _leftPadding - _topPadding - scrollBarWidth) / kConsoleCharWidth;
_linesPerPage = (_h - 2 - _topPadding - _bottomPadding) / kConsoleLineHeight;
_linesInBuffer = kBufferSize / kCharsPerLine;
@@ -154,8 +149,6 @@ void ConsoleDialog::open() {
if (_w != w || _h != h)
init();
- _drawingHints |= THEME_HINT_FIRST_DRAW | THEME_HINT_SAVE_BACKGROUND;
-
_y = -_h;
_slideTime = g_system->getMillis();
_slideMode = kDownSlideMode;
@@ -172,7 +165,7 @@ void ConsoleDialog::close() {
}
void ConsoleDialog::drawDialog() {
- g_gui.theme()->drawDialogBackground(Common::Rect(_x, _y, _x+_w, _y+_h), _drawingHints);
+ g_gui.theme()->drawDialogBackground(Common::Rect(_x, _y, _x+_w, _y+_h), _backgroundType);
// FIXME: for the old theme the frame around the console vanishes
// when any action is processed if we enable this
// _drawingHints &= ~THEME_HINT_FIRST_DRAW;
@@ -231,7 +224,6 @@ void ConsoleDialog::handleTickle() {
// Perform the "slide animation".
if (_slideMode != kNoSlideMode) {
- _drawingHints = THEME_HINT_FIRST_DRAW | THEME_HINT_SAVE_BACKGROUND;
const float tmp = (float)(g_system->getMillis() - _slideTime) / kConsoleSlideDownDuration;
if (_slideMode == kUpSlideMode) {
_y = (int)(_h * (0.0 - tmp));
diff --git a/gui/dialog.cpp b/gui/dialog.cpp
index ef396301be..3b302ff36a 100644
--- a/gui/dialog.cpp
+++ b/gui/dialog.cpp
@@ -42,18 +42,15 @@ namespace GUI {
* ...
*/
-Dialog::Dialog(int x, int y, int w, int h, bool dimsInactive_)
+Dialog::Dialog(int x, int y, int w, int h)
: GuiObject(x, y, w, h),
- _mouseWidget(0), _focusedWidget(0), _dragWidget(0), _visible(false), _drawingHints(0),
- _dimsInactive(dimsInactive_) {
- _drawingHints = THEME_HINT_FIRST_DRAW | THEME_HINT_SAVE_BACKGROUND;
-}
+ _mouseWidget(0), _focusedWidget(0), _dragWidget(0), _visible(false),
+ _backgroundType(GUI::Theme::kDialogBackgroundDefault) {}
-Dialog::Dialog(const Common::String &name, bool dimsInactive_)
+Dialog::Dialog(const Common::String &name)
: GuiObject(name),
- _mouseWidget(0), _focusedWidget(0), _dragWidget(0), _visible(false), _drawingHints(0),
- _dimsInactive(dimsInactive_) {
- _drawingHints = THEME_HINT_FIRST_DRAW | THEME_HINT_SAVE_BACKGROUND;
+ _mouseWidget(0), _focusedWidget(0), _dragWidget(0), _visible(false),
+ _backgroundType(GUI::Theme::kDialogBackgroundDefault) {
// It may happen that we have 3x scaler in launcher (960xY) and then 640x480
// game will be forced to 1x. At this stage GUI will not be aware of
@@ -113,11 +110,9 @@ void Dialog::reflowLayout() {
// changed, so any cached image may be invalid. The subsequent redraw
// should be treated as the very first draw.
- _drawingHints |= THEME_HINT_FIRST_DRAW;
Widget *w = _firstWidget;
while (w) {
w->reflowLayout();
- w->setHints(THEME_HINT_FIRST_DRAW);
w = w->_next;
}
@@ -132,7 +127,11 @@ void Dialog::releaseFocus() {
}
void Dialog::draw() {
- g_gui._needRedraw = true;
+ //TANOKU - FIXME when is this enabled? what does this do?
+ // Update: called on tab drawing, mainly...
+ // we can pass this as open a new dialog or something
+// g_gui._needRedraw = true;
+ g_gui._redrawStatus = GUI::NewGui::kRedrawTopDialog;
}
void Dialog::drawDialog() {
@@ -140,12 +139,12 @@ void Dialog::drawDialog() {
if (!isVisible())
return;
- g_gui.theme()->drawDialogBackground(Common::Rect(_x, _y, _x+_w, _y+_h), _drawingHints);
- _drawingHints &= ~THEME_HINT_FIRST_DRAW;
+ g_gui.theme()->drawDialogBackground(Common::Rect(_x, _y, _x+_w, _y+_h), _backgroundType);
// Draw all children
Widget *w = _firstWidget;
while (w) {
+ //if (w->_debugVisible)
w->draw();
w = w->_next;
}
diff --git a/gui/dialog.h b/gui/dialog.h
index d17d3a5ad1..71edb63ee3 100644
--- a/gui/dialog.h
+++ b/gui/dialog.h
@@ -48,15 +48,15 @@ protected:
Widget *_focusedWidget;
Widget *_dragWidget;
bool _visible;
- uint16 _drawingHints;
+
+ Theme::DialogBackground _backgroundType;
private:
int _result;
- bool _dimsInactive;
public:
- Dialog(int x, int y, int w, int h, bool dimsInactive = true);
- Dialog(const Common::String &name, bool dimsInactive = true);
+ Dialog(int x, int y, int w, int h);
+ Dialog(const Common::String &name);
virtual int runModal();
@@ -90,9 +90,6 @@ protected:
void setResult(int result) { _result = result; }
int getResult() const { return _result; }
-
- // Whether dialog dims all underneath dialogs or not when active
- bool dimsInactive() { return _dimsInactive; }
};
} // End of namespace GUI
diff --git a/gui/launcher.cpp b/gui/launcher.cpp
index c4b0a9bd6a..08206c9aab 100644
--- a/gui/launcher.cpp
+++ b/gui/launcher.cpp
@@ -35,7 +35,6 @@
#include "gui/about.h"
#include "gui/browser.h"
#include "gui/chooser.h"
-#include "gui/eval.h"
#include "gui/launcher.h"
#include "gui/massadd.h"
#include "gui/message.h"
@@ -50,6 +49,7 @@
#include "sound/mididrv.h"
+#include "gui/ThemeEval.h"
using Common::ConfigManager;
@@ -148,9 +148,9 @@ protected:
};
EditGameDialog::EditGameDialog(const String &domain, const String &desc)
- : OptionsDialog(domain, "gameoptions") {
+ : OptionsDialog(domain, "GameOptions") {
- int labelWidth = g_gui.evaluator()->getVar("tabPopupsLabelW");
+ int labelWidth = g_gui.xmlEval()->getVar("Globals.TabLabelWidth");
// GAME: Path to game data (r/o), extra data (r/o), and save data (r/w)
String gamePath(ConfMan.get("path", _domain));
@@ -164,8 +164,7 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
}
// GUI: Add tab widget
- TabWidget *tab = new TabWidget(this, "gameoptions_tabwidget");
- tab->setHints(THEME_HINT_FIRST_DRAW | THEME_HINT_SAVE_BACKGROUND);
+ TabWidget *tab = new TabWidget(this, "GameOptions.TabWidget");
//
// 1) The game tab
@@ -173,15 +172,15 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
tab->addTab("Game");
// GUI: Label & edit widget for the game ID
- new StaticTextWidget(tab, "gameoptions_id", "ID:");
- _domainWidget = new DomainEditTextWidget(tab, "gameoptions_domain", _domain);
+ new StaticTextWidget(tab, "GameOptions_Game.Id", "ID:");
+ _domainWidget = new DomainEditTextWidget(tab, "GameOptions_Game.Domain", _domain);
// GUI: Label & edit widget for the description
- new StaticTextWidget(tab, "gameoptions_name", "Name:");
- _descriptionWidget = new EditTextWidget(tab, "gameoptions_desc", description);
+ new StaticTextWidget(tab, "GameOptions_Game.Name", "Name:");
+ _descriptionWidget = new EditTextWidget(tab, "GameOptions_Game.Desc", description);
// Language popup
- _langPopUp = new PopUpWidget(tab, "gameoptions_lang", "Language:", labelWidth);
+ _langPopUp = new PopUpWidget(tab, "GameOptions_Game.Lang", "Language:", labelWidth);
_langPopUp->appendEntry("<default>");
_langPopUp->appendEntry("");
const Common::LanguageDescription *l = Common::g_languages;
@@ -190,7 +189,7 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
}
// Platform popup
- _platformPopUp = new PopUpWidget(tab, "gameoptions_platform", "Platform:", labelWidth);
+ _platformPopUp = new PopUpWidget(tab, "GameOptions_Game.Platform", "Platform:", labelWidth);
_platformPopUp->appendEntry("<default>");
_platformPopUp->appendEntry("");
const Common::PlatformDescription *p = Common::g_platforms;
@@ -201,39 +200,39 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
//
// 3) The graphics tab
//
- tab->addTab("Graphics");
+ _graphicsTabId = tab->addTab(g_system->getOverlayWidth() > 320 ? "Graphics" : "GFX");
- _globalGraphicsOverride = new CheckboxWidget(tab, "gameoptions_graphicsCheckbox", "Override global graphic settings", kCmdGlobalGraphicsOverride, 0);
+ _globalGraphicsOverride = new CheckboxWidget(tab, "GameOptions_Graphics.EnableTabCheckbox", "Override global graphic settings", kCmdGlobalGraphicsOverride, 0);
- addGraphicControls(tab, "gameoptions_");
+ addGraphicControls(tab, "GameOptions_Graphics.");
//
// 4) The audio tab
//
tab->addTab("Audio");
- _globalAudioOverride = new CheckboxWidget(tab, "gameoptions_audioCheckbox", "Override global audio settings", kCmdGlobalAudioOverride, 0);
+ _globalAudioOverride = new CheckboxWidget(tab, "GameOptions_Audio.EnableTabCheckbox", "Override global audio settings", kCmdGlobalAudioOverride, 0);
- addAudioControls(tab, "gameoptions_");
- addSubtitleControls(tab, "gameoptions_");
+ addAudioControls(tab, "GameOptions_Audio.");
+ addSubtitleControls(tab, "GameOptions_Audio.");
//
// 5) The volume tab
//
tab->addTab("Volume");
- _globalVolumeOverride = new CheckboxWidget(tab, "gameoptions_volumeCheckbox", "Override global volume settings", kCmdGlobalVolumeOverride, 0);
+ _globalVolumeOverride = new CheckboxWidget(tab, "GameOptions_Volume.EnableTabCheckbox", "Override global volume settings", kCmdGlobalVolumeOverride, 0);
- addVolumeControls(tab, "gameoptions_");
+ addVolumeControls(tab, "GameOptions_Volume.");
//
// 6) The MIDI tab
//
tab->addTab("MIDI");
- _globalMIDIOverride = new CheckboxWidget(tab, "gameoptions_midiCheckbox", "Override global MIDI settings", kCmdGlobalMIDIOverride, 0);
+ _globalMIDIOverride = new CheckboxWidget(tab, "GameOptions_MIDI.EnableTabCheckbox", "Override global MIDI settings", kCmdGlobalMIDIOverride, 0);
- addMIDIControls(tab, "gameoptions_");
+ addMIDIControls(tab, "GameOptions_MIDI.");
//
// 2) The 'Path' tab
@@ -244,35 +243,36 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
// in the small version of the GUI.
// GUI: Button + Label for the game path
- new ButtonWidget(tab, "gameoptions_gamepath", "Game Path:", kCmdGameBrowser, 0);
- _gamePathWidget = new StaticTextWidget(tab, "gameoptions_gamepathText", gamePath);
+ new ButtonWidget(tab, "GameOptions_Paths.Gamepath", "Game Path:", kCmdGameBrowser, 0);
+ _gamePathWidget = new StaticTextWidget(tab, "GameOptions_Paths.GamepathText", gamePath);
// GUI: Button + Label for the additional path
- new ButtonWidget(tab, "gameoptions_extrapath", "Extra Path:", kCmdExtraBrowser, 0);
- _extraPathWidget = new StaticTextWidget(tab, "gameoptions_extrapathText", extraPath);
+ new ButtonWidget(tab, "GameOptions_Paths.Extrapath", "Extra Path:", kCmdExtraBrowser, 0);
+ _extraPathWidget = new StaticTextWidget(tab, "GameOptions_Paths.ExtrapathText", extraPath);
if (extraPath.empty() || !ConfMan.hasKey("extrapath", _domain)) {
_extraPathWidget->setLabel("None");
}
// GUI: Button + Label for the save path
- new ButtonWidget(tab, "gameoptions_savepath", "Save Path:", kCmdSaveBrowser, 0);
- _savePathWidget = new StaticTextWidget(tab, "gameoptions_savepathText", savePath);
+ new ButtonWidget(tab, "GameOptions_Paths.Savepath", "Save Path:", kCmdSaveBrowser, 0);
+ _savePathWidget = new StaticTextWidget(tab, "GameOptions_Paths.SavepathText", savePath);
if (savePath.empty() || !ConfMan.hasKey("savepath", _domain)) {
_savePathWidget->setLabel("Default");
}
-
+
// Activate the first tab
tab->setActiveTab(0);
+ _tabWidget = tab;
// Add OK & Cancel buttons
- new ButtonWidget(this, "gameoptions_cancel", "Cancel", kCloseCmd, 0);
- new ButtonWidget(this, "gameoptions_ok", "OK", kOKCmd, 0);
+ new ButtonWidget(this, "GameOptions.Cancel", "Cancel", kCloseCmd, 0);
+ new ButtonWidget(this, "GameOptions.Ok", "OK", kOKCmd, 0);
}
void EditGameDialog::reflowLayout() {
OptionsDialog::reflowLayout();
- int labelWidth = g_gui.evaluator()->getVar("tabPopupsLabelW");
+ int labelWidth = g_gui.xmlEval()->getVar("Globals.TabLabelWidth");
if (_langPopUp)
_langPopUp->changeLabelWidth(labelWidth);
@@ -513,17 +513,18 @@ public:
};
SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel)
- : Dialog("scummsaveload"), _delSupport(0), _list(0), _chooseButton(0), _deleteButton(0), _gfxWidget(0) {
+ : Dialog("ScummSaveLoad"), _delSupport(0), _list(0), _chooseButton(0), _deleteButton(0), _gfxWidget(0) {
_delSupport = _metaInfoSupport = _thumbnailSupport = _saveDateSupport = _playTimeSupport = false;
- _drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR;
+// _drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR;
+ _backgroundType = Theme::kDialogBackgroundDefault;
- new StaticTextWidget(this, "scummsaveload_title", title);
+ new StaticTextWidget(this, "ScummSaveLoad.Title", title);
// Add choice list
- _list = new GUI::ListWidget(this, "scummsaveload_list");
+ _list = new GUI::ListWidget(this, "ScummSaveLoad.List");
_list->setNumberingMode(GUI::kListNumberingOff);
-
+
_gfxWidget = new GUI::GraphicsWidget(this, 0, 0, 10, 10);
_date = new StaticTextWidget(this, 0, 0, 10, 10, "No date saved", kTextAlignCenter);
@@ -531,17 +532,17 @@ SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel)
_playtime = new StaticTextWidget(this, 0, 0, 10, 10, "No playtime saved", kTextAlignCenter);
// Buttons
- new GUI::ButtonWidget(this, "scummsaveload_cancel", "Cancel", kCloseCmd, 0);
- _chooseButton = new GUI::ButtonWidget(this, "scummsaveload_choose", buttonLabel, kChooseCmd, 0);
+ new GUI::ButtonWidget(this, "ScummSaveLoad.Cancel", "Cancel", kCloseCmd, 0);
+ _chooseButton = new GUI::ButtonWidget(this, "ScummSaveLoad.Choose", buttonLabel, kChooseCmd, 0);
_chooseButton->setEnabled(false);
- _deleteButton = new GUI::ButtonWidget(this, "scummsaveload_delete", "Delete", kDelCmd, 0);
+ _deleteButton = new GUI::ButtonWidget(this, "ScummSaveLoad.Delete", "Delete", kDelCmd, 0);
_deleteButton->setEnabled(false);
_delSupport = _metaInfoSupport = _thumbnailSupport = false;
_container = new GUI::ContainerWidget(this, 0, 0, 10, 10);
- _container->setHints(GUI::THEME_HINT_USE_SHADOW);
+// _container->setHints(GUI::THEME_HINT_USE_SHADOW);
}
SaveLoadChooser::~SaveLoadChooser() {
@@ -609,26 +610,26 @@ void SaveLoadChooser::handleCommand(CommandSender *sender, uint32 cmd, uint32 da
}
void SaveLoadChooser::reflowLayout() {
- if (g_gui.evaluator()->getVar("scummsaveload_extinfo.visible") == 1 && _thumbnailSupport) {
- int thumbX = g_gui.evaluator()->getVar("scummsaveload_thumbnail.x");
- int thumbY = g_gui.evaluator()->getVar("scummsaveload_thumbnail.y");
- int hPad = g_gui.evaluator()->getVar("scummsaveload_thumbnail.hPad");
- int vPad = g_gui.evaluator()->getVar("scummsaveload_thumbnail.vPad");
+ if (g_gui.xmlEval()->getVar("Globals.ScummSaveLoad.ExtInfo.Visible") == 1 && _thumbnailSupport) {
+ int16 x, y;
+ uint16 w, h;
+
+ if (!g_gui.xmlEval()->getWidgetData("ScummSaveLoad.Thumbnail", x, y, w, h))
+ error("Error when loading position data for Save/Load Thumbnails.");
+
+ int thumbW = kThumbnailWidth;
int thumbH = ((g_system->getHeight() % 200 && g_system->getHeight() != 350) ? kThumbnailHeight2 : kThumbnailHeight1);
+ int thumbX = x + (w >> 1) - (thumbW >> 1);
+ int thumbY = y + kLineHeight;
int textLines = 0;
- if (_saveDateSupport)
- textLines += 2;
- if (_playTimeSupport)
- textLines += 1;
-
- if (textLines)
- ++textLines;
-
- _container->resize(thumbX - hPad, thumbY - vPad, kThumbnailWidth + hPad * 2, thumbH + vPad * 2 + kLineHeight * textLines);
+ if (!_saveDateSupport)
+ textLines++;
+ if (!_playTimeSupport)
+ textLines++;
- // Add the thumbnail display
- _gfxWidget->resize(thumbX, thumbY, kThumbnailWidth, thumbH);
+ _container->resize(x, y, w, h - (kLineHeight * textLines));
+ _gfxWidget->resize(thumbX, thumbY, thumbW, thumbH);
int height = thumbY + thumbH + kLineHeight;
@@ -658,9 +659,9 @@ void SaveLoadChooser::reflowLayout() {
else
_playtime->setFlags(GUI::WIDGET_INVISIBLE);
- _fillR = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillR");
- _fillG = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillG");
- _fillB = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillB");
+ _fillR = 0;
+ _fillG = 0;
+ _fillB = 0;
updateSelection(false);
} else {
_container->setFlags(GUI::WIDGET_INVISIBLE);
@@ -765,7 +766,7 @@ void SaveLoadChooser::updateSaveList() {
LauncherDialog::LauncherDialog()
: Dialog(0, 0, 320, 200) {
- _drawingHints |= THEME_HINT_MAIN_DIALOG;
+ _backgroundType = GUI::Theme::kDialogBackgroundMain;
const int screenW = g_system->getOverlayWidth();
const int screenH = g_system->getOverlayHeight();
@@ -775,39 +776,39 @@ LauncherDialog::LauncherDialog()
#ifndef DISABLE_FANCY_THEMES
_logo = 0;
- if (g_gui.evaluator()->getVar("launcher_logo.visible") == 1 && g_gui.theme()->supportsImages()) {
- _logo = new GraphicsWidget(this, "launcher_logo");
+ if (g_gui.xmlEval()->getVar("Globals.ShowLauncherLogo") == 1 && g_gui.theme()->supportsImages()) {
+ _logo = new GraphicsWidget(this, "Launcher.Logo");
_logo->useThemeTransparency(true);
_logo->setGfx(g_gui.theme()->getImageSurface(Theme::kImageLogo));
- new StaticTextWidget(this, "launcher_version", gScummVMVersionDate);
+ new StaticTextWidget(this, "Launcher.Version", gScummVMVersionDate);
} else
- new StaticTextWidget(this, "launcher_version", gScummVMFullVersion);
+ new StaticTextWidget(this, "Launcher.Version", gScummVMFullVersion);
#else
// Show ScummVM version
- new StaticTextWidget(this, "launcher_version", gScummVMFullVersion);
+ new StaticTextWidget(this, "Launcher.Version", gScummVMFullVersion);
#endif
- new ButtonWidget(this, "launcher_quit_button", "Quit", kQuitCmd, 'Q');
- new ButtonWidget(this, "launcher_about_button", "About", kAboutCmd, 'B');
- new ButtonWidget(this, "launcher_options_button", "Options", kOptionsCmd, 'O');
+ new ButtonWidget(this, "Launcher.QuitButton", "Quit", kQuitCmd, 'Q');
+ new ButtonWidget(this, "Launcher.AboutButton", "About", kAboutCmd, 'B');
+ new ButtonWidget(this, "Launcher.OptionsButton", "Options", kOptionsCmd, 'O');
_startButton =
- new ButtonWidget(this, "launcher_start_button", "Start", kStartCmd, 'S');
+ new ButtonWidget(this, "Launcher.StartButton", "Start", kStartCmd, 'S');
_loadButton =
- new ButtonWidget(this, "launcher_loadGame_button", "Load", kLoadGameCmd, 'L');
+ new ButtonWidget(this, "Launcher.LoadGameButton", "Load", kLoadGameCmd, 'L');
// Above the lowest button rows: two more buttons (directly below the list box)
_addButton =
- new ButtonWidget(this, "launcher_addGame_button", "Add Game...", kAddGameCmd, 'A');
+ new ButtonWidget(this, "Launcher.AddGameButton", "Add Game...", kAddGameCmd, 'A');
_editButton =
- new ButtonWidget(this, "launcher_editGame_button", "Edit Game...", kEditGameCmd, 'E');
+ new ButtonWidget(this, "Launcher.EditGameButton", "Edit Game...", kEditGameCmd, 'E');
_removeButton =
- new ButtonWidget(this, "launcher_removeGame_button", "Remove Game", kRemoveGameCmd, 'R');
+ new ButtonWidget(this, "Launcher.RemoveGameButton", "Remove Game", kRemoveGameCmd, 'R');
// Add list with game titles
- _list = new ListWidget(this, "launcher_list");
+ _list = new ListWidget(this, "Launcher.GameList");
_list->setEditable(false);
_list->setNumberingMode(kListNumberingOff);
@@ -1218,21 +1219,21 @@ void LauncherDialog::updateButtons() {
void LauncherDialog::reflowLayout() {
#ifndef DISABLE_FANCY_THEMES
- if (g_gui.evaluator()->getVar("launcher_logo.visible") == 1 && g_gui.theme()->supportsImages()) {
- StaticTextWidget *ver = (StaticTextWidget*)findWidget("launcher_version");
+ if (g_gui.xmlEval()->getVar("Globals.ShowLauncherLogo") == 1 && g_gui.theme()->supportsImages()) {
+ StaticTextWidget *ver = (StaticTextWidget*)findWidget("Launcher.Version");
if (ver) {
- ver->setAlign((Graphics::TextAlignment)g_gui.evaluator()->getVar("launcher_version.align"));
+ ver->setAlign((Graphics::TextAlignment)g_gui.xmlEval()->getVar("Launcher.Version.Align", Graphics::kTextAlignCenter));
ver->setLabel(gScummVMVersionDate);
}
if (!_logo)
- _logo = new GraphicsWidget(this, "launcher_logo");
+ _logo = new GraphicsWidget(this, "Launcher.Logo");
_logo->useThemeTransparency(true);
_logo->setGfx(g_gui.theme()->getImageSurface(Theme::kImageLogo));
} else {
- StaticTextWidget *ver = (StaticTextWidget*)findWidget("launcher_version");
+ StaticTextWidget *ver = (StaticTextWidget*)findWidget("Launcher.Version");
if (ver) {
- ver->setAlign((Graphics::TextAlignment)g_gui.evaluator()->getVar("launcher_version.align"));
+ ver->setAlign((Graphics::TextAlignment)g_gui.xmlEval()->getVar("Launcher.Version.Align", Graphics::kTextAlignCenter));
ver->setLabel(gScummVMFullVersion);
}
diff --git a/gui/module.mk b/gui/module.mk
index c572dcbeea..f87ef36599 100644
--- a/gui/module.mk
+++ b/gui/module.mk
@@ -9,7 +9,7 @@ MODULE_OBJS := \
dialog.o \
editable.o \
EditTextWidget.o \
- eval.o \
+ ThemeEngine.o \
launcher.o \
ListWidget.o \
massadd.o \
@@ -23,9 +23,9 @@ MODULE_OBJS := \
themebrowser.o \
widget.o \
theme.o \
- ThemeClassic.o \
- ThemeModern.o \
- theme-config.o
+ ThemeEval.o \
+ ThemeLayout.o \
+ ThemeParser.o
# Include common rules
include $(srcdir)/rules.mk
diff --git a/gui/newgui.cpp b/gui/newgui.cpp
index c340c1e8fd..1520aacaea 100644
--- a/gui/newgui.cpp
+++ b/gui/newgui.cpp
@@ -29,9 +29,7 @@
#include "graphics/cursorman.h"
#include "gui/newgui.h"
#include "gui/dialog.h"
-#include "gui/eval.h"
-#include "gui/ThemeModern.h"
-#include "gui/ThemeClassic.h"
+#include "gui/ThemeEngine.h"
#include "common/config-manager.h"
@@ -58,15 +56,12 @@ enum {
void GuiObject::reflowLayout() {
if (!_name.empty()) {
- if ((_x = g_gui.evaluator()->getVar(_name + ".x")) == EVAL_UNDEF_VAR)
- error("Undefined variable %s.x", _name.c_str());
- if ((_y = g_gui.evaluator()->getVar(_name + ".y")) == EVAL_UNDEF_VAR)
- error("Undefined variable %s.y", _name.c_str());
- _w = g_gui.evaluator()->getVar(_name + ".w");
- _h = g_gui.evaluator()->getVar(_name + ".h");
+ if (!g_gui.xmlEval()->getWidgetData(_name, _x, _y, _w, _h)) {
+ warning("Could not load widget position for '%s'", _name.c_str());
+ }
if (_x < 0)
- error("Widget <%s> has x < 0", _name.c_str());
+ error("Widget <%s> has x < 0: %d", _name.c_str(), _x);
if (_x >= g_system->getOverlayWidth())
error("Widget <%s> has x > %d", _name.c_str(), g_system->getOverlayWidth());
if (_x + _w > g_system->getOverlayWidth())
@@ -81,7 +76,7 @@ void GuiObject::reflowLayout() {
}
// Constructor
-NewGui::NewGui() : _needRedraw(false),
+NewGui::NewGui() : _redrawStatus(kRedrawDisabled),
_stateIsSaved(false), _cursorAnimateCounter(0), _cursorAnimateTimer(0) {
_theme = 0;
_useStdCursor = false;
@@ -92,33 +87,16 @@ NewGui::NewGui() : _needRedraw(false),
// Clear the cursor
memset(_cursor, 0xFF, sizeof(_cursor));
- bool loadClassicTheme = true;
-#ifndef DISABLE_FANCY_THEMES
- ConfMan.registerDefault("gui_theme", "default");
- Common::String style(ConfMan.get("gui_theme"));
- // The default theme for now is the 'modern' theme.
- if (style.compareToIgnoreCase("default") == 0)
- style = "modern";
-
- Common::String styleType;
- Common::ConfigFile cfg;
- if (loadNewTheme(style)) {
- loadClassicTheme = false;
- } else {
- loadClassicTheme = true;
- warning("falling back to classic style");
- }
-#endif
- if (loadClassicTheme) {
- _theme = new ThemeClassic(_system);
- assert(_theme);
- if (!_theme->init()) {
- error("Couldn't initialize classic theme");
- }
- }
+ ConfMan.registerDefault("gui_theme", "scummodern.zip");
+ Common::String themefile(ConfMan.get("gui_theme"));
+ if (themefile.compareToIgnoreCase("default") == 0)
+ themefile = "builtin";
+
+ ConfMan.registerDefault("gui_renderer", 2);
+ ThemeEngine::GraphicsMode gfxMode = (ThemeEngine::GraphicsMode)ConfMan.getInt("gui_renderer");
- _theme->resetDrawArea();
+ loadNewTheme(themefile, gfxMode);
_themeChange = false;
}
@@ -126,11 +104,14 @@ NewGui::~NewGui() {
delete _theme;
}
-bool NewGui::loadNewTheme(const Common::String &style) {
- Common::String styleType;
- Common::ConfigFile cfg;
-
- Common::String oldTheme = (_theme != 0) ? _theme->getStylefileName() : "";
+bool NewGui::loadNewTheme(Common::String filename, ThemeEngine::GraphicsMode gfx) {
+ if (_theme && filename == _theme->getThemeFileName() && gfx == _theme->getGraphicsMode())
+ return true;
+
+ Common::String oldTheme = (_theme != 0) ? _theme->getThemeFileName() : "";
+
+ if (gfx == ThemeEngine::kGfxDisabled)
+ gfx = (ThemeEngine::GraphicsMode)ConfMan.getInt("gui_renderer");
if (_theme)
_theme->disable();
@@ -141,38 +122,12 @@ bool NewGui::loadNewTheme(const Common::String &style) {
}
delete _theme;
- _theme = 0;
-
- if (style.compareToIgnoreCase("classic (builtin)") == 0 ||
- style.compareToIgnoreCase("classic") == 0) {
- _theme = new ThemeClassic(_system, style);
- } else {
- if (Theme::themeConfigUseable(style, "", &styleType, &cfg)) {
- if (0 == styleType.compareToIgnoreCase("classic"))
- _theme = new ThemeClassic(_system, style, &cfg);
-#ifndef DISABLE_FANCY_THEMES
- else if (0 == styleType.compareToIgnoreCase("modern"))
- _theme = new ThemeModern(_system, style, &cfg);
-#endif
- else
- warning("Unsupported theme type '%s'", styleType.c_str());
- } else {
- warning("Config '%s' is NOT usable for themes or not found", style.c_str());
- }
- }
- cfg.clear();
+ _theme = new ThemeEngine(filename, gfx);
if (!_theme)
return (!oldTheme.empty() ? loadNewTheme(oldTheme) : false);
- if (!_theme->init()) {
- warning("Could not initialize your preferred theme");
- delete _theme;
- _theme = 0;
- loadNewTheme(oldTheme);
- return false;
- }
- _theme->resetDrawArea();
+ _theme->init();
if (!oldTheme.empty())
screenChange();
@@ -185,29 +140,35 @@ bool NewGui::loadNewTheme(const Common::String &style) {
void NewGui::redraw() {
int i;
- // Restore the overlay to its initial state, then draw all dialogs.
- // This is necessary to get the blending right.
- _theme->clearAll();
-
- _theme->closeAllDialogs();
- //for (i = 0; i < _dialogStack.size(); ++i)
- // _theme->closeDialog();
+ if (_redrawStatus == kRedrawDisabled)
+ return;
- for (i = 0; i < _dialogStack.size(); i++) {
- // Special treatment when topmost dialog has dimsInactive() set to false
- // This is the case for PopUpWidget which should not dim a dialog
- // which it belongs to
- if ((i == _dialogStack.size() - 2) && !_dialogStack[i + 1]->dimsInactive())
- _theme->openDialog(true);
- else if ((i != (_dialogStack.size() - 1)) || !_dialogStack[i]->dimsInactive())
- _theme->openDialog(false);
- else
+ switch (_redrawStatus) {
+ case kRedrawCloseDialog:
+ case kRedrawFull:
+ case kRedrawTopDialog:
+ _theme->clearAll();
_theme->openDialog(true);
- _dialogStack[i]->drawDialog();
+ for (i = 0; i < _dialogStack.size() - 1; i++) {
+ _dialogStack[i]->drawDialog();
+ }
+
+ _theme->finishBuffering();
+ _theme->updateScreen();
+
+ case kRedrawOpenDialog:
+ _theme->openDialog(true, (Theme::ShadingStyle)xmlEval()->getVar("Dialog." + _dialogStack.top()->_name + ".Shading", 0));
+ _dialogStack.top()->drawDialog();
+ _theme->finishBuffering();
+ break;
+
+ default:
+ return;
}
_theme->updateScreen();
+ _redrawStatus = kRedrawDisabled;
}
Dialog *NewGui::getTopDialog() const {
@@ -236,12 +197,11 @@ void NewGui::runLoop() {
}
Common::EventManager *eventMan = _system->getEventManager();
+ uint32 lastRedraw = 0;
+ const uint32 waitTime = 1000 / 45;
while (!_dialogStack.empty() && activeDialog == getTopDialog()) {
- if (_needRedraw) {
- redraw();
- _needRedraw = false;
- }
+ redraw();
// Don't "tickle" the dialog until the theme has had a chance
// to re-allocate buffers in case of a scaler change.
@@ -250,9 +210,15 @@ void NewGui::runLoop() {
if (_useStdCursor)
animateCursor();
- _theme->updateScreen();
- _system->updateScreen();
-
+// _theme->updateScreen();
+// _system->updateScreen();
+
+ if (lastRedraw + waitTime < _system->getMillis()) {
+ _theme->updateScreen();
+ _system->updateScreen();
+ lastRedraw = _system->getMillis();
+ }
+
Common::Event event;
while (eventMan->pollEvent(event)) {
@@ -272,8 +238,15 @@ void NewGui::runLoop() {
_theme->refresh();
_themeChange = false;
+ _redrawStatus = kRedrawFull;
redraw();
}
+
+ if (lastRedraw + waitTime < _system->getMillis()) {
+ _theme->updateScreen();
+ _system->updateScreen();
+ lastRedraw = _system->getMillis();
+ }
switch (event.type) {
case Common::EVENT_KEYDOWN:
@@ -329,11 +302,6 @@ void NewGui::runLoop() {
_system->delayMillis(10);
}
- // HACK: since we reopen all dialogs anyway on redraw
- // we for now use Theme::closeAllDialogs here, until
- // we properly add (and implement) Theme::closeDialog
- _theme->closeAllDialogs();
-
if (didSaveState) {
_theme->disable();
restoreState();
@@ -365,7 +333,7 @@ void NewGui::restoreState() {
void NewGui::openDialog(Dialog *dialog) {
_dialogStack.push(dialog);
- _needRedraw = true;
+ _redrawStatus = kRedrawOpenDialog;
// We reflow the dialog just before opening it. If the screen changed
// since the last time we looked, also refresh the loaded theme,
@@ -392,7 +360,7 @@ void NewGui::closeTopDialog() {
// Remove the dialog from the stack
_dialogStack.pop();
- _needRedraw = true;
+ _redrawStatus = kRedrawCloseDialog;
}
void NewGui::setupCursor() {
@@ -430,7 +398,7 @@ void NewGui::animateCursor() {
}
WidgetSize NewGui::getWidgetSize() {
- return (WidgetSize)(_theme->_evaluator->getVar("widgetSize"));
+ return (WidgetSize)(g_gui.xmlEval()->getVar("Globals.WidgetSize"));
}
void NewGui::clearDragWidget() {
@@ -450,7 +418,10 @@ void NewGui::screenChange() {
// We need to redraw immediately. Otherwise
// some other event may cause a widget to be
// redrawn before redraw() has been called.
+ _redrawStatus = kRedrawFull;
redraw();
+ _system->showOverlay();
+ _system->updateScreen();
}
} // End of namespace GUI
diff --git a/gui/newgui.h b/gui/newgui.h
index 4cf082c877..0b3de01c83 100644
--- a/gui/newgui.h
+++ b/gui/newgui.h
@@ -33,12 +33,15 @@
#include "gui/theme.h"
#include "gui/widget.h"
+#include "gui/ThemeEngine.h"
+
class OSystem;
namespace GUI {
class Dialog;
class Eval;
+class ThemeEval;
#define g_gui (GUI::NewGui::instance())
@@ -75,9 +78,10 @@ public:
bool isActive() const { return ! _dialogStack.empty(); }
- bool loadNewTheme(const Common::String &file);
+ bool loadNewTheme(Common::String file, ThemeEngine::GraphicsMode gfx = ThemeEngine::kGfxDisabled);
Theme *theme() { return _theme; }
- Eval *evaluator() { return _theme->_evaluator; }
+
+ ThemeEval *xmlEval() { return _theme->evaluator(); }
const Graphics::Font &getFont(Theme::FontStyle style = Theme::kFontStyleBold) const { return *(_theme->getFont(style)); }
int getFontHeight(Theme::FontStyle style = Theme::kFontStyleBold) const { return _theme->getFontHeight(style); }
@@ -90,12 +94,21 @@ public:
void screenChange();
+ enum RedrawStatus {
+ kRedrawDisabled = 0,
+ kRedrawOpenDialog,
+ kRedrawCloseDialog,
+ kRedrawTopDialog,
+ kRedrawFull
+ };
+
protected:
OSystem *_system;
Theme *_theme;
- bool _needRedraw;
+// bool _needRedraw;
+ RedrawStatus _redrawStatus;
int _lastScreenChangeID;
DialogStack _dialogStack;
diff --git a/gui/options.cpp b/gui/options.cpp
index 6797e4a80c..5a95101f3d 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -25,9 +25,9 @@
#include "gui/browser.h"
#include "gui/themebrowser.h"
#include "gui/chooser.h"
-#include "gui/eval.h"
#include "gui/message.h"
#include "gui/newgui.h"
+#include "gui/ThemeEval.h"
#include "gui/options.h"
#include "gui/PopUpWidget.h"
#include "gui/TabWidget.h"
@@ -73,12 +73,12 @@ static const int outputRateValues[] = { 0, 22050, 8000, 11025, 44100, 48000, -1
OptionsDialog::OptionsDialog(const String &domain, int x, int y, int w, int h)
- : Dialog(x, y, w, h), _domain(domain) {
+ : Dialog(x, y, w, h), _domain(domain), _graphicsTabId(-1), _tabWidget(0) {
init();
}
OptionsDialog::OptionsDialog(const String &domain, const String &name)
- : Dialog(name), _domain(domain) {
+ : Dialog(name), _domain(domain), _graphicsTabId(-1), _tabWidget(0) {
init();
}
@@ -88,6 +88,12 @@ const char *OptionsDialog::_subModeDesc[] = {
"Subtitles Only"
};
+const char *OptionsDialog::_lowresSubModeDesc[] = {
+ "Speech Only",
+ "Speech & Subs",
+ "Subtitles Only"
+};
+
void OptionsDialog::init() {
_enableGraphicSettings = false;
_gfxPopUp = 0;
@@ -417,7 +423,7 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
else
_subMode = 0;
- _subToggleButton->setLabel(_subModeDesc[_subMode]);
+ _subToggleButton->setLabel(g_system->getOverlayWidth() > 320 ? _subModeDesc[_subMode] : _lowresSubModeDesc[_subMode]);
_subToggleButton->draw();
_subSpeedDesc->draw();
_subSpeedSlider->draw();
@@ -500,7 +506,7 @@ void OptionsDialog::setSubtitleSettingsState(bool enabled) {
void OptionsDialog::addGraphicControls(GuiObject *boss, const String &prefix) {
const OSystem::GraphicsMode *gm = g_system->getSupportedGraphicsModes();
- int labelWidth = g_gui.evaluator()->getVar("tabPopupsLabelW");
+ int labelWidth = g_gui.xmlEval()->getVar("Globals.TabLabelWidth");
// The GFX mode popup
_gfxPopUp = new PopUpWidget(boss, prefix + "grModePopup", "Graphics mode:", labelWidth);
@@ -537,7 +543,7 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const String &prefix) {
}
void OptionsDialog::addAudioControls(GuiObject *boss, const String &prefix) {
- int labelWidth = g_gui.evaluator()->getVar("tabPopupsLabelW");
+ int labelWidth = g_gui.xmlEval()->getVar("Globals.TabLabelWidth");
// The MIDI mode popup & a label
_midiPopUp = new PopUpWidget(boss, prefix + "auMidiPopup", "Music driver:", labelWidth);
@@ -643,7 +649,10 @@ int OptionsDialog::getSubtitleMode(bool subtitles, bool speech_mute) {
void OptionsDialog::reflowLayout() {
Dialog::reflowLayout();
- int labelWidth = g_gui.evaluator()->getVar("tabPopupsLabelW");
+ int labelWidth = g_gui.xmlEval()->getVar("Globals.TabLabelWidth");
+
+ if (_graphicsTabId != -1 && _tabWidget)
+ _tabWidget->setTabTitle(_graphicsTabId, g_system->getOverlayWidth() > 320 ? "Graphics" : "GFX");
if (_midiPopUp)
_midiPopUp->changeLabelWidth(labelWidth);
@@ -659,27 +668,26 @@ void OptionsDialog::reflowLayout() {
GlobalOptionsDialog::GlobalOptionsDialog()
- : OptionsDialog(Common::ConfigManager::kApplicationDomain, "globaloptions") {
+ : OptionsDialog(Common::ConfigManager::kApplicationDomain, "GlobalOptions") {
// The tab widget
- TabWidget *tab = new TabWidget(this, "globaloptions_tabwidget");
- tab->setHints(THEME_HINT_FIRST_DRAW | THEME_HINT_SAVE_BACKGROUND);
+ TabWidget *tab = new TabWidget(this, "GlobalOptions.TabWidget");
//
// 1) The graphics tab
//
- tab->addTab("Graphics");
- addGraphicControls(tab, "globaloptions_");
+ _graphicsTabId = tab->addTab(g_system->getOverlayWidth() > 320 ? "Graphics" : "GFX");
+ addGraphicControls(tab, "GlobalOptions_Graphics.");
//
// 2) The audio tab
//
tab->addTab("Audio");
- addAudioControls(tab, "globaloptions_");
- addSubtitleControls(tab, "globaloptions_");
+ addAudioControls(tab, "GlobalOptions_Audio.");
+ addSubtitleControls(tab, "GlobalOptions_Audio.");
tab->addTab("Volume");
- addVolumeControls(tab, "globaloptions_");
+ addVolumeControls(tab, "GlobalOptions_Volume.");
// TODO: cd drive setting
@@ -687,7 +695,7 @@ GlobalOptionsDialog::GlobalOptionsDialog()
// 3) The MIDI tab
//
tab->addTab("MIDI");
- addMIDIControls(tab, "globaloptions_");
+ addMIDIControls(tab, "GlobalOptions_MIDI.");
//
// 4) The miscellaneous tab
@@ -699,33 +707,40 @@ GlobalOptionsDialog::GlobalOptionsDialog()
// truncated in the small version of the GUI.
// Save game path
- new ButtonWidget(tab, "globaloptions_savebutton", "Save Path: ", kChooseSaveDirCmd, 0);
- _savePath = new StaticTextWidget(tab, "globaloptions_savepath", "/foo/bar");
+ new ButtonWidget(tab, "GlobalOptions_Paths.SaveButton", "Save Path: ", kChooseSaveDirCmd, 0);
+ _savePath = new StaticTextWidget(tab, "GlobalOptions_Paths.SavePath", "/foo/bar");
- new ButtonWidget(tab, "globaloptions_themebutton", "Theme Path:", kChooseThemeDirCmd, 0);
- _themePath = new StaticTextWidget(tab, "globaloptions_themepath", "None");
+ new ButtonWidget(tab, "GlobalOptions_Paths.ThemeButton", "Theme Path:", kChooseThemeDirCmd, 0);
+ _themePath = new StaticTextWidget(tab, "GlobalOptions_Paths.ThemePath", "None");
- new ButtonWidget(tab, "globaloptions_extrabutton", "Extra Path:", kChooseExtraDirCmd, 0);
- _extraPath = new StaticTextWidget(tab, "globaloptions_extrapath", "None");
+ new ButtonWidget(tab, "GlobalOptions_Paths.ExtraButton", "Extra Path:", kChooseExtraDirCmd, 0);
+ _extraPath = new StaticTextWidget(tab, "GlobalOptions_Paths.ExtraPath", "None");
#ifdef DYNAMIC_MODULES
- new ButtonWidget(tab, "globaloptions_pluginsbutton", "Plugins Path:", kChoosePluginsDirCmd, 0);
- _pluginsPath = new StaticTextWidget(tab, "globaloptions_pluginspath", "None");
+ new ButtonWidget(tab, "GlobalOptions_Paths.PluginsButton", "Plugins Path:", kChoosePluginsDirCmd, 0);
+ _pluginsPath = new StaticTextWidget(tab, "GlobalOptions_Paths.PluginsPath", "None");
#endif
#endif
#ifdef SMALL_SCREEN_DEVICE
- new ButtonWidget(tab, "globaloptions_keysbutton", "Keys", kChooseKeyMappingCmd, 0);
+ new ButtonWidget(tab, "GlobalOptions.KeysButton", "Keys", kChooseKeyMappingCmd, 0);
#endif
tab->addTab("Misc");
- new ButtonWidget(tab, "globaloptions_themebutton2", "Theme:", kChooseThemeCmd, 0);
- _curTheme = new StaticTextWidget(tab, "globaloptions_curtheme", g_gui.theme()->getThemeName());
-
- int labelWidth = g_gui.evaluator()->getVar("tabPopupsLabelW");
+ new ButtonWidget(tab, "GlobalOptions_Misc.ThemeButton", "Theme:", kChooseThemeCmd, 0);
+ _curTheme = new StaticTextWidget(tab, "GlobalOptions_Misc.CurTheme", g_gui.theme()->getThemeName());
+
- _autosavePeriodPopUp = new PopUpWidget(tab, "globaloptions_autosaveperiod", "Autosave:", labelWidth);
+ int labelWidth = g_gui.xmlEval()->getVar("Globals.TabLabelWidth");
+
+ _rendererPopUp = new PopUpWidget(tab, "GlobalOptions_Misc.Renderer", "GUI Renderer:", labelWidth);
+
+ for (int i = 1; i < GUI::ThemeEngine::kGfxMAX; ++i) {
+ _rendererPopUp->appendEntry(GUI::ThemeEngine::rendererModeLabels[i], i);
+ }
+
+ _autosavePeriodPopUp = new PopUpWidget(tab, "GlobalOptions_Misc.AutosavePeriod", "Autosave:", labelWidth);
for (int i = 0; savePeriodLabels[i]; i++) {
_autosavePeriodPopUp->appendEntry(savePeriodLabels[i], savePeriodValues[i]);
@@ -736,10 +751,11 @@ GlobalOptionsDialog::GlobalOptionsDialog()
// Activate the first tab
tab->setActiveTab(0);
+ _tabWidget = tab;
// Add OK & Cancel buttons
- new ButtonWidget(this, "globaloptions_cancel", "Cancel", kCloseCmd, 0);
- new ButtonWidget(this, "globaloptions_ok", "OK", kOKCmd, 0);
+ new ButtonWidget(this, "GlobalOptions.Cancel", "Cancel", kCloseCmd, 0);
+ new ButtonWidget(this, "GlobalOptions.Ok", "OK", kOKCmd, 0);
#ifdef SMALL_SCREEN_DEVICE
_keysDialog = new KeysDialog();
@@ -796,6 +812,8 @@ void GlobalOptionsDialog::open() {
if (value == savePeriodValues[i])
_autosavePeriodPopUp->setSelected(i);
}
+
+ _rendererPopUp->setSelected(ConfMan.getInt("gui_renderer") - 1);
}
void GlobalOptionsDialog::close() {
@@ -825,6 +843,11 @@ void GlobalOptionsDialog::close() {
#endif
ConfMan.setInt("autosave_period", _autosavePeriodPopUp->getSelectedTag(), _domain);
+
+ if ((int)_rendererPopUp->getSelectedTag() != ConfMan.getInt("gui_renderer")) {
+ g_gui.loadNewTheme(g_gui.theme()->getThemeFileName(), (GUI::ThemeEngine::GraphicsMode)_rendererPopUp->getSelectedTag());
+ ConfMan.setInt("gui_renderer", _rendererPopUp->getSelectedTag(), _domain);
+ }
}
OptionsDialog::close();
}
@@ -906,7 +929,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
if (browser.runModal() > 0) {
// User made his choice...
const Common::String &theme = browser.selected();
- if (0 != theme.compareToIgnoreCase(g_gui.theme()->getStylefileName()))
+ if (0 != theme.compareToIgnoreCase(g_gui.theme()->getThemeFileName()))
if (g_gui.loadNewTheme(theme)) {
_curTheme->setLabel(g_gui.theme()->getThemeName());
ConfMan.set("gui_theme", theme);
diff --git a/gui/options.h b/gui/options.h
index 8f4496c753..187e163b79 100644
--- a/gui/options.h
+++ b/gui/options.h
@@ -26,6 +26,7 @@
#define OPTIONS_DIALOG_H
#include "gui/dialog.h"
+#include "gui/TabWidget.h"
#include "common/str.h"
#ifdef SMALL_SCREEN_DEVICE
@@ -80,6 +81,9 @@ protected:
void setMIDISettingsState(bool enabled);
void setVolumeSettingsState(bool enabled);
void setSubtitleSettingsState(bool enabled);
+
+ TabWidget *_tabWidget;
+ int _graphicsTabId;
private:
//
@@ -118,6 +122,7 @@ private:
ButtonWidget *_subToggleButton;
int _subMode;
static const char *_subModeDesc[];
+ static const char *_lowresSubModeDesc[];
StaticTextWidget *_subSpeedDesc;
SliderWidget *_subSpeedSlider;
StaticTextWidget *_subSpeedLabel;
@@ -166,7 +171,7 @@ protected:
// Misc controls
//
StaticTextWidget *_curTheme;
-
+ PopUpWidget *_rendererPopUp;
PopUpWidget *_autosavePeriodPopUp;
};
diff --git a/gui/theme.cpp b/gui/theme.cpp
index 39dedd3875..3205ee6533 100644
--- a/gui/theme.cpp
+++ b/gui/theme.cpp
@@ -23,40 +23,15 @@
*/
#include "gui/theme.h"
-#include "gui/eval.h"
#include "common/file.h"
-
#include "common/archive.h"
#include "common/unzip.h"
namespace GUI {
-Theme::Theme() : _drawArea(), _stylefile(""), _configFile(), _loadedThemeX(0), _loadedThemeY(0) {
- Common::MemoryReadStream s((const byte *)_defaultConfigINI, strlen(_defaultConfigINI));
- _defaultConfig.loadFromStream(s);
-
- _evaluator = new Eval();
-}
-
-Theme::~Theme() {
- delete _evaluator;
-}
-
-void Theme::getColorFromConfig(const Common::String &value, OverlayColor &color) {
- const char *postfixes[] = {".r", ".g", ".b"};
- int rgb[3];
-
- for (int cnt = 0; cnt < 3; cnt++)
- rgb[cnt] = _evaluator->getVar(value + postfixes[cnt], 0);
-
- color = g_system->RGBToColor(rgb[0], rgb[1], rgb[2]);
-}
+Theme::Theme() : _loadedThemeX(0), _loadedThemeY(0) {}
-void Theme::getColorFromConfig(const Common::String &value, uint8 &r, uint8 &g, uint8 &b) {
- r = _evaluator->getVar(value + ".r", 0);
- g = _evaluator->getVar(value + ".g", 0);
- b = _evaluator->getVar(value + ".b", 0);
-}
+Theme::~Theme() {}
const Graphics::Font *Theme::loadFont(const char *filename) {
const Graphics::NewFont *font = 0;
@@ -70,7 +45,7 @@ const Graphics::Font *Theme::loadFont(const char *filename) {
return font;
#ifdef USE_ZLIB
- Common::ZipArchive zipArchive(_stylefile + ".zip");
+ Common::ZipArchive zipArchive(getThemeFileName().c_str());
Common::SeekableReadStream *stream(zipArchive.openFile(cacheFilename));
if (stream) {
font = Graphics::NewFont::loadFromCache(*stream);
@@ -88,7 +63,8 @@ const Graphics::Font *Theme::loadFont(const char *filename) {
#ifdef USE_ZLIB
if (!font) {
- Common::ZipArchive zipArchive(_stylefile + ".zip");
+ Common::ZipArchive zipArchive(getThemeFileName().c_str());
+
Common::SeekableReadStream *stream(zipArchive.openFile(filename));
if (stream) {
font = Graphics::NewFont::loadFont(*stream);
@@ -124,83 +100,71 @@ Common::String Theme::genCacheFilename(const char *filename) {
return "";
}
-bool Theme::loadConfigFile(const Common::String &stylefile) {
- if (ConfMan.hasKey("themepath"))
- Common::File::addDefaultDirectory(ConfMan.get("themepath"));
-
-#ifdef DATA_PATH
- Common::File::addDefaultDirectoryRecursive(DATA_PATH);
-#endif
+bool Theme::isThemeLoadingRequired() {
+ int x = g_system->getOverlayWidth(), y = g_system->getOverlayHeight();
- if (ConfMan.hasKey("extrapath"))
- Common::File::addDefaultDirectoryRecursive(ConfMan.get("extrapath"));
+ if (_loadedThemeX == x && _loadedThemeY == y)
+ return false;
- if (_configFile.loadFromFile(stylefile + ".ini"))
- return true;
+ _loadedThemeX = x;
+ _loadedThemeY = y;
-#ifdef USE_ZLIB
- // Maybe find a nicer solution to this
- Common::ZipArchive zipArchive(stylefile + ".zip");
- Common::File file;
- if (file.open(stylefile + ".ini", zipArchive)) {
- return _configFile.loadFromStream(file);
- }
-#endif
-
- return false;
+ return true;
}
-bool Theme::themeConfigUseable(const Common::String &stylefile, const Common::String &style, Common::String *cStyle, Common::ConfigFile *cfg) {
- 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"));
+bool Theme::themeConfigParseHeader(Common::String header, Common::String &themeName) {
+ header.trim();
+
+ 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();
- Common::File file;
- Common::ConfigFile configFile;
- if (!cfg && (cStyle || !style.empty()))
- cfg = &configFile;
+ return tok.empty();
+}
- if (!file.open(stylefile + ".ini")) {
+bool Theme::themeConfigUseable(const Common::FSNode &node, Common::String &themeName) {
+ Common::String stxHeader;
+ bool foundHeader = false;
+
+ if (node.getName().hasSuffix(".zip")) {
+
#ifdef USE_ZLIB
- // Maybe find a nicer solution to this
- Common::ZipArchive zipArchive(stylefile + ".zip");
- if (zipArchive.hasFile(stylefile + ".ini")) {
- if (!style.empty() || cStyle || cfg) {
- Common::FilePtr stream(zipArchive.openFile(stylefile + ".ini"));
- if (!cfg->loadFromStream(*stream.get()))
- return false;
- }
- } else {
- return false;
+ Common::ZipArchive zipArchive(node.getPath().c_str());
+ if (zipArchive.hasFile("THEMERC")) {
+ Common::FilePtr stream(zipArchive.openFile("THEMERC"));
+ stxHeader = stream->readLine();
+ // TODO: Read first line of file. How?
+ if (themeConfigParseHeader(stxHeader.c_str(), themeName))
+ foundHeader = true;
}
#else
return false;
#endif
- }
- if (!style.empty() || cStyle || cfg) {
- if (file.isOpen()) {
- if (!cfg->loadFromStream(file))
- return false;
- file.close();
- }
-
- Common::String temp;
- if (!cfg->getKey("type", "theme", temp))
- return false;
- if (cStyle)
- *cStyle = temp;
- if (0 != temp.compareToIgnoreCase(style) && !style.empty())
+ } else if (node.isDirectory()) {
+ Common::FSNode headerfile = node.getChild("THEMERC");
+ if (!headerfile.exists() || !headerfile.isReadable() || headerfile.isDirectory())
return false;
+
+ // TODO: File or FilePtr?
+ Common::File f;
+ f.open(headerfile);
+ stxHeader = f.readLine();
+ if (themeConfigParseHeader(stxHeader.c_str(), themeName))
+ foundHeader = true;
}
- return true;
+ return foundHeader;
}
} // End of namespace GUI
diff --git a/gui/theme.h b/gui/theme.h
index c5a412e286..c4080f884e 100644
--- a/gui/theme.h
+++ b/gui/theme.h
@@ -28,49 +28,18 @@
#include "common/system.h"
#include "common/rect.h"
#include "common/str.h"
+#include "common/fs.h"
#include "common/config-file.h"
#include "graphics/surface.h"
#include "graphics/fontman.h"
#define THEME_VERSION 24
+#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_THEME_V23"
namespace GUI {
-class Eval;
-
-//! Hint to the theme engine that the widget is used in a non-standard way.
-enum ThemeHint {
- //! Indicates that this is the first time the widget is drawn.
- THEME_HINT_FIRST_DRAW = 1 << 0,
-
- /**
- * Indicates that the widget will be redrawn often, e.g. list widgets.
- * It may therefore be a good idea to save the background so that it
- * can be redrawn quickly.
- */
- THEME_HINT_SAVE_BACKGROUND = 1 << 1,
-
- //! Indicates that this is the launcher dialog (maybe delete this in the future)
- THEME_HINT_MAIN_DIALOG = 1 << 2,
-
- //! Indicates special colorfade
- THEME_HINT_SPECIAL_COLOR = 1 << 3,
-
- //! Indicates no colorfade
- THEME_HINT_PLAIN_COLOR = 1 << 4,
-
- //! Indictaes that a shadows should be drawn around the background
- THEME_HINT_USE_SHADOW = 1 << 5,
-
- /**
- * Indicates that no background should be restored when drawing the widget
- * (note that this can be silently ignored if for example the theme does
- * alpha blending and would blend over an already drawn widget)
- * TODO: currently only ThemeModern::drawButton supports this
- */
- THEME_HINT_NO_BACKGROUND_RESTORE = 1 << 6
-};
+class ThemeEval;
/**
* Our theme renderer class.
@@ -91,6 +60,13 @@ public:
kTextAlignCenter, //! Text should be centered
kTextAlignRight //! Text should be aligned to the right
};
+
+ //! Vertical alignment of the text.
+ enum TextAlignVertical {
+ kTextAlignVBottom,
+ kTextAlignVCenter,
+ kTextAlignVTop
+ };
//! Widget background type
enum WidgetBackground {
@@ -101,6 +77,14 @@ public:
kWidgetBackgroundEditText, //! Background used for edit text fields
kWidgetBackgroundSlider //! Background used for sliders
};
+
+ //! Dialog background type
+ enum DialogBackground {
+ kDialogBackgroundMain,
+ kDialogBackgroundSpecial,
+ kDialogBackgroundPlain,
+ kDialogBackgroundDefault
+ };
//! State of the widget to be drawn
enum State {
@@ -221,7 +205,7 @@ public:
*
* @see closeAllDialogs
*/
- virtual void openDialog(bool topDialog) = 0;
+ virtual void openDialog(bool topDialog, ShadingStyle shading = kShadingNone) = 0;
/**
* This indicates that all dialogs have been closed.
@@ -231,6 +215,21 @@ public:
virtual void closeAllDialogs() = 0;
/**
+ * Closes the topmost dialog, and redraws the screen
+ * accordingly.
+ *
+ * TODO: Make this purely virtual by making ThemeClassic
+ * and ThemeModern implement it too.
+ *
+ * @returns True if the dialog was sucessfully closed.
+ * If we weren't able to restore the screen after closing
+ * the dialog, we return false, which means we need to redraw
+ * the dialog stack from scratch.
+ */
+ virtual void startBuffering() = 0;
+ virtual void finishBuffering() = 0;
+
+ /**
* Clear the complete GUI screen.
*/
virtual void clearAll() = 0;
@@ -243,42 +242,12 @@ public:
*/
virtual void updateScreen() = 0;
- /**
- * Set the active screen area, in which the renderer is able to
- * draw.
- *
- * This does not affect the coordinates for the draw* functions,
- * it just marks the screen rect given in param r as writeable.
- *
- * This is for example used in the credits dialog, which, if not
- * just a part of the screen would be marked as writeable, would
- * draw parts of the scrolling text outside the dialog box and
- * thus would look strange.
- *
- * The active area defaults to the whole screen, so there is just
- * need to use this function if you want to limit it.
- *
- * @param r rect of the screen, which should be writeable
- *
- * @see resetDrawArea
- */
- virtual void setDrawArea(const Common::Rect &r) { _drawArea = r; }
-
- /**
- * Resets the draw area to the whole screen.
- *
- * @see setDrawArea
- */
- virtual void resetDrawArea() = 0;
-
- virtual const Common::ConfigFile &getConfigFile() const { return _configFile; }
-
virtual const Graphics::Font *getFont(FontStyle font = kFontStyleBold) const = 0;
virtual int getFontHeight(FontStyle font = kFontStyleBold) const = 0;
virtual int getStringWidth(const Common::String &str, FontStyle font = kFontStyleBold) const = 0;
virtual int getCharWidth(byte c, FontStyle font = kFontStyleBold) const = 0;
- virtual void drawDialogBackground(const Common::Rect &r, uint16 hints, WidgetStateInfo state = kStateEnabled) = 0;
+ virtual void drawDialogBackground(const Common::Rect &r, DialogBackground type, WidgetStateInfo state = kStateEnabled) = 0;
virtual void drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state = kStateEnabled, TextAlign align = kTextAlignCenter, bool inverted = false, int deltax = 0, bool useEllipsis = true, FontStyle font = kFontStyleBold) = 0;
// this should ONLY be used by the debugger until we get a nicer solution
virtual void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state = kStateEnabled) = 0;
@@ -332,20 +301,16 @@ public:
return kTextAlignCenter;
}
- void processResSection(Common::ConfigFile &config, const Common::String &name, bool skipDefs = false, const Common::String &prefix = "");
- void processSingleLine(const Common::String &section, const Common::String &prefix, const Common::String &name, const Common::String &str);
- void setSpecialAlias(const Common::String &alias, const Common::String &name);
bool isThemeLoadingRequired();
- bool sectionIsSkipped(Common::ConfigFile &config, const char *name, int w, int h);
- void loadTheme(Common::ConfigFile &config, bool reset = true);
- void loadTheme(Common::ConfigFile &config, bool reset, bool doBackendSpecificPostProcessing);
- Eval *_evaluator;
+ virtual ThemeEval *evaluator() = 0;
- static bool themeConfigUseable(const Common::String &file, const Common::String &style="", Common::String *cStyle=0, Common::ConfigFile *cfg=0);
+ static bool themeConfigUseable(const Common::FSNode &node, Common::String &themeName);
+ static bool themeConfigParseHeader(Common::String header, Common::String &themeName);
- const Common::String &getStylefileName() const { return _stylefile; }
- const Common::String &getThemeName() const { return _stylename; }
+ virtual const Common::String &getThemeFileName() const = 0;
+ virtual const Common::String &getThemeName() const = 0;
+ virtual int getGraphicsMode() const = 0;
/**
* Checks if the theme renderer supports drawing of images.
@@ -370,19 +335,10 @@ public:
*/
virtual const Graphics::Surface *getImageSurface(const kThemeImages n) const { return 0; }
protected:
- bool loadConfigFile(const Common::String &file);
- void getColorFromConfig(const Common::String &name, OverlayColor &col);
- void getColorFromConfig(const Common::String &value, uint8 &r, uint8 &g, uint8 &b);
const Graphics::Font *loadFont(const char *filename);
Common::String genCacheFilename(const char *filename);
- Common::String _stylefile, _stylename;
-
- Common::Rect _drawArea;
- Common::ConfigFile _configFile;
- Common::ConfigFile _defaultConfig;
-
public:
bool needThemeReload() { return ((_loadedThemeX != g_system->getOverlayWidth()) ||
(_loadedThemeY != g_system->getOverlayHeight())); }
diff --git a/gui/themebrowser.cpp b/gui/themebrowser.cpp
index 2c1c542319..7d3933cfbe 100644
--- a/gui/themebrowser.cpp
+++ b/gui/themebrowser.cpp
@@ -43,21 +43,21 @@ enum {
// but for now this simple browser works,
// also it will get its own theme config values
// and not use 'browser_' anymore
-ThemeBrowser::ThemeBrowser() : Dialog("browser") {
+ThemeBrowser::ThemeBrowser() : Dialog("Browser") {
_fileList = 0;
- new StaticTextWidget(this, "browser_headline", "Select a Theme");
+ new StaticTextWidget(this, "Browser.Headline", "Select a Theme");
// Add file list
- _fileList = new ListWidget(this, "browser_list");
+ _fileList = new ListWidget(this, "Browser.List");
_fileList->setNumberingMode(kListNumberingOff);
_fileList->setEditable(false);
- _fileList->setHints(THEME_HINT_PLAIN_COLOR);
+ _backgroundType = GUI::Theme::kDialogBackgroundPlain;
// Buttons
- new ButtonWidget(this, "browser_cancel", "Cancel", kCloseCmd, 0);
- new ButtonWidget(this, "browser_choose", "Choose", kChooseCmd, 0);
+ new ButtonWidget(this, "Browser.Cancel", "Cancel", kCloseCmd, 0);
+ new ButtonWidget(this, "Browser.Choose", "Choose", kChooseCmd, 0);
}
void ThemeBrowser::open() {
@@ -89,11 +89,10 @@ void ThemeBrowser::handleCommand(CommandSender *sender, uint32 cmd, uint32 data)
void ThemeBrowser::updateListing() {
_themes.clear();
- // classic is always build in
+ // classic is always built-in
Entry th;
- th.name = "Classic (Builtin)";
- th.type = "Classic";
- th.file = "Classic (Builtin)";
+ th.name = "ScummVM Classic Theme (Builtin Version)";
+ th.file = "builtin";
_themes.push_back(th);
// we are using only the paths 'themepath', 'extrapath', DATA_PATH and '.'
@@ -101,7 +100,7 @@ void ThemeBrowser::updateListing() {
// files in other places are ignored in this dialog
// TODO: let the user browse the complete FS too/only the FS?
if (ConfMan.hasKey("themepath"))
- addDir(_themes, Common::FSNode(ConfMan.get("themepath")), 0);
+ addDir(_themes, Common::FSNode(ConfMan.get("themepath")));
#ifdef DATA_PATH
addDir(_themes, Common::FSNode(DATA_PATH));
@@ -113,7 +112,7 @@ void ThemeBrowser::updateListing() {
char buf[256];
if (CFURLGetFileSystemRepresentation(resourceUrl, true, (UInt8 *)buf, 256)) {
Common::FSNode resourcePath(buf);
- addDir(_themes, resourcePath, 0);
+ addDir(_themes, resourcePath);
}
CFRelease(resourceUrl);
}
@@ -122,7 +121,7 @@ void ThemeBrowser::updateListing() {
if (ConfMan.hasKey("extrapath"))
addDir(_themes, Common::FSNode(ConfMan.get("extrapath")));
- addDir(_themes, Common::FSNode("."), 0);
+ addDir(_themes, Common::FSNode("."));
// Populate the ListWidget
Common::StringList list;
@@ -137,10 +136,8 @@ void ThemeBrowser::updateListing() {
draw();
}
-void ThemeBrowser::addDir(ThList &list, const Common::FSNode &node, int level) {
- if (level < 0)
- return;
+void ThemeBrowser::addDir(ThList &list, const Common::FSNode &node) {
if (!node.exists() || !node.isReadable())
return;
@@ -149,12 +146,30 @@ void ThemeBrowser::addDir(ThList &list, const Common::FSNode &node, int level) {
return;
for (Common::FSList::const_iterator i = fslist.begin(); i != fslist.end(); ++i) {
- if (i->isDirectory()) {
- addDir(list, *i, level-1);
- } else {
+
+ Entry th;
+ if (isTheme(*i, th)) {
+ bool add = true;
+
+ for (ThList::const_iterator p = list.begin(); p != list.end(); ++p) {
+ if (p->name == th.name || p->file == th.file) {
+ add = false;
+ break;
+ }
+ }
+
+ if (add)
+ list.push_back(th);
+ }
+ }
+
+ if (node.lookupFile(fslist, "THEMERC", false, true, 1)) {
+ for (FSList::const_iterator i = fslist.begin(); i != fslist.end(); ++i) {
+
Entry th;
- if (isTheme(*i, th)) {
+ if (isTheme(i->getParent(), th)) {
bool add = true;
+
for (ThList::const_iterator p = list.begin(); p != list.end(); ++p) {
if (p->name == th.name || p->file == th.file) {
add = false;
@@ -170,35 +185,19 @@ void ThemeBrowser::addDir(ThList &list, const Common::FSNode &node, int level) {
}
bool ThemeBrowser::isTheme(const Common::FSNode &node, Entry &out) {
- Common::ConfigFile cfg;
- Common::String type;
-
- out.file = node.getName();
+ out.file = node.getPath();
- // Only accept .ini and .zip fies
- if (!out.file.hasSuffix(".ini") && !out.file.hasSuffix(".zip"))
+#ifdef USE_ZLIB
+ if (!out.file.hasSuffix(".zip") && !node.isDirectory())
return false;
-
- // Remove the filename extension
- while (!out.file.empty() && out.file.lastChar() != '.') {
- out.file.deleteLastChar();
- }
- if (out.file.lastChar() == '.')
- out.file.deleteLastChar();
-
- if (out.file.empty())
+#else
+ if (!node.isDirectory())
return false;
-
- if (!Theme::themeConfigUseable(out.file, "", &type, &cfg))
+#endif
+
+ if (!Theme::themeConfigUseable(node, out.name))
return false;
- out.type = type;
-
- if (cfg.hasKey("name", "theme"))
- cfg.getKey("name", "theme", out.name);
- else
- out.name = out.file;
-
return true;
}
diff --git a/gui/themebrowser.h b/gui/themebrowser.h
index 509e9dc2eb..c33e239110 100644
--- a/gui/themebrowser.h
+++ b/gui/themebrowser.h
@@ -46,7 +46,6 @@ public:
private:
struct Entry {
Common::String name;
- Common::String type;
Common::String file;
};
@@ -57,7 +56,7 @@ private:
void updateListing();
- void addDir(ThList &list, const Common::FSNode &node, int level = 4);
+ void addDir(ThList &list, const Common::FSNode &node);
bool isTheme(const Common::FSNode &node, Entry &out);
};
diff --git a/gui/themes/classic080.ini b/gui/themes/classic080.ini
deleted file mode 100644
index 4138e24536..0000000000
--- a/gui/themes/classic080.ini
+++ /dev/null
@@ -1,469 +0,0 @@
-# $URL$
-# $Id$
-[theme]
-version=24
-type=classic
-name=Classic (ScummVM 0.8.0)
-
-[colors]
-color=104 104 104
-shadowcolor=64 64 64
-bgcolor=0 0 0
-textcolor=32 160 32
-textcolorhi=0 255 0
-
-[extra]
-font="builtin"
-blending=true
-
-[XxY]
-def_widgetSize=kBigWidgetSize
-def_buttonWidth=kBigButtonWidth
-def_buttonHeight=kBigButtonHeight
-def_sliderWidth=kBigSliderWidth
-def_sliderHeight=kBigSliderHeight
-def_kLineHeight=16
-def_kFontHeight=14
-def_insetX=10
-def_insetY=20
-def_insetW=(w - 2 * 10)
-def_insetH=(h - 2 * 40)
-def_gameOptionsLabelWidth=90
-def_tabPopupsLabelW=150
-def_aboutXOff=8
-def_aboutYOff=5
-def_aboutOuterBorder=80
-def_scummmainHOffset=12
-def_scummmainVSpace=7
-def_scummmainVAddOff=3
-def_scummmainButtonWidth=160
-def_scummmainButtonHeight=28
-def_scummhelpW=370
-def_scummhelpX=((w - scummhelpW) / 2)
-def_midiControlsSpacing=2
-def_vcAudioTabIndent=10
-def_vcAudioTabSpacing=4
-
-use=colors
-use=extra
-
-##### Widgets config
-ListWidget.leftPadding=4
-ListWidget.rightPadding=0
-ListWidget.topPadding=2
-ListWidget.bottomPadding=2
-ListWidget.hlLeftPadding=2
-ListWidget.hlRightPadding=1
-PopUpWidget.leftPadding=4
-PopUpWidget.rightPadding=0
-TabWidget.tabWidth=70
-TabWidget.tabHeight=21
-TabWidget.titleVPad=2
-
-###### chooser
-opHeight=(h * 7 / 10)
-useWithPrefix=chooser defaultChooser_
-
-##### browser
-brW=((w * 7) / 8)
-brH=((h * 9) / 10)
-browser=((w - brW) / 2) ((h - brH) / 2) brW brH
-set_parent=browser
-browser_headline=10 kLineHeight (parent.w - 2 * 10) kLineHeight
-browser_headline.align=kTextAlignCenter
-browser_path=10 prev.y2 prev.w prev.h
-browser_list=10 prev.y2 prev.w (parent.h - 3 * kLineHeight - buttonHeight - 14)
-browser_up=10 (parent.h - buttonHeight - 8) buttonWidth buttonHeight
-browser_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
-browser_choose=(prev.x2 + 10) prev.y prev.w prev.h
-
-##### launcher
-hBorder=10
-launcher_version=hBorder 8 (w - 2 * hBorder) kLineHeight
-launcher_version.align=kTextAlignCenter
-top=(h - 8 - buttonHeight)
-numButtons=3
-space=8
-butWidth=((w - 2 * hBorder - space * (numButtons - 1)) / numButtons)
-launcher_quit_button=hBorder top butWidth buttonHeight
-launcher_about_button=(prev.x2 + space) prev.y prev.w prev.h
-launcher_options_button=(prev.x2 + space) prev.y prev.w prev.h
-launcher_start_button=(prev.x2 + space) prev.y prev.w prev.h
-launcher_loadGame_button=(prev.x2 + space) prev.y prev.w prev.h
-top=(top - buttonHeight * 2)
-numButtons=3
-space=10
-butWidth=((w - 2 * hBorder - space * (numButtons - 1)) / numButtons)
-launcher_addGame_button=hBorder top butWidth buttonHeight
-launcher_editGame_button=(prev.x2 + space) prev.y prev.w prev.h
-launcher_removeGame_button=(prev.x2 + space) prev.y prev.w prev.h
-launcher_list=hBorder (kLineHeight + 16) (w - 2 * hBorder) (top - kLineHeight - 20)
-
-### global options
-globaloptions=insetX insetY insetW insetH
-set_parent=globaloptions
-vBorder=5
-globaloptions_tabwidget=0 vBorder parent.w (parent.h - buttonHeight - 8 - 2 * vBorder)
-
-# graphics tab
-opYoffset=vBorder
-opXoffset=0
-useWithPrefix=graphicsControls globaloptions_
-
-# audio tab
-opYoffset=vBorder
-useWithPrefix=audioControls globaloptions_
-useWithPrefix=subtitleControls globaloptions_
-
-# volume tab
-opYoffset=vBorder
-useWithPrefix=volumeControls globaloptions_
-
-# MIDI tab
-opYoffset=vBorder
-useWithPrefix=midiControls globaloptions_
-
-# paths tab
-yoffset=vBorder
-glOff=((buttonHeight - kLineHeight) / 2 + 2)
-globaloptions_savebutton=10 yoffset (buttonWidth + 5) buttonHeight
-globaloptions_savepath=(prev.x2 + 20) (yoffset + glOff) (parent.w - (prev.w + 20) - 15) kLineHeight
-yoffset=(yoffset + buttonHeight + 4)
-globaloptions_extrabutton=10 yoffset (buttonWidth + 5) buttonHeight
-globaloptions_extrapath=(prev.x2 + 20) (yoffset + glOff) (parent.w - (prev.w + 20) - 15) kLineHeight
-yoffset=(yoffset + buttonHeight + 4)
-globaloptions_themebutton=10 yoffset (buttonWidth + 5) buttonHeight
-globaloptions_themepath=(prev.x2 + 20) (yoffset + glOff) (parent.w - (prev.w + 20) - 15) kLineHeight
-yoffset=(yoffset + buttonHeight + 4)
-globaloptions_pluginsbutton=10 yoffset (buttonWidth + 5) buttonHeight
-globaloptions_pluginspath=(prev.x2 + 20) (yoffset + glOff) (parent.w - (prev.w + 20) - 15) kLineHeight
-yoffset=(yoffset + buttonHeight + 4)
-globaloptions_keysbutton=10 yoffset (buttonWidth + 5) buttonHeight
-
-# Misc options
-yoffset=vBorder
-glOff=((buttonHeight - kLineHeight) / 2 + 2)
-globaloptions_themebutton2=10 yoffset buttonWidth buttonHeight
-globaloptions_curtheme=(prev.x2 + 20) (yoffset + glOff) (parent.w - (prev.w + 20) - 10) kLineHeight
-yoffset=(yoffset + buttonHeight + 12)
-globaloptions_autosaveperiod=10 yoffset (parent.w - 10 - 25) (kLineHeight + 2)
-
-globaloptions_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
-globaloptions_ok=(prev.x2 + 10) prev.y prev.w prev.h
-
-### game options
-gameoptions=insetX insetY insetW insetH
-set_parent=gameoptions
-vBorder=5
-gox=5
-gow=(parent.w - 15)
-
-gameoptions_tabwidget=0 vBorder parent.w (parent.h - buttonHeight - 8 - 2 * vBorder)
-
-# game tab
-opYoffset=vBorder
-gameoptions_id=gox (opYoffset + 2) gameOptionsLabelWidth kLineHeight
-gameoptions_id.align=kTextAlignRight
-gameoptions_domain=prev.x2 (prev.y - 1) (parent.w - gameOptionsLabelWidth - 10 - gox) (prev.h + 2)
-opYoffset=(opYoffset + prev.h + 5)
-gameoptions_name=gox (opYoffset + 2) gameOptionsLabelWidth kLineHeight
-gameoptions_name.align=kTextAlignRight
-gameoptions_desc=prev.x2 (prev.y - 1) (parent.w - gameOptionsLabelWidth - 10 - gox) (prev.h + 2)
-opYoffset=(opYoffset + prev.h + 7)
-gameoptions_lang=gox (opYoffset - 1) gow (kLineHeight + 2)
-opYoffset=(opYoffset + prev.h + 5)
-gameoptions_platform=prev.x opYoffset prev.w prev.h
-opYoffset=(opYoffset + prev.h + 5)
-
-# paths tab
-opYoffset=vBorder
-goOff=((buttonHeight - kLineHeight) / 2 + 2)
-gameoptions_savepath=gox opYoffset (buttonWidth + 5) buttonHeight
-gameoptions_savepathText=(prev.x2 + 20) (opYoffset + goOff) (parent.w - self.x - 10) kLineHeight
-opYoffset=(opYoffset + buttonHeight + 4)
-gameoptions_extrapath=gox opYoffset (buttonWidth + 5) buttonHeight
-gameoptions_extrapathText=(prev.x2 + 20) (opYoffset + goOff) (parent.w - self.x - 10) kLineHeight
-opYoffset=(opYoffset + buttonHeight + 4)
-gameoptions_gamepath=gox opYoffset (buttonWidth + 5) buttonHeight
-gameoptions_gamepathText=(prev.x2 + 20) (opYoffset + goOff) (parent.w - self.x - 10) kLineHeight
-opYoffset=(opYoffset + buttonHeight + 4)
-
-# graphics tab
-opYoffset=vBorder
-opXoffset=gox
-gameoptions_graphicsCheckbox=gox opYoffset (parent.w - gox - 5) buttonHeight
-opYoffset=(opYoffset + buttonHeight)
-useWithPrefix=graphicsControls gameoptions_
-
-# audio tab
-opYoffset=vBorder
-gameoptions_audioCheckbox=gox opYoffset (parent.w - gox - 5) buttonHeight
-opYoffset=(opYoffset + buttonHeight)
-useWithPrefix=audioControls gameoptions_
-useWithPrefix=subtitleControls gameoptions_
-
-# volume tab
-opYoffset=vBorder
-gameoptions_volumeCheckbox=gox opYoffset (parent.w - gox - 5) buttonHeight
-opYoffset=(opYoffset + buttonHeight)
-useWithPrefix=volumeControls gameoptions_
-
-# midi tab
-opYoffset=vBorder
-gameoptions_midiCheckbox=gox opYoffset (parent.w - gox - 5) buttonHeight
-opYoffset=(opYoffset + buttonHeight)
-useWithPrefix=midiControls gameoptions_
-
-gameoptions_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
-gameoptions_ok=(prev.x2 + 10) prev.y prev.w prev.h
-
-### keys dialog
-keysdialog=(w / 20) (h / 10) (w - w / 10) (h - h / 5)
-set_parent=keysdialog
-keysdialog_map=(parent.w - buttonWidth - 10) 20 buttonWidth buttonHeight
-keysdialog_ok=prev.x (prev.y2 + 4) prev.w prev.h
-keysdialog_cancel=prev.x (prev.y2 + 4) prev.w prev.h
-keysdialog_list=10 10 (prev.x - 20) (parent.h - kLineHeight * 4 - self.y)
-keysdialog_action=prev.x (parent.h - kLineHeight * 3) (parent.w - self.x * 2) kLineHeight
-keysdialog_mapping=prev.x (prev.y + kLineHeight) prev.w prev.h
-
-### mass add dialog
-massadddialog=10 20 300 174
-set_parent=massadddialog
-massadddialog_caption=10 (10 + 1 * kLineHeight) (parent.w - 2*10) kLineHeight
-massadddialog_caption.align=kTextAlignCenter
-massadddialog_dirprogress=10 (10 + 3 * kLineHeight) prev.w prev.h
-massadddialog_dirprogress.align=kTextAlignCenter
-massadddialog_gameprogress=10 (10 + 4 * kLineHeight) prev.w prev.h
-massadddialog_gameprogress.align=kTextAlignCenter
-massadddialog_ok=((parent.w - (buttonWidth * 2)) / 2) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
-massadddialog_cancel=(prev.x2 + 10) prev.y prev.w prev.h
-
-
-##### SCUMM dialogs
-scummDummyDialog=0 80 0 16
-
-use=scummmain
-## Engine config
-# note that scummconfig size depends on overall height
-# hence it is on the end of the list
-opYoffset=8
-useWithPrefix=volumeControls scummconfig_
-useWithPrefix=subtitleControls scummconfig_
-opYoffset=(opYoffset + buttonHeight)
-opYoffset=(opYoffset + buttonHeight + 4)
-soWidth=(39 + 3 * buttonWidth)
-scummconfig_keys=(soWidth - 3 * (buttonWidth + 4) + 6) opYoffset (buttonWidth - 10) buttonHeight
-scummconfig_cancel=(prev.x2 + 4) prev.y (prev.w + 10) prev.h
-scummconfig_ok=(prev.x2 + 4) prev.y prev.w prev.h
-opYoffset=(opYoffset + buttonHeight)
-scummconfig=((w - soWidth) / 2) ((h - opYoffset) / 2) soWidth (opYoffset + 8)
-
-## Help
-scummHelpNumLines=15
-shH=(5 + (2 + scummHelpNumLines) * kFontHeight + buttonHeight + 7)
-scummhelp=scummhelpX ((h - shH) / 2) scummhelpW shH
-scummhelp_title=10 5 scummhelpW kFontHeight
-scummhelp_key.x=10
-scummhelp_key.yoffset=5
-scummhelp_key.w=80
-scummhelp_key.h=kFontHeight
-scummhelp_dsc.x=90
-scummhelp_dsc.yoffset=5
-scummhelp_dsc.w=(scummhelpW - 10 - 90)
-scummhelp_dsc.h=kFontHeight
-scummhelp_prev=10 (5 + kFontHeight * (scummHelpNumLines + 2) + 2) buttonWidth buttonHeight
-scummhelp_next=(prev.x2 + 8) prev.y prev.w prev.h
-scummhelp_close=(scummhelpW - 8 - buttonWidth) prev.y prev.w prev.h
-
-# Saveload dialog
-scummsaveload=8 8 (w - 2 * 8) (h - 16)
-set_parent=scummsaveload
-scummsaveload_title=10 2 (parent.w - 2 * 10 - 180) kLineHeight
-scummsaveload_title.align=kTextAlignCenter
-scummsaveload_list=10 18 prev.w (parent.h - 17 - buttonHeight - 8 - self.y)
-scummsaveload_thumbnail=(parent.w - (kThumbnailWidth + 18)) 22
-scummsaveload_thumbnail.hPad=4
-scummsaveload_thumbnail.vPad=4
-scummsaveload_thumbnail.fillR=0
-scummsaveload_thumbnail.fillG=0
-scummsaveload_thumbnail.fillB=0
-scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
-scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h
-scummsaveload_delete=prev.x (prev.y - 30) prev.w prev.h
-scummsaveload_extinfo.visible=true
-
-############################################
-[chooser]
-chooserW=(w - 2 * 8)
-chooser=((w - chooserW) / 2) ((h - opHeight) / 2) chooserW opHeight
-chooser_headline=10 6 (chooserW - 2 * 10) (kLineHeight)
-chooser_headline.align=kTextAlignCenter
-chooser_list=10 (6 + kLineHeight + 2) prev.w (opHeight - self.y - buttonHeight - 12)
-chooser_cancel=(chooserW - 2 * (buttonWidth + 10)) (opHeight - buttonHeight - 8) buttonWidth buttonHeight
-chooser_ok=(prev.x2 + 10) prev.y prev.w prev.h
-
-[graphicsControls]
-gcx=10
-gcw=(parent.w - 2 * 10)
-grModePopup=(gcx - 5) (opYoffset - 1) (gcw + 5) (kLineHeight + 2)
-opYoffset=(opYoffset + kLineHeight + 4)
-grRenderPopup=prev.x (opYoffset - 1) prev.w prev.h
-opYoffset=(opYoffset + kLineHeight + 4)
-grFullscreenCheckbox=gcx opYoffset (parent.w - gcx - 5) buttonHeight
-opYoffset=(opYoffset + buttonHeight)
-grAspectCheckbox=prev.x opYoffset prev.w prev.h
-opYoffset=(opYoffset + buttonHeight)
-
-[audioControls]
-aux=10
-auw=(parent.w - 2 * 10)
-auMidiPopup=(aux - 5) (opYoffset - 1) (auw + 5) (kLineHeight + 2)
-opYoffset=(opYoffset + buttonHeight + 4)
-auSampleRatePopup=(aux - 5) (opYoffset - 1) (auw + 5) (kLineHeight + 2)
-opYoffset=(opYoffset + buttonHeight + 4)
-
-[volumeControls]
-vctextw=(95 + vcAudioTabIndent)
-vcxoff=(opXoffset + vctextw + 15)
-vcx=(opXoffset + 10)
-vcMusicText=vcx (opYoffset + 2) vctextw kLineHeight
-vcMusicText.align=kTextAlignRight
-vcMusicSlider=vcxoff opYoffset sliderWidth sliderHeight
-vcMusicLabel=(vcxoff + prev.w + 10) (opYoffset + 2) 24 kLineHeight
-opYoffset=(opYoffset + sliderHeight + vcAudioTabSpacing)
-vcSfxText=vcx (opYoffset + 2) vctextw kLineHeight
-vcSfxText.align=kTextAlignRight
-vcSfxSlider=vcxoff opYoffset sliderWidth sliderHeight
-vcSfxLabel=(vcxoff + prev.w + 10) (opYoffset + 2) 24 kLineHeight
-opYoffset=(opYoffset + sliderHeight + vcAudioTabSpacing)
-vcSpeechText=vcx (opYoffset + 2) vctextw kLineHeight
-vcSpeechText.align=kTextAlignRight
-vcSpeechSlider=vcxoff opYoffset sliderWidth sliderHeight
-vcSpeechLabel=(vcxoff + prev.w + 10) (opYoffset + 2) 24 kLineHeight
-opYoffset=(opYoffset + sliderHeight + vcAudioTabSpacing)
-
-[midiControls]
-mcx=10
-mcFontButton=mcx opYoffset buttonWidth buttonHeight
-mcFontPath=(prev.x2 + 20) (opYoffset + 3) (parent.w - (buttonWidth + 20) - mcx - kLineHeight - 20) kLineHeight
-mcFontClearButton=(prev.x2 + 10) (opYoffset + 3) kLineHeight kLineHeight
-opYoffset=(opYoffset + buttonHeight + 2 * midiControlsSpacing)
-mcMixedCheckbox=mcx opYoffset (parent.w - mcx - 5) buttonHeight
-opYoffset=(opYoffset + buttonHeight + midiControlsSpacing)
-mcMt32Checkbox=mcx opYoffset prev.w buttonHeight
-opYoffset=(opYoffset + buttonHeight + midiControlsSpacing)
-mcGSCheckbox=mcx opYoffset prev.w buttonHeight
-opYoffset=(opYoffset + buttonHeight + midiControlsSpacing)
-mcMidiGainText=mcx (opYoffset + 2) 95 kLineHeight
-mcMidiGainText.align=kTextAlignRight
-mcMidiGainSlider=(prev.x2 + 10) opYoffset sliderWidth sliderHeight
-mcMidiGainLabel=(prev.x2 + 10) (opYoffset + 2) 40 kLineHeight
-opYoffset=(opYoffset + sliderHeight + midiControlsSpacing)
-
-[subtitleControls]
-sbx=(opXoffset + 10)
-sbYoff=(buttonHeight / 8)
-sbOff=((sliderHeight - kLineHeight) / 2 + 2)
-sbtextw=(100 + vcAudioTabIndent)
-opYoffset=(opYoffset + sbYoff)
-subToggleDesc=sbx (opYoffset + sbYoff) sbtextw buttonHeight
-subToggleDesc.align=kTextAlignRight
-subToggleButton=prev.x2 (opYoffset - sbYoff) (buttonWidth + 54) buttonHeight
-opYoffset=(opYoffset + buttonHeight + 6)
-subSubtitleSpeedDesc=sbx (opYoffset + sbOff) sbtextw kLineHeight
-subSubtitleSpeedDesc.align=kTextAlignRight
-subSubtitleSpeedSlider=prev.x2 opYoffset sliderWidth sliderHeight
-subSubtitleSpeedLabel=(prev.x2 + 10) (opYoffset + sbOff) 24 kLineHeight
-opYoffset=(opYoffset + sliderHeight + 8)
-
-[scummmain]
-## Main dialog
-# note that scummmain size depends on overall height
-smY=(scummmainVSpace + scummmainVAddOff)
-scummmain_resume=scummmainHOffset smY scummmainButtonWidth scummmainButtonHeight
-smY=(smY + scummmainButtonHeight + scummmainVAddOff)
-smY=(smY + scummmainVSpace)
-scummmain_load=prev.x smY prev.w prev.h
-smY=(smY + scummmainButtonHeight + scummmainVAddOff)
-scummmain_save=prev.x smY prev.w prev.h
-smY=(smY + scummmainButtonHeight + scummmainVAddOff)
-smY=(smY + scummmainVSpace)
-scummmain_options=prev.x smY prev.w prev.h
-smY=(smY + scummmainButtonHeight + scummmainVAddOff)
-scummmain_about=prev.x smY prev.w prev.h
-smY=(smY + scummmainButtonHeight + scummmainVAddOff)
-scummmain_help=prev.x smY prev.w prev.h
-smY=(smY + scummmainButtonHeight + scummmainVAddOff)
-smY=(smY + scummmainVSpace)
-scummmain_quit=prev.x smY prev.w prev.h
-smY=(smY + scummmainButtonHeight + scummmainVAddOff)
-smW=(scummmainButtonWidth + 2 * scummmainHOffset)
-smH=(smY + scummmainVSpace)
-scummmain=((w - smW) / 2) ((h - smH) / 2) smW smH
-
-# Define our classic greenish theme here
-[320xY]
-def_widgetSize=kNormalWidgetSize
-def_buttonWidth=kButtonWidth
-def_buttonHeight=kButtonHeight
-def_sliderWidth=kSliderWidth
-def_sliderHeight=kSliderHeight
-def_kLineHeight=12
-def_kFontHeight=10
-def_insetX=10
-def_insetY=10
-def_insetW=(w - 2 * 10)
-def_insetH=(h - 30)
-def_gameOptionsLabelWidth=60
-def_tabPopupsLabelW=100
-def_aboutXOff=3
-def_aboutYOff=2
-def_aboutOuterBorder=10
-def_scummmainHOffset=8
-def_scummmainVSpace=5
-def_scummmainVAddOff=2
-def_scummmainButtonWidth=90
-def_scummmainButtonHeight=16
-def_scummhelpX=5
-def_scummhelpW=(w - 2 * 5)
-def_midiControlsSpacing=1
-def_vcAudioTabIndent=0
-def_vcAudioTabSpacing=2
-use=XxY
-
-TabWidget.tabWidth=0
-TabWidget.tabHeight=16
-TabWidget.titleVPad=2
-# Scumm Saveload dialog
-scummsaveload=8 8 (w - 2 * 8) (h - 16)
-set_parent=scummsaveload
-scummsaveload_title=10 2 (parent.w - 2 * 10) kLineHeight
-scummsaveload_list=10 18 prev.w (parent.h - 17 - buttonHeight - 8 - self.y)
-scummsaveload_thumbnail=(parent.w - (kThumbnailWidth + 22)) 18
-scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
-scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h
-scummsaveload_delete=prev.x (prev.y - 30) prev.w prev.h
-scummsaveload_extinfo.visible=false
-
-# MM NES resolution
-[256x240]
-useAsIs=320xY
-
-# PSP GUI
-[480x272]
-def_buttonWidth=100
-def_buttonHeight=23
-def_insetX=20
-def_insetY=10
-def_insetW=(w - 2 * insetX)
-def_insetH=(h - 13 - insetY)
-def_launcherVersionX=50
-def_launcherVersionY=5
-def_midiControlsSpacing=2
-def_gameOptionsOverrideVPad=10
-def_aboutXOff=3
-def_aboutYOff=2
-def_aboutOuterBorder=10
-
-use=XxY
diff --git a/gui/themes/default.inc b/gui/themes/default.inc
new file mode 100644
index 0000000000..f2ef86d241
--- /dev/null
+++ b/gui/themes/default.inc
@@ -0,0 +1,1462 @@
+"<render_info> "
+"<palette> "
+"<color name = 'black' "
+"rgb = '0, 0, 0' "
+"/> "
+"<color name = 'lightgrey' "
+"rgb = '104, 104, 104' "
+"/> "
+"<color name = 'darkgrey' "
+"rgb = '64, 64, 64' "
+"/> "
+"<color name = 'green' "
+"rgb = '32, 160, 32' "
+"/> "
+"<color name = 'green2' "
+"rgb = '0, 255, 0' "
+"/> "
+"</palette> "
+"<fonts> "
+"<font id = 'text_default' "
+"file = 'default' "
+"color = 'green' "
+"/> "
+"<font id = 'text_hover' "
+"file = 'default' "
+"color = 'green2' "
+"/> "
+"<font id = 'text_disabled' "
+"file = 'default' "
+"color = 'lightgrey' "
+"/> "
+"<font id = 'text_inverted' "
+"file = 'default' "
+"color = 'black' "
+"/> "
+"<font id = 'text_button' "
+"file = 'default' "
+"color = 'green' "
+"/> "
+"<font id = 'text_button_hover' "
+"file = 'default' "
+"color = 'green2' "
+"/> "
+"<font id = 'text_normal' "
+"file = 'default' "
+"color = 'green' "
+"/> "
+"</fonts> "
+"<defaults fill = 'foreground' fg_color = 'darkgrey' bg_color = 'black' shadow = '0' bevel_color = 'lightgrey'/> "
+"<drawdata id = 'text_selection' cache = false> "
+"<drawstep func = 'square' "
+"fill = 'foreground' "
+"fg_color = 'green' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'mainmenu_bg' cache = false> "
+"<drawstep func = 'fill' "
+"fill = 'foreground' "
+"fg_color = 'black' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'special_bg' cache = false> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'separator' cache = false> "
+"<drawstep func = 'square' "
+"fill = 'foreground' "
+"height = '2' "
+"ypos = 'center' "
+"fg_color = 'lightgrey' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'scrollbar_base' cache = false> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'scrollbar_handle_hover' cache = false> "
+"<drawstep func = 'square' "
+"fill = 'foreground' "
+"fg_color = 'green2' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'scrollbar_handle_idle' cache = false> "
+"<drawstep func = 'square' "
+"fill = 'foreground' "
+"fg_color = 'green' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'scrollbar_button_idle' cache = false> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"fill = 'none' "
+"/> "
+"<drawstep func = 'triangle' "
+"fg_color = 'green' "
+"fill = 'foreground' "
+"width = 'auto' "
+"height = 'auto' "
+"xpos = 'center' "
+"ypos = 'center' "
+"orientation = 'top' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'scrollbar_button_hover' cache = false> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"fill = 'none' "
+"/> "
+"<drawstep func = 'triangle' "
+"fg_color = 'green2' "
+"fill = 'foreground' "
+"width = 'auto' "
+"height = 'auto' "
+"xpos = 'center' "
+"ypos = 'center' "
+"orientation = 'top' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'tab_active' cache = false> "
+"<text font = 'text_hover' "
+"vertical_align = 'center' "
+"horizontal_align = 'center' "
+"/> "
+"<drawstep func = 'tab' "
+"bevel = '2' "
+"radius = '0' "
+"fill = 'none' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'tab_inactive' cache = false> "
+"<text font = 'text_default' "
+"vertical_align = 'center' "
+"horizontal_align = 'center' "
+"/> "
+"<drawstep func = 'tab' "
+"bevel = '2' "
+"radius = '0' "
+"fill = 'none' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'tab_background' cache = false> "
+"</drawdata> "
+"<drawdata id = 'widget_slider' cache = false> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"fill = 'none' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'slider_disabled' cache = false> "
+"<drawstep func = 'square' "
+"fill = 'foreground' "
+"fg_color = 'lightgrey' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'slider_full' cache = false> "
+"<drawstep func = 'square' "
+"fill = 'foreground' "
+"fg_color = 'green' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'slider_hover' cache = false> "
+"<drawstep func = 'square' "
+"fill = 'foreground' "
+"fg_color = 'green2' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'widget_small' cache = false> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"fill = 'none' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'popup_idle' cache = false> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"fill = 'none' "
+"/> "
+"<drawstep func = 'triangle' "
+"fg_color = 'green' "
+"fill = 'foreground' "
+"width = 'height' "
+"height = 'auto' "
+"xpos = 'right' "
+"ypos = 'center' "
+"orientation = 'bottom' "
+"/> "
+"<text font = 'text_default' "
+"vertical_align = 'center' "
+"horizontal_align = 'left' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'popup_hover' cache = false> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"fill = 'none' "
+"/> "
+"<drawstep func = 'triangle' "
+"fg_color = 'green2' "
+"fill = 'foreground' "
+"width = 'height' "
+"height = 'auto' "
+"xpos = 'right' "
+"ypos = 'center' "
+"orientation = 'bottom' "
+"/> "
+"<text font = 'text_hover' "
+"vertical_align = 'center' "
+"horizontal_align = 'left' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'widget_textedit' cache = false> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"fill = 'none' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'plain_bg' cache = false> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'caret' cache = false> "
+"<drawstep func = 'square' "
+"fill = 'foreground' "
+"fg_color = 'lightgrey' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'default_bg' cache = false> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'button_idle' cache = false> "
+"<text font = 'text_button' "
+"vertical_align = 'center' "
+"horizontal_align = 'center' "
+"/> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"fill = 'none' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'button_hover' cache = false> "
+"<text font = 'text_button_hover' "
+"vertical_align = 'center' "
+"horizontal_align = 'center' "
+"/> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"fill = 'none' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'button_disabled' cache = false> "
+"<text font = 'text_disabled' "
+"vertical_align = 'center' "
+"horizontal_align = 'center' "
+"/> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"fill = 'none' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'checkbox_disabled' cache = false> "
+"<text font = 'text_disabled' "
+"vertical_align = 'top' "
+"horizontal_align = 'left' "
+"/> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"fill = 'none' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'checkbox_selected' cache = false> "
+"<text font = 'text_default' "
+"vertical_align = 'top' "
+"horizontal_align = 'left' "
+"/> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"fill = 'none' "
+"/> "
+"<drawstep func = 'cross' "
+"fill = 'foreground' "
+"stroke = '2' "
+"fg_color = 'green' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'checkbox_default' cache = false> "
+"<text font = 'text_default' "
+"vertical_align = 'top' "
+"horizontal_align = 'left' "
+"/> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"fill = 'none' "
+"/> "
+"</drawdata> "
+"<drawdata id = 'widget_default' cache = false> "
+"<drawstep func = 'bevelsq' "
+"bevel = '2' "
+"/> "
+"</drawdata> "
+"</render_info> "
+"<layout_info resolution = '-320xY, -256x240'> "
+"<globals> "
+"<def var = 'Line.Height' value = '16' /> "
+"<def var = 'Font.Height' value = '16' /> "
+"<def var = 'TabLabelWidth' value = '110' /> "
+"<def var = 'WidgetSize' value = 'kBigWidgetSize' /> "
+"<def var = 'About.OuterBorder' value = '80'/> "
+"<def var = 'PopUpWidget.labelSpacing' value = '10' /> "
+"<def var = 'Layout.Spacing' value = '8' /> "
+"<def var = 'ShowLauncherLogo' value = '0'/> "
+"<def var = 'ShowGlobalMenuLogo' value = '0'/> "
+"<def var = 'ScummSaveLoad.ExtInfo.Visible' value = '1'/> "
+"<widget name = 'OptionsLabel' "
+"size = '110, Globals.Line.Height' "
+"/> "
+"<widget name = 'SmallLabel' "
+"size = '24, Globals.Line.Height' "
+"/> "
+"<widget name = 'ShortOptionsLabel' "
+"size = '60, Globals.Line.Height' "
+"/> "
+"<widget name = 'Button' "
+"size = 'kBigButtonWidth, kBigButtonHeight' "
+"/> "
+"<widget name = 'Slider' "
+"size = 'kBigSliderWidth, kBigSliderHeight' "
+"/> "
+"<widget name = 'PopUp' "
+"size = '-1, 19' "
+"/> "
+"<widget name = 'Checkbox' "
+"size = '-1, 14' "
+"/> "
+"<widget name = 'ListWidget' "
+"padding = '5, 0, 8, 0' "
+"/> "
+"<widget name = 'PopUpWidget' "
+"padding = '7, 5, 0, 0' "
+"/> "
+"<widget name = 'EditTextWidget' "
+"padding = '5, 5, 0, 0' "
+"/> "
+"<widget name = 'Console' "
+"padding = '7, 5, 5, 5' "
+"/> "
+"<widget name = 'TabWidget.Tab' "
+"size = '75, 27' "
+"padding = '0, 0, 8, 0' "
+"/> "
+"<widget name = 'TabWidget.NavButton' "
+"size = '15, 18' "
+"padding = '0, 3, 4, 0' "
+"/> "
+"</globals> "
+"<dialog name = 'Launcher' overlays = 'screen'> "
+"<layout type = 'vertical' center = 'true' padding = '16, 16, 8, 8'> "
+"<widget name = 'Version' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<widget name = 'GameList'/> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10'> "
+"<widget name = 'LoadGameButton' "
+"height = '20' "
+"/> "
+"<widget name = 'AddGameButton' "
+"height = '20' "
+"/> "
+"<widget name = 'EditGameButton' "
+"height = '20' "
+"/> "
+"<widget name = 'RemoveGameButton' "
+"height = '20' "
+"/> "
+"</layout> "
+"<space size = '12'/> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10'> "
+"<widget name = 'QuitButton' "
+"height = '20' "
+"/> "
+"<widget name = 'AboutButton' "
+"height = '20' "
+"/> "
+"<widget name = 'OptionsButton' "
+"height = '20' "
+"/> "
+"<widget name = 'StartButton' "
+"height = '20' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'Browser' overlays = 'Dialog.Launcher.GameList' shading = 'dim'> "
+"<layout type = 'vertical' padding = '8, 8, 8, 8'> "
+"<widget name = 'Headline' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<widget name = 'Path' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<widget name = 'List'/> "
+"<layout type = 'horizontal' padding = '0, 0, 16, 0'> "
+"<widget name = 'Up' "
+"type = 'Button' "
+"/> "
+"<space/> "
+"<widget name = 'Cancel' "
+"type = 'Button' "
+"/> "
+"<widget name = 'Choose' "
+"type = 'Button' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GlobalOptions' overlays = 'Dialog.Launcher.GameList' shading = 'dim'> "
+"<layout type = 'vertical' padding = '0, 0, 0, 0'> "
+"<widget name = 'TabWidget'/> "
+"<layout type = 'horizontal' padding = '16, 16, 16, 16'> "
+"<space/> "
+"<widget name = 'Cancel' "
+"type = 'Button' "
+"/> "
+"<widget name = 'Ok' "
+"type = 'Button' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GlobalOptions_Graphics' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<widget name = 'grModePopup' "
+"type = 'PopUp' "
+"/> "
+"<widget name = 'grRenderPopup' "
+"type = 'PopUp' "
+"/> "
+"<widget name = 'grAspectCheckbox' "
+"type = 'Checkbox' "
+"/> "
+"<widget name = 'grFullscreenCheckbox' "
+"type = 'Checkbox' "
+"/> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GlobalOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<widget name = 'auMidiPopup' "
+"type = 'PopUp' "
+"/> "
+"<widget name = 'auSampleRatePopup' "
+"type = 'PopUp' "
+"/> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0'> "
+"<widget name = 'subToggleDesc' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'subToggleButton' "
+"width = '150' "
+"height = 'Globals.Slider.Height' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0'> "
+"<widget name = 'subSubtitleSpeedDesc' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'subSubtitleSpeedSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'subSubtitleSpeedLabel' "
+"type = 'SmallLabel' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GlobalOptions_Volume' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0'> "
+"<widget name = 'vcMusicText' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'vcMusicSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'vcMusicLabel' "
+"type = 'SmallLabel' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0'> "
+"<widget name = 'vcSfxText' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'vcSfxSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'vcSfxLabel' "
+"type = 'SmallLabel' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0'> "
+"<widget name = 'vcSpeechText' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'vcSpeechSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'vcSpeechLabel' "
+"type = 'SmallLabel' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GlobalOptions_MIDI' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0'> "
+"<widget name = 'mcFontButton' "
+"type = 'Button' "
+"/> "
+"<widget name = 'mcFontPath' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<widget name = 'mcFontClearButton' "
+"height = 'Globals.Line.Height' "
+"width = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"<widget name = 'mcMixedCheckbox' "
+"type = 'Checkbox' "
+"/> "
+"<widget name = 'mcMt32Checkbox' "
+"type = 'Checkbox' "
+"/> "
+"<widget name = 'mcGSCheckbox' "
+"type = 'Checkbox' "
+"/> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0'> "
+"<widget name = 'mcMidiGainText' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'mcMidiGainSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'mcMidiGainLabel' "
+"width = '32' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GlobalOptions_Paths' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'> "
+"<widget name = 'SaveButton' "
+"type = 'Button' "
+"/> "
+"<widget name = 'SavePath' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'> "
+"<widget name = 'ThemeButton' "
+"type = 'Button' "
+"/> "
+"<widget name = 'ThemePath' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'> "
+"<widget name = 'ExtraButton' "
+"type = 'Button' "
+"/> "
+"<widget name = 'ExtraPath' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'> "
+"<widget name = 'PluginsButton' "
+"type = 'Button' "
+"/> "
+"<widget name = 'PluginsPath' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GlobalOptions_Misc' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'> "
+"<widget name = 'ThemeButton' "
+"type = 'Button' "
+"/> "
+"<widget name = 'CurTheme' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"<widget name = 'Renderer' "
+"type = 'PopUp' "
+"/> "
+"<widget name = 'AutosavePeriod' "
+"type = 'PopUp' "
+"/> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GameOptions' overlays = 'Dialog.Launcher.GameList' shading = 'dim'> "
+"<layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '16'> "
+"<widget name = 'TabWidget'/> "
+"<layout type = 'horizontal' padding = '16, 16, 16, 4'> "
+"<space/> "
+"<widget name = 'Cancel' "
+"type = 'Button' "
+"/> "
+"<widget name = 'Ok' "
+"type = 'Button' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GameOptions_Graphics' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<widget name = 'EnableTabCheckbox' "
+"type = 'Checkbox' "
+"/> "
+"<import layout = 'Dialog.GlobalOptions_Graphics' /> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GameOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<widget name = 'EnableTabCheckbox' "
+"type = 'Checkbox' "
+"/> "
+"<import layout = 'Dialog.GlobalOptions_Audio' /> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GameOptions_MIDI' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<widget name = 'EnableTabCheckbox' "
+"type = 'Checkbox' "
+"/> "
+"<import layout = 'Dialog.GlobalOptions_MIDI' /> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GameOptions_Volume' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<widget name = 'EnableTabCheckbox' "
+"type = 'Checkbox' "
+"/> "
+"<import layout = 'Dialog.GlobalOptions_Volume' /> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GameOptions_Game' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16'> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'> "
+"<widget name = 'Id' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'Domain' "
+"type = 'PopUp' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'> "
+"<widget name = 'Name' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'Desc' "
+"type = 'PopUp' "
+"/> "
+"</layout> "
+"<widget name = 'Lang' "
+"type = 'PopUp' "
+"/> "
+"<widget name = 'Platform' "
+"type = 'PopUp' "
+"/> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GameOptions_Paths' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16'> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'> "
+"<widget name = 'Savepath' "
+"type = 'Button' "
+"/> "
+"<widget name = 'SavepathText' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'> "
+"<widget name = 'Extrapath' "
+"type = 'Button' "
+"/> "
+"<widget name = 'ExtrapathText' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'> "
+"<widget name = 'Gamepath' "
+"type = 'Button' "
+"/> "
+"<widget name = 'GamepathText' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GlobalMenu' overlays = 'screen_center'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' center = 'true'> "
+"<widget name = 'Title' "
+"width = '210' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<widget name = 'Version' "
+"width = '210' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<widget name = 'Resume' "
+"width = '150' "
+"height = 'Globals.Button.Height' "
+"/> "
+"<space size = '10'/> "
+"<widget name = 'Options' "
+"width = '150' "
+"height = 'Globals.Button.Height' "
+"/> "
+"<widget name = 'About' "
+"width = '150' "
+"height = 'Globals.Button.Height' "
+"/> "
+"<space size = '10'/> "
+"<widget name = 'RTL' "
+"width = '150' "
+"height = 'Globals.Button.Height' "
+"/> "
+"<widget name = 'Quit' "
+"width = '150' "
+"height = 'Globals.Button.Height' "
+"/> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'ScummMain' overlays = 'screen_center'> "
+"<layout type = 'vertical' padding = '8, 8, 8, 8'> "
+"<widget name = 'Resume' "
+"type = 'Button' "
+"/> "
+"<space size = '15'/> "
+"<widget name = 'Load' "
+"type = 'Button' "
+"/> "
+"<widget name = 'Save' "
+"type = 'Button' "
+"/> "
+"<space size = '15'/> "
+"<widget name = 'Options' "
+"type = 'Button' "
+"/> "
+"<widget name = 'Help' "
+"type = 'Button' "
+"/> "
+"<widget name = 'About' "
+"type = 'Button' "
+"/> "
+"<space size = '15'/> "
+"<widget name = 'Quit' "
+"type = 'Button' "
+"/> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'ScummConfig' overlays = 'screen_center'> "
+"<layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'> "
+"<widget name = 'vcMusicText' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'vcMusicSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'vcMusicLabel' "
+"type = 'SmallLabel' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'> "
+"<widget name = 'vcSfxText' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'vcSfxSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'vcSfxLabel' "
+"type = 'SmallLabel' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'> "
+"<widget name = 'vcSpeechText' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'vcSpeechSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'vcSpeechLabel' "
+"type = 'SmallLabel' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'> "
+"<widget name = 'subToggleDesc' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'subToggleButton' "
+"width = '158' "
+"height = 'Globals.Slider.Height' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'> "
+"<widget name = 'subSubtitleSpeedDesc' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'subSubtitleSpeedSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'subSubtitleSpeedLabel' "
+"type = 'SmallLabel' "
+"/> "
+"</layout> "
+"<space size = '60'/> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'> "
+"<space size = 'Globals.Button.Width' /> "
+"<widget name = 'Cancel' "
+"type = 'Button' "
+"/> "
+"<widget name = 'Ok' "
+"type = 'Button' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'ScummSaveLoad' overlays = 'screen' inset = '16'> "
+"<layout type = 'vertical' padding = '8, 8, 8, 32' center = 'true'> "
+"<widget name = 'Title' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 16' spacing = '16'> "
+"<widget name = 'List' /> "
+"<widget name = 'Thumbnail' "
+"width = '180' "
+"height = '200' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0'> "
+"<space/> "
+"<widget name = 'Delete' "
+"type = 'Button' "
+"/> "
+"<space size = '32'/> "
+"<widget name = 'Cancel' "
+"type = 'Button' "
+"/> "
+"<widget name = 'Choose' "
+"type = 'Button' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'ScummHelp' overlays = 'screen_center'> "
+"<layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'> "
+"<widget name = 'Title' "
+"width = '320' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<widget name = 'HelpText' "
+"height = '220' "
+"/> "
+"<layout type = 'horizontal' padding = '0, 0, 16, 0'> "
+"<widget name = 'Prev' "
+"type = 'Button' "
+"/> "
+"<widget name = 'Next' "
+"type = 'Button' "
+"/> "
+"<space size = '32'/> "
+"<widget name = 'Close' "
+"type = 'Button' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"</layout_info> "
+"<layout_info resolution = '320xY, 256x240'> "
+"<globals> "
+"<def var = 'Line.Height' value = '12' /> "
+"<def var = 'Font.Height' value = '10' /> "
+"<def var = 'TabLabelWidth' value = '100' /> "
+"<def var = 'WidgetSize' value = 'kNormalWidgetSize' /> "
+"<def var = 'About.OuterBorder' value = '10'/> "
+"<def var = 'PopUpWidget.labelSpacing' value = '6' /> "
+"<def var = 'Layout.Spacing' value = '8'/> "
+"<def var = 'ShowLauncherLogo' value = '0'/> "
+"<def var = 'ShowGlobalMenuLogo' value = '0'/> "
+"<def var = 'ScummSaveLoad.ExtInfo.Visible' value = '0'/> "
+"<widget name = 'Button' "
+"size = 'kButtonWidth, kButtonHeight' "
+"/> "
+"<widget name = 'Slider' "
+"size = 'kSliderWidth, kSliderHeight' "
+"/> "
+"<widget name = 'OptionsLabel' "
+"size = '110, Globals.Line.Height' "
+"/> "
+"<widget name = 'SmallLabel' "
+"size = '18, Globals.Line.Height' "
+"/> "
+"<widget name = 'PopUp' "
+"size = '-1, 15' "
+"/> "
+"<widget name = 'Checkbox' "
+"size = '-1, Globals.Line.Height' "
+"/> "
+"<widget name = 'ListWidget' "
+"padding = '5, 0, 8, 0' "
+"/> "
+"<widget name = 'PopUpWidget' "
+"padding = '7, 5, 0, 0' "
+"/> "
+"<widget name = 'EditTextWidget' "
+"padding = '5, 5, 0, 0' "
+"/> "
+"<widget name = 'Console' "
+"padding = '7, 5, 5, 5' "
+"/> "
+"<widget name = 'TabWidget.Tab' "
+"size = '45, 16' "
+"padding = '0, 0, 2, 0' "
+"/> "
+"<widget name = 'TabWidget.NavButton' "
+"size = '32, 18' "
+"padding = '0, 3, 4, 0' "
+"/> "
+"</globals> "
+"<dialog name = 'Launcher' overlays = 'screen'> "
+"<layout type = 'vertical' center = 'true' padding = '8, 8, 4, 4'> "
+"<widget name = 'Version' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<widget name = 'GameList'/> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10'> "
+"<widget name = 'LoadGameButton' "
+"height = '12' "
+"/> "
+"<widget name = 'AddGameButton' "
+"height = '12' "
+"/> "
+"<widget name = 'EditGameButton' "
+"height = '12' "
+"/> "
+"<widget name = 'RemoveGameButton' "
+"height = '12' "
+"/> "
+"</layout> "
+"<space size = '4'/> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10'> "
+"<widget name = 'QuitButton' "
+"height = '12' "
+"/> "
+"<widget name = 'AboutButton' "
+"height = '12' "
+"/> "
+"<widget name = 'OptionsButton' "
+"height = '12' "
+"/> "
+"<widget name = 'StartButton' "
+"height = '12' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'Browser' overlays = 'screen' inset = '16' shading = 'dim'> "
+"<layout type = 'vertical' padding = '8, 8, 8, 8'> "
+"<widget name = 'Headline' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<widget name = 'Path' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<widget name = 'List'/> "
+"<layout type = 'horizontal' padding = '0, 0, 16, 0'> "
+"<widget name = 'Up' "
+"type = 'Button' "
+"/> "
+"<space/> "
+"<widget name = 'Cancel' "
+"type = 'Button' "
+"/> "
+"<widget name = 'Choose' "
+"type = 'Button' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GlobalOptions' overlays = 'screen' inset = '16' shading = 'dim'> "
+"<layout type = 'vertical' padding = '0, 0, 0, 0'> "
+"<widget name = 'TabWidget'/> "
+"<layout type = 'horizontal' padding = '8, 8, 8, 8'> "
+"<space/> "
+"<widget name = 'Cancel' "
+"type = 'Button' "
+"/> "
+"<widget name = 'Ok' "
+"type = 'Button' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GlobalOptions_Graphics' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<widget name = 'grModePopup' "
+"type = 'PopUp' "
+"/> "
+"<widget name = 'grRenderPopup' "
+"type = 'PopUp' "
+"/> "
+"<widget name = 'grAspectCheckbox' "
+"type = 'Checkbox' "
+"/> "
+"<widget name = 'grFullscreenCheckbox' "
+"type = 'Checkbox' "
+"/> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GlobalOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<widget name = 'auMidiPopup' "
+"type = 'PopUp' "
+"/> "
+"<widget name = 'auSampleRatePopup' "
+"type = 'PopUp' "
+"/> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0'> "
+"<widget name = 'subToggleDesc' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'subToggleButton' "
+"width = 'Globals.Slider.Width' "
+"height = 'Globals.Slider.Height' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0'> "
+"<widget name = 'subSubtitleSpeedDesc' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'subSubtitleSpeedSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'subSubtitleSpeedLabel' "
+"type = 'SmallLabel' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GlobalOptions_Volume' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0'> "
+"<widget name = 'vcMusicText' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'vcMusicSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'vcMusicLabel' "
+"type = 'SmallLabel' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0'> "
+"<widget name = 'vcSfxText' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'vcSfxSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'vcSfxLabel' "
+"type = 'SmallLabel' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0'> "
+"<widget name = 'vcSpeechText' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'vcSpeechSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'vcSpeechLabel' "
+"type = 'SmallLabel' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GlobalOptions_MIDI' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0'> "
+"<widget name = 'mcFontButton' "
+"type = 'Button' "
+"/> "
+"<widget name = 'mcFontPath' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<widget name = 'mcFontClearButton' "
+"height = 'Globals.Line.Height' "
+"width = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"<widget name = 'mcMixedCheckbox' "
+"type = 'Checkbox' "
+"/> "
+"<widget name = 'mcMt32Checkbox' "
+"type = 'Checkbox' "
+"/> "
+"<widget name = 'mcGSCheckbox' "
+"type = 'Checkbox' "
+"/> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0'> "
+"<widget name = 'mcMidiGainText' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'mcMidiGainSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'mcMidiGainLabel' "
+"width = '32' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GlobalOptions_Paths' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'> "
+"<widget name = 'SaveButton' "
+"type = 'Button' "
+"/> "
+"<widget name = 'SavePath' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'> "
+"<widget name = 'ThemeButton' "
+"type = 'Button' "
+"/> "
+"<widget name = 'ThemePath' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'> "
+"<widget name = 'ExtraButton' "
+"type = 'Button' "
+"/> "
+"<widget name = 'ExtraPath' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'> "
+"<widget name = 'PluginsButton' "
+"type = 'Button' "
+"/> "
+"<widget name = 'PluginsPath' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GlobalOptions_Misc' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'> "
+"<widget name = 'ThemeButton' "
+"type = 'Button' "
+"/> "
+"<widget name = 'CurTheme' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"<widget name = 'Renderer' "
+"type = 'PopUp' "
+"/> "
+"<widget name = 'AutosavePeriod' "
+"type = 'PopUp' "
+"/> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GameOptions' overlays = 'screen' inset = '16' shading = 'dim'> "
+"<layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '16'> "
+"<widget name = 'TabWidget'/> "
+"<layout type = 'horizontal' padding = '8, 8, 8, 8'> "
+"<space/> "
+"<widget name = 'Cancel' "
+"type = 'Button' "
+"/> "
+"<widget name = 'Ok' "
+"type = 'Button' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GameOptions_Graphics' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<widget name = 'EnableTabCheckbox' "
+"type = 'Checkbox' "
+"/> "
+"<import layout = 'Dialog.GlobalOptions_Graphics' /> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GameOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<widget name = 'EnableTabCheckbox' "
+"type = 'Checkbox' "
+"/> "
+"<import layout = 'Dialog.GlobalOptions_Audio' /> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GameOptions_MIDI' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<widget name = 'EnableTabCheckbox' "
+"type = 'Checkbox' "
+"/> "
+"<import layout = 'Dialog.GlobalOptions_MIDI' /> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GameOptions_Volume' overlays = 'Dialog.GlobalOptions.TabWidget'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> "
+"<widget name = 'EnableTabCheckbox' "
+"type = 'Checkbox' "
+"/> "
+"<import layout = 'Dialog.GlobalOptions_Volume' /> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GameOptions_Game' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16'> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'> "
+"<widget name = 'Id' "
+"width = '35' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<widget name = 'Domain' "
+"type = 'PopUp' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'> "
+"<widget name = 'Name' "
+"width = '35' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<widget name = 'Desc' "
+"type = 'PopUp' "
+"/> "
+"</layout> "
+"<space size = '8'/> "
+"<widget name = 'Lang' "
+"type = 'PopUp' "
+"/> "
+"<widget name = 'Platform' "
+"type = 'PopUp' "
+"/> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GameOptions_Paths' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'> "
+"<layout type = 'vertical' padding = '16, 16, 16, 16'> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'> "
+"<widget name = 'Savepath' "
+"type = 'Button' "
+"/> "
+"<widget name = 'SavepathText' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'> "
+"<widget name = 'Extrapath' "
+"type = 'Button' "
+"/> "
+"<widget name = 'ExtrapathText' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'> "
+"<widget name = 'Gamepath' "
+"type = 'Button' "
+"/> "
+"<widget name = 'GamepathText' "
+"height = 'Globals.Line.Height' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'GlobalMenu' overlays = 'screen_center'> "
+"<layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'> "
+"<widget name = 'Title' "
+"width = '120' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<widget name = 'Version' "
+"width = '120' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<widget name = 'Resume' "
+"width = '70' "
+"height = 'Globals.Button.Height' "
+"/> "
+"<space size = '4'/> "
+"<widget name = 'Options' "
+"width = '70' "
+"height = 'Globals.Button.Height' "
+"/> "
+"<widget name = 'About' "
+"width = '70' "
+"height = 'Globals.Button.Height' "
+"/> "
+"<space size = '4'/> "
+"<widget name = 'RTL' "
+"width = '70' "
+"height = 'Globals.Button.Height' "
+"/> "
+"<widget name = 'Quit' "
+"width = '70' "
+"height = 'Globals.Button.Height' "
+"/> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'ScummMain' overlays = 'screen_center'> "
+"<layout type = 'vertical' padding = '8, 8, 8, 8'> "
+"<widget name = 'Resume' "
+"type = 'Button' "
+"/> "
+"<space size = '4'/> "
+"<widget name = 'Load' "
+"type = 'Button' "
+"/> "
+"<widget name = 'Save' "
+"type = 'Button' "
+"/> "
+"<space size = '4'/> "
+"<widget name = 'Options' "
+"type = 'Button' "
+"/> "
+"<widget name = 'Help' "
+"type = 'Button' "
+"/> "
+"<widget name = 'About' "
+"type = 'Button' "
+"/> "
+"<space size = '4'/> "
+"<widget name = 'Quit' "
+"type = 'Button' "
+"/> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'ScummConfig' overlays = 'screen_center'> "
+"<layout type = 'vertical' padding = '8, 8, 8, 8'> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'> "
+"<widget name = 'vcMusicText' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'vcMusicSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'vcMusicLabel' "
+"type = 'SmallLabel' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'> "
+"<widget name = 'vcSfxText' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'vcSfxSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'vcSfxLabel' "
+"type = 'SmallLabel' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'> "
+"<widget name = 'vcSpeechText' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'vcSpeechSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'vcSpeechLabel' "
+"type = 'SmallLabel' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'> "
+"<widget name = 'subToggleDesc' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'subToggleButton' "
+"width = '92' "
+"height = 'Globals.Slider.Height' "
+"/> "
+"</layout> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'> "
+"<widget name = 'subSubtitleSpeedDesc' "
+"type = 'OptionsLabel' "
+"/> "
+"<widget name = 'subSubtitleSpeedSlider' "
+"type = 'Slider' "
+"/> "
+"<widget name = 'subSubtitleSpeedLabel' "
+"type = 'SmallLabel' "
+"/> "
+"</layout> "
+"<space size = '20'/> "
+"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'> "
+"<space size = 'Globals.Button.Width' /> "
+"<widget name = 'Cancel' "
+"type = 'Button' "
+"/> "
+"<widget name = 'Ok' "
+"type = 'Button' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'ScummSaveLoad' overlays = 'screen' inset = '16'> "
+"<layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'> "
+"<widget name = 'Title' height = 'Globals.Line.Height'/> "
+"<widget name = 'List' /> "
+"<layout type = 'horizontal' padding = '0, 0, 16, 0'> "
+"<space/> "
+"<widget name = 'Delete' "
+"type = 'Button' "
+"/> "
+"<space size = '16'/> "
+"<widget name = 'Cancel' "
+"type = 'Button' "
+"/> "
+"<widget name = 'Choose' "
+"type = 'Button' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"<dialog name = 'ScummHelp' overlays = 'screen_center'> "
+"<layout type = 'vertical' padding = '8, 8, 8, 8'> "
+"<widget name = 'Title' "
+"width = '180' "
+"height = 'Globals.Line.Height' "
+"/> "
+"<widget name = 'HelpText' "
+"height = '170' "
+"/> "
+"<layout type = 'horizontal' padding = '0, 0, 4, 0'> "
+"<widget name = 'Prev' "
+"type = 'Button' "
+"/> "
+"<widget name = 'Next' "
+"type = 'Button' "
+"/> "
+"<space size = '32'/> "
+"<widget name = 'Close' "
+"type = 'Button' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
+"</layout_info> "
diff --git a/gui/themes/modern.ini b/gui/themes/modern.ini
deleted file mode 100644
index e1712c5608..0000000000
--- a/gui/themes/modern.ini
+++ /dev/null
@@ -1,649 +0,0 @@
-# $URL$
-# $Id$
-[theme]
-version=24
-type=modern
-name=Modern Style
-
-[pixmaps]
-pix_dialog_corner="dialog_bkgd_corner.bmp"
-pix_dialog_top="dialog_bkgd_top.bmp"
-pix_dialog_left="dialog_bkgd_left.bmp"
-pix_dialog_bkgd="dialog_bkgd.bmp"
-
-pix_widget_corner="widget_bkgd_corner.bmp"
-pix_widget_top="widget_bkgd_top.bmp"
-pix_widget_left="widget_bkgd_left.bmp"
-pix_widget_bkgd="widget_bkgd.bmp"
-
-pix_widget_small_corner="widget_small_bkgd_corner.bmp"
-pix_widget_small_top="widget_small_bkgd_top.bmp"
-pix_widget_small_left="widget_small_bkgd_left.bmp"
-pix_widget_small_bkgd="widget_small_bkgd.bmp"
-
-pix_checkbox_empty="checkbox_empty.bmp"
-pix_checkbox_checked="checkbox_checked.bmp"
-
-pix_widget_arrow="widget_arrow.bmp"
-
-pix_tab_corner="button_bkgd_corner.bmp"
-pix_tab_top="widget_bkgd_top.bmp"
-pix_tab_left="widget_bkgd_left.bmp"
-pix_tab_bkgd="widget_bkgd.bmp"
-
-pix_slider_bkgd_corner="button_bkgd_corner.bmp"
-pix_slider_bkgd_top="button_bkgd_top.bmp"
-pix_slider_bkgd_left="button_bkgd_left.bmp"
-pix_slider_bkgd_bkgd="button_bkgd.bmp"
-
-pix_slider_corner="button_bkgd_corner.bmp"
-pix_slider_top="button_bkgd_top.bmp"
-pix_slider_left="button_bkgd_left.bmp"
-pix_slider_bkgd="button_bkgd.bmp"
-
-pix_scrollbar_bkgd_corner="widget_small_bkgd_corner.bmp"
-pix_scrollbar_bkgd_top="widget_small_bkgd_top.bmp"
-pix_scrollbar_bkgd_left="widget_small_bkgd_left.bmp"
-pix_scrollbar_bkgd_bkgd="widget_small_bkgd.bmp"
-
-pix_scrollbar_corner="widget_bkgd_corner.bmp"
-pix_scrollbar_top="widget_bkgd_top.bmp"
-pix_scrollbar_left="widget_bkgd_left.bmp"
-pix_scrollbar_bkgd="widget_bkgd.bmp"
-
-pix_button_corner="button_bkgd_corner.bmp"
-pix_button_top="button_bkgd_top.bmp"
-pix_button_left="button_bkgd_left.bmp"
-pix_button_bkgd="button_bkgd.bmp"
-
-pix_popupwidget_corner="button_bkgd_corner.bmp"
-pix_popupwidget_top="button_bkgd_top.bmp"
-pix_popupwidget_left="button_bkgd_left.bmp"
-pix_popupwidget_bkgd="button_bkgd.bmp"
-
-pix_edittext_bkgd_corner="button_bkgd_corner.bmp"
-pix_edittext_bkgd_top="button_bkgd_top.bmp"
-pix_edittext_bkgd_left="button_bkgd_left.bmp"
-pix_edittext_bkgd_bkgd="button_bkgd.bmp"
-
-pix_theme_logo="logo.bmp"
-pix_theme_logo_small="logo_small.bmp"
-
-pix_cursor_image="cursor.bmp"
-
-[colors]
-main_dialog_start=210 114 10
-main_dialog_end=239 196 24
-
-dialog_start=246 224 139
-dialog_end=251 241 206
-
-color_state_disabled=192 192 192
-color_state_highlight=100 162 8
-color_state_enabled=0 0 0
-
-color_transparency=255 0 255
-
-text_inverted_background=100 162 8
-text_inverted_color=0 0 0
-
-widget_bkgd_start=246 224 139
-widget_bkgd_end=251 241 206
-widget_bkgd_small_start=246 224 139
-widget_bkgd_small_end=251 241 206
-
-button_bkgd_start=203 126 107
-button_bkgd_end=169 42 12
-button_bkgd_highlight_start=255 210 200
-button_bkgd_highlight_end=200 70 50
-button_text_enabled=255 255 255
-button_text_disabled=192 192 192
-button_text_highlight=255 214 84
-
-slider_background_start=247 228 166
-slider_background_end=247 228 166
-slider_start=203 126 107
-slider_end=169 42 12
-slider_highlight_start=255 210 200
-slider_highlight_end=200 70 50
-
-tab_background_start=232 180 80
-tab_background_end=232 180 80
-
-tab_active_start=246 224 139
-tab_active_end=251 241 206
-tab_inactive_start=239 202 109
-tab_inactive_end=239 202 109
-
-scrollbar_background_start=247 228 166
-scrollbar_background_end=247 228 166
-scrollbar_button_start=247 228 166
-scrollbar_button_end=247 228 166
-scrollbar_slider_start=203 126 107
-scrollbar_slider_end=169 42 12
-scrollbar_button_highlight_start=255 210 200
-scrollbar_button_highlight_end=200 70 50
-scrollbar_slider_highlight_start=255 210 200
-scrollbar_slider_highlight_end=200 70 50
-
-popupwidget_start=251 241 206
-popupwidget_end=251 241 206
-popupwidget_highlight_start=246 224 139
-popupwidget_highlight_end=251 241 206
-
-edittext_background_start=247 228 166
-edittext_background_end=247 228 166
-
-caret_color=0 0 0
-
-[gradients]
-gradient_dialog_main=1
-gradient_dialog=4
-gradient_dialog_special=4
-
-gradient_widget_small=9
-gradient_widget=9
-
-gradient_button=1
-
-gradient_slider=1
-gradient_slider_bkgd=1
-
-gradient_tab=4
-
-gradient_scrollbar=1
-gradient_scrollbar_background=1
-
-gradient_popupwidget=1
-
-gradient_edittext=1
-
-[extra]
-shadow_left_width=2
-shadow_right_width=4
-shadow_top_height=2
-shadow_bottom_height=4
-inactive_dialog_shading=kShadingDim
-shading_dim_percent=50
-fontfile_normal="helvr12-l1.bdf"
-fontfile_fixed_normal="courr12-l1.bdf"
-cursor_hotspot_x=0
-cursor_hotspot_y=0
-cursor_targetScale=3
-
-[XxY]
-skipFor=320xY,256x240
-def_widgetSize=kBigWidgetSize
-def_buttonWidth=120
-def_buttonHeight=25
-def_sliderWidth=kBigSliderWidth
-def_sliderHeight=kBigSliderHeight
-def_kLineHeight=16
-def_kFontHeight=14
-def_kPopUpHeight=(kLineHeight + 3)
-def_insetX=23
-def_insetY=94
-def_insetW=(w - buttonWidth - 17 * 2 - insetX)
-def_insetH=(h - 23 - insetY)
-def_optionsVPad=20
-def_optionsLabelWidth=110
-def_gameOptionsOverrideVPad=20
-def_tabPopupsLabelW=optionsLabelWidth
-def_aboutXOff=8
-def_aboutYOff=5
-def_aboutOuterBorder=80
-def_scummmainHOffset=12
-def_scummmainVSpace=15
-def_scummmainVAddOff=5
-def_scummhelpW=370
-def_scummhelpX=((w - scummhelpW) / 2)
-def_launcherVersionX=(w / 2 - 283 / 2 - 90)
-def_launcherVersionY=21
-
-def_xSeparation=10
-def_ySeparation=10
-def_xBorder=15
-
-use=pixmaps
-use=colors
-use=gradients
-use=extra
-
-##### Widgets config
-ListWidget.leftPadding=7
-ListWidget.rightPadding=5
-ListWidget.topPadding=5
-ListWidget.bottomPadding=5
-ListWidget.hlLeftPadding=0
-ListWidget.hlRightPadding=0
-PopUpWidget.leftPadding=7
-PopUpWidget.rightPadding=5
-PopUpWidget.labelSpacing=xSeparation
-EditTextWidget.font=kFontStyleNormal
-EditTextWidget.leftPadding=7
-EditTextWidget.rightPadding=5
-Console.font=kFontStyleFixedNormal
-Console.leftPadding=7
-Console.rightPadding=5
-Console.topPadding=5
-Console.bottomPadding=5
-TabWidget.tabWidth=75
-TabWidget.tabHeight=27
-TabWidget.titleVPad=8
-TabWidget.navButtonRightPad=3
-TabWidget.navButtonTopPad=4
-TabWidget.navButtonW=15
-TabWidget.navButtonH=18
-
-###### chooser
-opHeight=insetH
-useWithPrefix=chooser defaultChooser_
-
-##### browser
-use=browser
-
-##### launcher
-launcher_version=launcherVersionX launcherVersionY 247 kLineHeight
-launcher_version.align=kTextAlignRight
-launcher_logo=(w / 2 - 283 / 2) 5 283 80
-launcher_logo.visible=true
-space1=20
-space2=5
-launcher_list=insetX insetY insetW insetH
-launcher_start_button=(prev.x2 + 17) prev.y buttonWidth buttonHeight
-launcher_loadGame_button=prev.x (prev.y2 + space2) prev.w prev.h
-launcher_addGame_button=prev.x (prev.y2 + space1) prev.w prev.h
-launcher_editGame_button=prev.x (prev.y2 + space2) prev.w prev.h
-launcher_removeGame_button=prev.x (prev.y2 + space2) prev.w prev.h
-launcher_options_button=prev.x (prev.y2 + space1) prev.w prev.h
-launcher_about_button=prev.x (prev.y2 + space2) prev.w prev.h
-launcher_quit_button=prev.x (prev.y2 + space1) prev.w prev.h
-
-use=scummmain
-
-#### Global Main Menu Dialog
-# note that globalmain size depends on overall height
-hBorder=10
-gmW=(scummmainButtonWidth + (2 * scummmainHOffset) + 80)
-global_logo=((gmW - 142) / 2) scummmainVSpace 142 40
-global_logo.visible=true
-global_version=hBorder (prev.y + prev.h) (gmW - 2 * hBorder) kLineHeight
-global_version.align=kTextAlignCenter
-gmY=(prev.y + prev.h + scummmainVAddOff)
-globalmain_resume=globalmainHOffset gmY scummmainButtonWidth scummmainButtonHeight
-gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)
-gmY=(gmY + scummmainVSpace)
-globalmain_options=prev.x gmY prev.w prev.h
-gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)
-globalmain_about=prev.x gmY prev.w prev.h
-gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)
-gmY=(gmY + scummmainVSpace)
-globalmain_rtl=prev.x gmY prev.w prev.h
-gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)
-globalmain_quit=prev.x gmY prev.w prev.h
-gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)
-gmH=(gmY + scummmainVSpace)
-globalmain=((w - gmW) / 2) ((h - gmH) / 2) gmW gmH
-
-### global options
-globaloptions=insetX insetY insetW insetH
-set_parent=globaloptions
-vBorder=optionsVPad
-globaloptions_tabwidget=0 0 parent.w (parent.h - buttonHeight - 8 - ySeparation)
-
-# graphics tab
-opYoffset=vBorder
-opXoffset=0
-useWithPrefix=graphicsControls globaloptions_
-
-# audio tab
-opYoffset=vBorder
-useWithPrefix=audioControls globaloptions_
-useWithPrefix=subtitleControls globaloptions_
-
-# volume tab
-opYoffset=vBorder
-useWithPrefix=volumeControls globaloptions_
-
-# MIDI tab
-opYoffset=vBorder
-useWithPrefix=midiControls globaloptions_
-
-# paths tab
-yoffset=vBorder
-glOff=((buttonHeight - kLineHeight) / 2 + 2)
-globaloptions_savebutton=xBorder yoffset buttonWidth buttonHeight
-globaloptions_savepath=(prev.x2 + xSeparation) (yoffset + glOff) (parent.w - self.x - xBorder) kLineHeight
-yoffset=(yoffset + buttonHeight + ySeparation)
-globaloptions_extrabutton=xBorder yoffset buttonWidth buttonHeight
-globaloptions_extrapath=(prev.x2 + xSeparation) (yoffset + glOff) (parent.w - self.x - xBorder) kLineHeight
-yoffset=(yoffset + buttonHeight + ySeparation)
-globaloptions_themebutton=xBorder yoffset buttonWidth buttonHeight
-globaloptions_themepath=(prev.x2 + xSeparation) (yoffset + glOff) (parent.w - self.x - xBorder) kLineHeight
-yoffset=(yoffset + buttonHeight + ySeparation)
-globaloptions_pluginsbutton=xBorder yoffset buttonWidth buttonHeight
-globaloptions_pluginspath=(prev.x2 + xSeparation) (yoffset + glOff) (parent.w - self.x - xBorder) kLineHeight
-yoffset=(yoffset + buttonHeight + ySeparation)
-globaloptions_keysbutton=xBorder yoffset buttonWidth buttonHeight
-
-# Misc options
-yoffset=vBorder
-glOff=((buttonHeight - kLineHeight) / 2 + 2)
-globaloptions_themebutton2=xBorder yoffset buttonWidth buttonHeight
-globaloptions_curtheme=(prev.x2 + xSeparation) (yoffset + glOff) (parent.w - self.x - xBorder) kLineHeight
-yoffset=(yoffset + buttonHeight + ySeparation)
-globaloptions_autosaveperiod=xBorder yoffset (parent.w - self.x - xBorder) kPopUpHeight
-
-globaloptions_cancel=(parent.w - 2 * buttonWidth - xSeparation - xBorder) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
-globaloptions_ok=(prev.x2 + xSeparation) prev.y prev.w prev.h
-
-### game options
-gameoptions=insetX insetY insetW insetH
-set_parent=gameoptions
-vBorder=gameOptionsOverrideVPad
-gox=xBorder
-gow=(parent.w - gox - xBorder)
-
-gameoptions_tabwidget=0 0 parent.w (parent.h - buttonHeight - 8 - ySeparation)
-
-# game tab
-opYoffset=optionsVPad
-glOff=((kPopUpHeight - kLineHeight) / 2 + 2)
-gameoptions_id=gox (opYoffset + glOff) optionsLabelWidth kLineHeight
-gameoptions_id.align=kTextAlignRight
-gameoptions_domain=(prev.x2 + xSeparation) opYoffset (parent.w - self.x - xBorder) kPopUpHeight
-opYoffset=(opYoffset + prev.h + ySeparation)
-gameoptions_name=gox (opYoffset + glOff) optionsLabelWidth kLineHeight
-gameoptions_name.align=kTextAlignRight
-gameoptions_desc=(prev.x2 + xSeparation) opYoffset (parent.w - self.x - xBorder) kPopUpHeight
-opYoffset=(opYoffset + prev.h + ySeparation)
-gameoptions_lang=gox opYoffset (parent.w - self.x - xBorder) kPopUpHeight
-opYoffset=(opYoffset + prev.h + ySeparation)
-gameoptions_platform=prev.x opYoffset prev.w prev.h
-opYoffset=(opYoffset + prev.h + ySeparation)
-
-# paths tab
-opYoffset=optionsVPad
-goOff=((buttonHeight - kLineHeight) / 2 + 2)
-gameoptions_savepath=gox opYoffset buttonWidth buttonHeight
-gameoptions_savepathText=(prev.x2 + xSeparation) (opYoffset + goOff) (parent.w - self.x - xBorder) kLineHeight
-opYoffset=(opYoffset + buttonHeight + ySeparation)
-gameoptions_extrapath=gox opYoffset buttonWidth buttonHeight
-gameoptions_extrapathText=(prev.x2 + xSeparation) (opYoffset + goOff) (parent.w - self.x - xBorder) kLineHeight
-opYoffset=(opYoffset + buttonHeight + ySeparation)
-gameoptions_gamepath=gox opYoffset buttonWidth buttonHeight
-gameoptions_gamepathText=(prev.x2 + xSeparation) (opYoffset + goOff) (parent.w - self.x - xBorder) kLineHeight
-opYoffset=(opYoffset + buttonHeight + ySeparation)
-
-# graphics tab
-opYoffset=vBorder
-opXoffset=gox
-gameoptions_graphicsCheckbox=gox opYoffset (parent.w - gox - xBorder) buttonHeight
-opYoffset=(prev.y2 + ySeparation)
-useWithPrefix=graphicsControls gameoptions_
-
-# audio tab
-opYoffset=vBorder
-gameoptions_audioCheckbox=gox opYoffset (parent.w - gox - xBorder) buttonHeight
-opYoffset=(prev.y2 + ySeparation)
-useWithPrefix=audioControls gameoptions_
-useWithPrefix=subtitleControls gameoptions_
-
-# volume tab
-opYoffset=vBorder
-gameoptions_volumeCheckbox=gox opYoffset (parent.w - gox - xBorder) buttonHeight
-opYoffset=(prev.y2 + ySeparation)
-useWithPrefix=volumeControls gameoptions_
-
-# midi tab
-opYoffset=vBorder
-gameoptions_midiCheckbox=gox opYoffset (parent.w - gox - xBorder) buttonHeight
-opYoffset=(prev.y2 + ySeparation)
-useWithPrefix=midiControls gameoptions_
-
-gameoptions_cancel=(parent.w - 2 * buttonWidth - xSeparation - xBorder) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
-gameoptions_ok=(prev.x2 + xSeparation) prev.y prev.w prev.h
-
-### keys dialog
-keysdialog=(w / 20) (h / 10) (w - w / 10) (h - h / 5)
-set_parent=keysdialog
-keysdialog_map=(parent.w - buttonWidth - 10) 20 buttonWidth buttonHeight
-keysdialog_ok=prev.x (prev.y2 + 4) prev.w prev.h
-keysdialog_cancel=prev.x (prev.y2 + 4) prev.w prev.h
-keysdialog_list=10 10 (prev.x - 20) (parent.h - kLineHeight * 4 - self.y)
-keysdialog_action=prev.x (parent.h - kLineHeight * 3) (parent.w - self.x * 2) kLineHeight
-keysdialog_action.align=kTextAlignCenter
-keysdialog_mapping=prev.x (prev.y + kLineHeight) prev.w prev.h
-keysdialog_mapping.align=kTextAlignCenter
-
-### mass add dialog
-massadddialog=10 20 300 174
-set_parent=massadddialog
-massadddialog_caption=xBorder (10 + 1 * kLineHeight) (parent.w - 2 * xBorder) kLineHeight
-massadddialog_caption.align=kTextAlignCenter
-massadddialog_dirprogress=xBorder (10 + 3 * kLineHeight) prev.w prev.h
-massadddialog_dirprogress.align=kTextAlignCenter
-massadddialog_gameprogress=xBorder (10 + 4 * kLineHeight) prev.w prev.h
-massadddialog_gameprogress.align=kTextAlignCenter
-massadddialog_ok=((parent.w - (buttonWidth * 2) - xSeparation) / 2) (parent.h - buttonHeight - ySeparation) buttonWidth buttonHeight
-massadddialog_cancel=(prev.x2 + xSeparation) prev.y prev.w prev.h
-
-
-##### SCUMM dialogs
-scummDummyDialog=0 80 0 16
-
-use=scummmain
-## Engine config
-# note that scummconfig size depends on overall height
-# hence it is on the end of the list
-opYoffset=8
-useWithPrefix=volumeControls scummconfig_
-opYoffset=(opYoffset + 2)
-useWithPrefix=subtitleControls scummconfig_
-opYoffset=(opYoffset + buttonHeight)
-opYoffset=(opYoffset + buttonHeight + 4)
-soWidth=(8 + 3 * buttonWidth + 4)
-scummconfig_keys=(soWidth - 3 * (buttonWidth + 4) + 6) opYoffset (buttonWidth - 10) buttonHeight
-scummconfig_cancel=(prev.x2 + 4) prev.y (prev.w + 10) prev.h
-scummconfig_ok=(prev.x2 + 4) prev.y prev.w prev.h
-opYoffset=(opYoffset + buttonHeight)
-scummconfig=((w - soWidth) / 2) ((h - opYoffset) / 2) soWidth (opYoffset + 8)
-
-## Help
-scummHelpNumLines=15
-shH=(5 + (2 + scummHelpNumLines) * kFontHeight + buttonHeight + 7)
-shButtonWidth=(buttonWidth - 20)
-scummhelp=scummhelpX ((h - shH) / 2) scummhelpW shH
-scummhelp_title=10 5 scummhelpW kFontHeight
-scummhelp_title.align=kTextAlignCenter
-scummhelp_key.x=10
-scummhelp_key.yoffset=5
-scummhelp_key.w=80
-scummhelp_key.h=kFontHeight
-scummhelp_dsc.x=90
-scummhelp_dsc.yoffset=5
-scummhelp_dsc.w=(scummhelpW - 10 - 90)
-scummhelp_dsc.h=kFontHeight
-scummhelp_prev=10 (5 + kFontHeight * (scummHelpNumLines + 2) + 2) shButtonWidth buttonHeight
-scummhelp_next=(prev.x2 + 8) prev.y prev.w prev.h
-scummhelp_close=(scummhelpW - 8 - shButtonWidth) prev.y prev.w prev.h
-
-# Saveload dialog
-scummsaveload=8 8 (w - 2 * 8) (h - 16)
-set_parent=scummsaveload
-scummsaveload_title=10 2 (parent.w - 2 * 10 - 180-20) kLineHeight
-scummsaveload_title.align=kTextAlignCenter
-scummsaveload_list=10 18 prev.w (parent.h - 17 - buttonHeight - 8 - self.y)
-scummsaveload_thumbnail=(parent.w - (kThumbnailWidth + 22)) 18
-scummsaveload_thumbnail.hPad=10
-scummsaveload_thumbnail.vPad=10
-scummsaveload_thumbnail.fillR=0
-scummsaveload_thumbnail.fillG=0
-scummsaveload_thumbnail.fillB=0
-scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
-scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h
-scummsaveload_delete=prev.x (prev.y - 30) prev.w prev.h
-scummsaveload_extinfo.visible=true
-
-############################################
-[chooser]
-chooserW=insetW
-chooser=insetX insetY chooserW opHeight
-chooser_headline=xBorder 6 (chooserW - 2 * xBorder) kLineHeight
-chooser_list=prev.x (prev.y2 + 2) prev.w (opHeight - self.y - buttonHeight - 12)
-#JVPRAT: next Y doesn't seem right
-chooser_cancel=(chooserW - 2 * buttonWidth - xSeparation - xBorder) (opHeight - buttonHeight - 8) buttonWidth buttonHeight
-chooser_ok=(prev.x2 + xSeparation) prev.y prev.w prev.h
-
-[browser]
-browser=insetX insetY insetW insetH
-set_parent=browser
-browser_headline=xBorder 5 (parent.w - 2 * xBorder) kLineHeight
-browser_headline.align=kTextAlignCenter
-browser_path=prev.x (prev.y2 + 5) prev.w prev.h
-browser_list=prev.x prev.y2 prev.w (parent.h - 3 * kLineHeight - buttonHeight - 14)
-browser_up=prev.x (parent.h - buttonHeight - 8) buttonWidth buttonHeight
-#JVPRAT: doesn't it lack insetx?:
-browser_cancel=(parent.w - 2 * buttonWidth - xSeparation - xBorder) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
-browser_choose=(prev.x2 + xSeparation) prev.y prev.w prev.h
-
-[graphicsControls]
-gcx=(opXoffset + xBorder)
-grModePopup=gcx opYoffset (parent.w - self.x - xBorder) kPopUpHeight
-opYoffset=(prev.y2 + ySeparation)
-grRenderPopup=prev.x (opYoffset - 1) prev.w prev.h
-opYoffset=(prev.y2 + ySeparation)
-grFullscreenCheckbox=gcx opYoffset (parent.w - gcx - xBorder) kLineHeight
-opYoffset=(prev.y2 + ySeparation)
-grAspectCheckbox=prev.x opYoffset prev.w prev.h
-opYoffset=(prev.y2 + ySeparation)
-
-[audioControls]
-aux=(opXoffset + xBorder)
-auMidiPopup=aux opYoffset (parent.w - self.x - xBorder) kPopUpHeight
-opYoffset=(opYoffset + prev.h + ySeparation)
-auSampleRatePopup=aux (opYoffset - 1) prev.w kPopUpHeight
-opYoffset=(opYoffset + prev.h + ySeparation)
-
-[volumeControls]
-vcx=(opXoffset + xBorder)
-vcOff=((sliderHeight - kLineHeight) / 2 + 2)
-vcMusicText=vcx (opYoffset + vcOff) optionsLabelWidth kLineHeight
-vcMusicText.align=kTextAlignRight
-vcMusicSlider=(prev.x2 + xSeparation) opYoffset sliderWidth sliderHeight
-vcMusicLabel=(prev.x2 + xSeparation) (opYoffset + vcOff) 24 kLineHeight
-opYoffset=(opYoffset + sliderHeight + ySeparation)
-vcSfxText=vcx (opYoffset + vcOff) optionsLabelWidth kLineHeight
-vcSfxText.align=kTextAlignRight
-vcSfxSlider=(prev.x2 + xSeparation) opYoffset sliderWidth sliderHeight
-vcSfxLabel=(prev.x2 + xSeparation) (opYoffset + vcOff) 24 kLineHeight
-opYoffset=(opYoffset + sliderHeight + ySeparation)
-vcSpeechText=vcx (opYoffset + vcOff) optionsLabelWidth kLineHeight
-vcSpeechText.align=kTextAlignRight
-vcSpeechSlider=(prev.x2 + xSeparation) opYoffset sliderWidth sliderHeight
-vcSpeechLabel=(prev.x2 + xSeparation) (opYoffset + vcOff) 24 kLineHeight
-opYoffset=(opYoffset + sliderHeight + ySeparation)
-
-[midiControls]
-mcx=(opXoffset + xBorder)
-mcOff=((buttonHeight - kLineHeight) / 2 + 2)
-mcFontButton=mcx opYoffset buttonWidth buttonHeight
-mcFontPath=(prev.x2 + xSeparation) (opYoffset + mcOff) (parent.w - self.x - xSeparation - kLineHeight - xBorder) kLineHeight
-mcFontClearButton=(prev.x2 + xSeparation) prev.y kLineHeight kLineHeight
-opYoffset=(opYoffset + buttonHeight + ySeparation)
-mcMixedCheckbox=mcx opYoffset (parent.w - self.x - xBorder) kLineHeight
-opYoffset=(opYoffset + prev.h + ySeparation)
-mcMt32Checkbox=mcx opYoffset prev.w kLineHeight
-opYoffset=(opYoffset + prev.h + ySeparation)
-mcGSCheckbox=mcx opYoffset prev.w kLineHeight
-opYoffset=(opYoffset + prev.h + ySeparation)
-mcOff=((sliderHeight - kLineHeight) / 2 + 2)
-mcMidiGainText=mcx (opYoffset + mcOff) optionsLabelWidth kLineHeight
-mcMidiGainText.align=kTextAlignRight
-mcMidiGainSlider=(prev.x2 + xSeparation) opYoffset sliderWidth sliderHeight
-mcMidiGainLabel=(prev.x2 + xSeparation) (opYoffset + mcOff) 40 kLineHeight
-opYoffset=(opYoffset + sliderHeight + ySeparation)
-
-[subtitleControls]
-sbx=(opXoffset + xBorder)
-sbOff=((sliderHeight - kLineHeight) / 2 + 2)
-subToggleDesc=sbx (opYoffset + sbOff) optionsLabelWidth kLineHeight
-subToggleDesc.align=kTextAlignRight
-subToggleButton=(prev.x2 + xSeparation) opYoffset (buttonWidth + 34) sliderHeight
-opYoffset=(prev.y2 + ySeparation)
-subSubtitleSpeedDesc=sbx (opYoffset + sbOff) optionsLabelWidth kLineHeight
-subSubtitleSpeedDesc.align=kTextAlignRight
-subSubtitleSpeedSlider=(prev.x2 + xSeparation) opYoffset sliderWidth sliderHeight
-subSubtitleSpeedLabel=(prev.x2 + xSeparation) (opYoffset + sbOff) 24 kLineHeight
-opYoffset=(opYoffset + sliderHeight + ySeparation)
-
-[scummmain]
-## Main dialog
-# note that scummmain size depends on overall height
-smY=scummmainHOffset
-scummmain_resume=scummmainHOffset smY buttonWidth buttonHeight
-smY=(smY + buttonHeight + scummmainVAddOff)
-smY=(smY + scummmainVSpace)
-scummmain_load=prev.x smY prev.w prev.h
-smY=(smY + buttonHeight + scummmainVAddOff)
-scummmain_save=prev.x smY prev.w prev.h
-smY=(smY + buttonHeight + scummmainVAddOff)
-smY=(smY + scummmainVSpace)
-scummmain_options=prev.x smY prev.w prev.h
-smY=(smY + buttonHeight + scummmainVAddOff)
-scummmain_about=prev.x smY prev.w prev.h
-smY=(smY + buttonHeight + scummmainVAddOff)
-scummmain_help=prev.x smY prev.w prev.h
-smY=(smY + buttonHeight + scummmainVAddOff)
-smY=(smY + scummmainVSpace)
-scummmain_quit=prev.x smY prev.w prev.h
-smH=(smY + buttonHeight + scummmainHOffset)
-smW=(buttonWidth + 2 * scummmainHOffset)
-scummmain=((w - smW) / 2) ((h - smH) / 2) smW smH
-
-[320xY]
-use=pixmaps
-use=colors
-use=gradients
-use=extra
-shadow_right_width=1
-pix_checkbox_empty="checkbox_empty320.bmp"
-pix_checkbox_checked="checkbox_checked320.bmp"
-pix_cursor_image="cursor320.bmp"
-
-# NES resoltuion
-[256x240]
-use=320xY
-
-# PSP GUI
-[480x272]
-def_buttonWidth=100
-def_buttonHeight=23
-def_insetX=20
-def_insetY=10
-def_insetW=(w - buttonWidth - 17 * 2 - insetX)
-def_insetH=(h - 13 - insetY)
-def_launcherVersionX=50
-def_launcherVersionY=5
-def_gameOptionsOverrideVPad=10
-def_aboutXOff=3
-def_aboutYOff=2
-def_aboutOuterBorder=10
-
-use=XxY
-
-TabWidget.tabWidth=75
-
-# Override launcher
-launcher_list=insetX 103 (w - buttonWidth - 17 * 2 - self.x) (h - 15 - self.y)
-launcher_version=50 80 247 kLineHeight
-launcher_version.align=kTextAlignCenter
-launcher_logo=40 2 283 80
-launcher_logo.visible=true
-
-# Override extras
-inactive_dialog_shading=kShadingNone
-
-# Override browser
-def_buttonWidth=90
-use=browser
diff --git a/gui/themes/modern.zip b/gui/themes/modern.zip
deleted file mode 100644
index 329e3a2c1b..0000000000
--- a/gui/themes/modern.zip
+++ /dev/null
Binary files differ
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
new file mode 100644
index 0000000000..e285958029
--- /dev/null
+++ b/gui/themes/scummclassic.zip
Binary files differ
diff --git a/gui/themes/scummclassic/THEMERC b/gui/themes/scummclassic/THEMERC
new file mode 100644
index 0000000000..df6c0508b2
--- /dev/null
+++ b/gui/themes/scummclassic/THEMERC
@@ -0,0 +1 @@
+[SCUMMVM_THEME_V23:ScummVM Classic Theme:No Author] \ No newline at end of file
diff --git a/gui/themes/scummclassic/classic_gfx.stx b/gui/themes/scummclassic/classic_gfx.stx
new file mode 100644
index 0000000000..d9189743d3
--- /dev/null
+++ b/gui/themes/scummclassic/classic_gfx.stx
@@ -0,0 +1,364 @@
+/* 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$
+ *
+ */
+
+<render_info>
+ <palette>
+ <color name = 'black'
+ rgb = '0, 0, 0'
+ />
+ <color name = 'lightgrey'
+ rgb = '104, 104, 104'
+ />
+ <color name = 'darkgrey'
+ rgb = '64, 64, 64'
+ />
+ <color name = 'green'
+ rgb = '32, 160, 32'
+ />
+ <color name = 'green2'
+ rgb = '0, 255, 0'
+ />
+ </palette>
+
+ <fonts>
+ <font id = 'text_default'
+ file = 'default'
+ color = 'green'
+ />
+ <font id = 'text_hover'
+ file = 'default'
+ color = 'green2'
+ />
+ <font id = 'text_disabled'
+ file = 'default'
+ color = 'lightgrey'
+ />
+ <font id = 'text_inverted'
+ file = 'default'
+ color = 'black'
+ />
+ <font id = 'text_button'
+ file = 'default'
+ color = 'green'
+ />
+ <font id = 'text_button_hover'
+ file = 'default'
+ color = 'green2'
+ />
+ <font id = 'text_normal'
+ file = 'default'
+ color = 'green'
+ />
+ </fonts>
+
+ <defaults fill = 'foreground' fg_color = 'darkgrey' bg_color = 'black' shadow = '0' bevel_color = 'lightgrey'/>
+
+ <drawdata id = 'text_selection' cache = false>
+ <drawstep func = 'square'
+ fill = 'foreground'
+ fg_color = 'green'
+ />
+ </drawdata>
+
+ <drawdata id = 'mainmenu_bg' cache = false>
+ <drawstep func = 'fill'
+ fill = 'foreground'
+ fg_color = 'black'
+ />
+ </drawdata>
+
+ <drawdata id = 'special_bg' cache = false>
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ />
+ </drawdata>
+
+ <drawdata id = 'separator' cache = false>
+ <drawstep func = 'square'
+ fill = 'foreground'
+ height = '2'
+ ypos = 'center'
+ fg_color = 'lightgrey'
+ />
+ </drawdata>
+
+ <drawdata id = 'scrollbar_base' cache = false>
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ />
+ </drawdata>
+
+ <drawdata id = 'scrollbar_handle_hover' cache = false>
+ <drawstep func = 'square'
+ fill = 'foreground'
+ fg_color = 'green2'
+ />
+ </drawdata>
+
+ <drawdata id = 'scrollbar_handle_idle' cache = false>
+ <drawstep func = 'square'
+ fill = 'foreground'
+ fg_color = 'green'
+ />
+ </drawdata>
+
+ <drawdata id = 'scrollbar_button_idle' cache = false>
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ fill = 'none'
+ />
+ <drawstep func = 'triangle'
+ fg_color = 'green'
+ fill = 'foreground'
+ width = 'auto'
+ height = 'auto'
+ xpos = 'center'
+ ypos = 'center'
+ orientation = 'top'
+ />
+ </drawdata>
+
+ <drawdata id = 'scrollbar_button_hover' cache = false>
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ fill = 'none'
+ />
+ <drawstep func = 'triangle'
+ fg_color = 'green2'
+ fill = 'foreground'
+ width = 'auto'
+ height = 'auto'
+ xpos = 'center'
+ ypos = 'center'
+ orientation = 'top'
+ />
+ </drawdata>
+
+ <drawdata id = 'tab_active' cache = false>
+ <text font = 'text_hover'
+ vertical_align = 'center'
+ horizontal_align = 'center'
+ />
+ <drawstep func = 'tab'
+ bevel = '2'
+ radius = '0'
+ fill = 'none'
+ />
+ </drawdata>
+
+ <drawdata id = 'tab_inactive' cache = false>
+ <text font = 'text_default'
+ vertical_align = 'center'
+ horizontal_align = 'center'
+ />
+ <drawstep func = 'tab'
+ bevel = '2'
+ radius = '0'
+ fill = 'none'
+ />
+ </drawdata>
+
+ <drawdata id = 'tab_background' cache = false>
+ </drawdata>
+
+ <drawdata id = 'widget_slider' cache = false>
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ fill = 'none'
+ />
+ </drawdata>
+
+ <drawdata id = 'slider_disabled' cache = false>
+ <drawstep func = 'square'
+ fill = 'foreground'
+ fg_color = 'lightgrey'
+ />
+ </drawdata>
+
+ <drawdata id = 'slider_full' cache = false>
+ <drawstep func = 'square'
+ fill = 'foreground'
+ fg_color = 'green'
+ />
+ </drawdata>
+
+ <drawdata id = 'slider_hover' cache = false>
+ <drawstep func = 'square'
+ fill = 'foreground'
+ fg_color = 'green2'
+ />
+ </drawdata>
+
+ <drawdata id = 'widget_small' cache = false>
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ fill = 'none'
+ />
+ </drawdata>
+
+ <drawdata id = 'popup_idle' cache = false>
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ fill = 'none'
+ />
+ <drawstep func = 'triangle'
+ fg_color = 'green'
+ fill = 'foreground'
+ width = 'height'
+ height = 'auto'
+ xpos = 'right'
+ ypos = 'center'
+ orientation = 'bottom'
+ />
+ <text font = 'text_default'
+ vertical_align = 'center'
+ horizontal_align = 'left'
+ />
+ </drawdata>
+
+
+ <drawdata id = 'popup_hover' cache = false>
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ fill = 'none'
+ />
+ <drawstep func = 'triangle'
+ fg_color = 'green2'
+ fill = 'foreground'
+ width = 'height'
+ height = 'auto'
+ xpos = 'right'
+ ypos = 'center'
+ orientation = 'bottom'
+ />
+ <text font = 'text_hover'
+ vertical_align = 'center'
+ horizontal_align = 'left'
+ />
+ </drawdata>
+
+ <drawdata id = 'widget_textedit' cache = false>
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ fill = 'none'
+ />
+ </drawdata>
+
+ <drawdata id = 'plain_bg' cache = false>
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ />
+ </drawdata>
+
+ <drawdata id = 'caret' cache = false>
+ <drawstep func = 'square'
+ fill = 'foreground'
+ fg_color = 'lightgrey'
+ />
+ </drawdata>
+
+ <drawdata id = 'default_bg' cache = false>
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ />
+ </drawdata>
+
+ <drawdata id = 'button_idle' cache = false>
+ <text font = 'text_button'
+ vertical_align = 'center'
+ horizontal_align = 'center'
+ />
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ fill = 'none'
+ />
+ </drawdata>
+
+ <drawdata id = 'button_hover' cache = false>
+ <text font = 'text_button_hover'
+ vertical_align = 'center'
+ horizontal_align = 'center'
+ />
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ fill = 'none'
+ />
+ </drawdata>
+
+ <drawdata id = 'button_disabled' cache = false>
+ <text font = 'text_disabled'
+ vertical_align = 'center'
+ horizontal_align = 'center'
+ />
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ fill = 'none'
+ />
+ </drawdata>
+
+ <drawdata id = 'checkbox_disabled' cache = false>
+ <text font = 'text_disabled'
+ vertical_align = 'top'
+ horizontal_align = 'left'
+ />
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ fill = 'none'
+ />
+ </drawdata>
+
+ <drawdata id = 'checkbox_selected' cache = false>
+ <text font = 'text_default'
+ vertical_align = 'top'
+ horizontal_align = 'left'
+ />
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ fill = 'none'
+ />
+ <drawstep func = 'cross'
+ fill = 'foreground'
+ stroke = '2'
+ fg_color = 'green'
+ />
+ </drawdata>
+
+ <drawdata id = 'checkbox_default' cache = false>
+ <text font = 'text_default'
+ vertical_align = 'top'
+ horizontal_align = 'left'
+ />
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ fill = 'none'
+ />
+ </drawdata>
+
+ <drawdata id = 'widget_default' cache = false>
+ <drawstep func = 'bevelsq'
+ bevel = '2'
+ />
+ </drawdata>
+</render_info> \ No newline at end of file
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
new file mode 100644
index 0000000000..0704c8e91d
--- /dev/null
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -0,0 +1,635 @@
+/* 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$
+ *
+ */
+
+<layout_info resolution = '-320xY, -256x240'>
+ <globals>
+ <def var = 'Line.Height' value = '16' />
+ <def var = 'Font.Height' value = '16' />
+ <def var = 'TabLabelWidth' value = '110' />
+
+ <def var = 'WidgetSize' value = 'kBigWidgetSize' />
+ <def var = 'About.OuterBorder' value = '80'/>
+ <def var = 'PopUpWidget.labelSpacing' value = '10' />
+
+ <def var = 'Layout.Spacing' value = '8' />
+ <def var = 'ShowLauncherLogo' value = '0'/>
+ <def var = 'ShowGlobalMenuLogo' value = '0'/>
+
+ <def var = 'ScummSaveLoad.ExtInfo.Visible' value = '1'/>
+
+ <widget name = 'OptionsLabel'
+ size = '110, Globals.Line.Height'
+ />
+ <widget name = 'SmallLabel'
+ size = '24, Globals.Line.Height'
+ />
+
+ <widget name = 'ShortOptionsLabel'
+ size = '60, Globals.Line.Height'
+ />
+
+ <widget name = 'Button'
+ size = 'kBigButtonWidth, kBigButtonHeight'
+ />
+ <widget name = 'Slider'
+ size = 'kBigSliderWidth, kBigSliderHeight'
+ />
+
+ <widget name = 'PopUp'
+ size = '-1, 19'
+ />
+ <widget name = 'Checkbox'
+ size = '-1, 14'
+ />
+ <widget name = 'ListWidget'
+ padding = '5, 0, 8, 0'
+ />
+ <widget name = 'PopUpWidget'
+ padding = '7, 5, 0, 0'
+ />
+ <widget name = 'EditTextWidget'
+ padding = '5, 5, 0, 0'
+ />
+ <widget name = 'Console'
+ padding = '7, 5, 5, 5'
+ />
+ <widget name = 'TabWidget.Tab'
+ size = '75, 27'
+ padding = '0, 0, 8, 0'
+ />
+ <widget name = 'TabWidget.NavButton'
+ size = '15, 18'
+ padding = '0, 3, 4, 0'
+ />
+ </globals>
+
+ <dialog name = 'Launcher' overlays = 'screen'>
+ <layout type = 'vertical' center = 'true' padding = '16, 16, 8, 8'>
+ <widget name = 'Version'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'GameList'/>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10'>
+ <widget name = 'LoadGameButton'
+ height = '20'
+ />
+ <widget name = 'AddGameButton'
+ height = '20'
+ />
+ <widget name = 'EditGameButton'
+ height = '20'
+ />
+ <widget name = 'RemoveGameButton'
+ height = '20'
+ />
+ </layout>
+ <space size = '12'/>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10'>
+ <widget name = 'QuitButton'
+ height = '20'
+ />
+ <widget name = 'AboutButton'
+ height = '20'
+ />
+ <widget name = 'OptionsButton'
+ height = '20'
+ />
+ <widget name = 'StartButton'
+ height = '20'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'Browser' overlays = 'Dialog.Launcher.GameList' shading = 'dim'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'Headline'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Path'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'List'/>
+ <layout type = 'horizontal' padding = '0, 0, 16, 0'>
+ <widget name = 'Up'
+ type = 'Button'
+ />
+ <space/>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Choose'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions' overlays = 'Dialog.Launcher.GameList' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0'>
+ <widget name = 'TabWidget'/>
+ <layout type = 'horizontal' padding = '16, 16, 16, 16'>
+ <space/>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Ok'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Graphics' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'grModePopup'
+ type = 'PopUp'
+ />
+ <widget name = 'grRenderPopup'
+ type = 'PopUp'
+ />
+ <widget name = 'grAspectCheckbox'
+ type = 'Checkbox'
+ />
+ <widget name = 'grFullscreenCheckbox'
+ type = 'Checkbox'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'auMidiPopup'
+ type = 'PopUp'
+ />
+ <widget name = 'auSampleRatePopup'
+ type = 'PopUp'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'subToggleDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'subToggleButton'
+ width = '150'
+ height = 'Globals.Slider.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'subSubtitleSpeedDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'subSubtitleSpeedSlider'
+ type = 'Slider'
+ />
+ <widget name = 'subSubtitleSpeedLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Volume' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'vcMusicText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcMusicSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcMusicLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'vcSfxText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcSfxSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcSfxLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'vcSpeechText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcSpeechSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcSpeechLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_MIDI' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'mcFontButton'
+ type = 'Button'
+ />
+ <widget name = 'mcFontPath'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'mcFontClearButton'
+ height = 'Globals.Line.Height'
+ width = 'Globals.Line.Height'
+ />
+ </layout>
+ <widget name = 'mcMixedCheckbox'
+ type = 'Checkbox'
+ />
+ <widget name = 'mcMt32Checkbox'
+ type = 'Checkbox'
+ />
+ <widget name = 'mcGSCheckbox'
+ type = 'Checkbox'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'mcMidiGainText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'mcMidiGainSlider'
+ type = 'Slider'
+ />
+ <widget name = 'mcMidiGainLabel'
+ width = '32'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Paths' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'SaveButton'
+ type = 'Button'
+ />
+ <widget name = 'SavePath'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'ThemeButton'
+ type = 'Button'
+ />
+ <widget name = 'ThemePath'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'ExtraButton'
+ type = 'Button'
+ />
+ <widget name = 'ExtraPath'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'PluginsButton'
+ type = 'Button'
+ />
+ <widget name = 'PluginsPath'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Misc' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'ThemeButton'
+ type = 'Button'
+ />
+ <widget name = 'CurTheme'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <widget name = 'Renderer'
+ type = 'PopUp'
+ />
+ <widget name = 'AutosavePeriod'
+ type = 'PopUp'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions' overlays = 'Dialog.Launcher.GameList' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'TabWidget'/>
+ <layout type = 'horizontal' padding = '16, 16, 16, 4'>
+ <space/>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Ok'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Graphics' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'EnableTabCheckbox'
+ type = 'Checkbox'
+ />
+ <import layout = 'Dialog.GlobalOptions_Graphics' />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'EnableTabCheckbox'
+ type = 'Checkbox'
+ />
+ <import layout = 'Dialog.GlobalOptions_Audio' />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_MIDI' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'EnableTabCheckbox'
+ type = 'Checkbox'
+ />
+ <import layout = 'Dialog.GlobalOptions_MIDI' />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Volume' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'EnableTabCheckbox'
+ type = 'Checkbox'
+ />
+ <import layout = 'Dialog.GlobalOptions_Volume' />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Game' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'Id'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'Domain'
+ type = 'PopUp'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'Name'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'Desc'
+ type = 'PopUp'
+ />
+ </layout>
+ <widget name = 'Lang'
+ type = 'PopUp'
+ />
+ <widget name = 'Platform'
+ type = 'PopUp'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Paths' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'>
+ <widget name = 'Savepath'
+ type = 'Button'
+ />
+ <widget name = 'SavepathText'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'>
+ <widget name = 'Extrapath'
+ type = 'Button'
+ />
+ <widget name = 'ExtrapathText'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'>
+ <widget name = 'Gamepath'
+ type = 'Button'
+ />
+ <widget name = 'GamepathText'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalMenu' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' center = 'true'>
+ <widget name = 'Title'
+ width = '210'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Version'
+ width = '210'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Resume'
+ width = '150'
+ height = 'Globals.Button.Height'
+ />
+ <space size = '10'/>
+ <widget name = 'Options'
+ width = '150'
+ height = 'Globals.Button.Height'
+ />
+ <widget name = 'About'
+ width = '150'
+ height = 'Globals.Button.Height'
+ />
+ <space size = '10'/>
+ <widget name = 'RTL'
+ width = '150'
+ height = 'Globals.Button.Height'
+ />
+ <widget name = 'Quit'
+ width = '150'
+ height = 'Globals.Button.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummMain' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'Resume'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Load'
+ type = 'Button'
+ />
+ <widget name = 'Save'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Options'
+ type = 'Button'
+ />
+ <widget name = 'Help'
+ type = 'Button'
+ />
+ <widget name = 'About'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Quit'
+ type = 'Button'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummConfig' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'vcMusicText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcMusicSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcMusicLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'vcSfxText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcSfxSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcSfxLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'vcSpeechText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcSpeechSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcSpeechLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'subToggleDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'subToggleButton'
+ width = '158'
+ height = 'Globals.Slider.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'subSubtitleSpeedDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'subSubtitleSpeedSlider'
+ type = 'Slider'
+ />
+ <widget name = 'subSubtitleSpeedLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <space size = '60'/>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <space size = 'Globals.Button.Width' />
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Ok'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummSaveLoad' overlays = 'screen' inset = '16'>
+ <layout type = 'vertical' padding = '8, 8, 8, 32' center = 'true'>
+ <widget name = 'Title'
+ height = 'Globals.Line.Height'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 0, 16' spacing = '16'>
+ <widget name = 'List' />
+ <widget name = 'Thumbnail'
+ width = '180'
+ height = '200'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <space/>
+ <widget name = 'Delete'
+ type = 'Button'
+ />
+ <space size = '32'/>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Choose'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummHelp' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'>
+ <widget name = 'Title'
+ width = '320'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'HelpText'
+ height = '220'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 16, 0'>
+ <widget name = 'Prev'
+ type = 'Button'
+ />
+ <widget name = 'Next'
+ type = 'Button'
+ />
+ <space size = '32'/>
+ <widget name = 'Close'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+</layout_info> \ No newline at end of file
diff --git a/gui/themes/scummclassic/classic_layout_320.stx b/gui/themes/scummclassic/classic_layout_320.stx
new file mode 100644
index 0000000000..9c03d51e13
--- /dev/null
+++ b/gui/themes/scummclassic/classic_layout_320.stx
@@ -0,0 +1,628 @@
+/* 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$
+ *
+ */
+
+<layout_info resolution = "320xY, 256x240">
+ <globals>
+ <def var = 'Line.Height' value = '12' />
+ <def var = 'Font.Height' value = '10' />
+ <def var = 'TabLabelWidth' value = '100' />
+
+ <def var = 'WidgetSize' value = 'kNormalWidgetSize' />
+ <def var = 'About.OuterBorder' value = '10'/>
+ <def var = 'PopUpWidget.labelSpacing' value = '6' />
+
+ <def var = 'Layout.Spacing' value = '8'/>
+
+ <def var = 'ShowLauncherLogo' value = '0'/>
+ <def var = 'ShowGlobalMenuLogo' value = '0'/>
+ <def var = 'ScummSaveLoad.ExtInfo.Visible' value = '0'/>
+
+ <widget name = 'Button'
+ size = 'kButtonWidth, kButtonHeight'
+ />
+
+ <widget name = 'Slider'
+ size = 'kSliderWidth, kSliderHeight'
+ />
+
+ <widget name = 'OptionsLabel'
+ size = '110, Globals.Line.Height'
+ />
+ <widget name = 'SmallLabel'
+ size = '18, Globals.Line.Height'
+ />
+ <widget name = 'PopUp'
+ size = '-1, 15'
+ />
+ <widget name = 'Checkbox'
+ size = '-1, Globals.Line.Height'
+ />
+ <widget name = 'ListWidget'
+ padding = '5, 0, 8, 0'
+ />
+ <widget name = 'PopUpWidget'
+ padding = '7, 5, 0, 0'
+ />
+ <widget name = 'EditTextWidget'
+ padding = '5, 5, 0, 0'
+ />
+ <widget name = 'Console'
+ padding = '7, 5, 5, 5'
+ />
+ <widget name = 'TabWidget.Tab'
+ size = '45, 16'
+ padding = '0, 0, 2, 0'
+ />
+ <widget name = 'TabWidget.NavButton'
+ size = '32, 18'
+ padding = '0, 3, 4, 0'
+ />
+ </globals>
+
+ <dialog name = 'Launcher' overlays = 'screen'>
+ <layout type = 'vertical' center = 'true' padding = '8, 8, 4, 4'>
+ <widget name = 'Version'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'GameList'/>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10'>
+ <widget name = 'LoadGameButton'
+ height = '12'
+ />
+ <widget name = 'AddGameButton'
+ height = '12'
+ />
+ <widget name = 'EditGameButton'
+ height = '12'
+ />
+ <widget name = 'RemoveGameButton'
+ height = '12'
+ />
+ </layout>
+ <space size = '4'/>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10'>
+ <widget name = 'QuitButton'
+ height = '12'
+ />
+ <widget name = 'AboutButton'
+ height = '12'
+ />
+ <widget name = 'OptionsButton'
+ height = '12'
+ />
+ <widget name = 'StartButton'
+ height = '12'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'Browser' overlays = 'screen' inset = '16' shading = 'dim'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'Headline'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Path'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'List'/>
+ <layout type = 'horizontal' padding = '0, 0, 16, 0'>
+ <widget name = 'Up'
+ type = 'Button'
+ />
+ <space/>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+
+ <widget name = 'Choose'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions' overlays = 'screen' inset = '16' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0'>
+ <widget name = 'TabWidget'/>
+ <layout type = 'horizontal' padding = '8, 8, 8, 8'>
+ <space/>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+
+ <widget name = 'Ok'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Graphics' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'grModePopup'
+ type = 'PopUp'
+ />
+ <widget name = 'grRenderPopup'
+ type = 'PopUp'
+ />
+ <widget name = 'grAspectCheckbox'
+ type = 'Checkbox'
+ />
+ <widget name = 'grFullscreenCheckbox'
+ type = 'Checkbox'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'auMidiPopup'
+ type = 'PopUp'
+ />
+ <widget name = 'auSampleRatePopup'
+ type = 'PopUp'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'subToggleDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'subToggleButton'
+ width = 'Globals.Slider.Width'
+ height = 'Globals.Slider.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'subSubtitleSpeedDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'subSubtitleSpeedSlider'
+ type = 'Slider'
+ />
+ <widget name = 'subSubtitleSpeedLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Volume' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'vcMusicText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcMusicSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcMusicLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'vcSfxText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcSfxSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcSfxLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'vcSpeechText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcSpeechSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcSpeechLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_MIDI' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'mcFontButton'
+ type = 'Button'
+ />
+ <widget name = 'mcFontPath'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'mcFontClearButton'
+ height = 'Globals.Line.Height'
+ width = 'Globals.Line.Height'
+ />
+ </layout>
+ <widget name = 'mcMixedCheckbox'
+ type = 'Checkbox'
+ />
+ <widget name = 'mcMt32Checkbox'
+ type = 'Checkbox'
+ />
+ <widget name = 'mcGSCheckbox'
+ type = 'Checkbox'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'mcMidiGainText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'mcMidiGainSlider'
+ type = 'Slider'
+ />
+ <widget name = 'mcMidiGainLabel'
+ width = '32'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Paths' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'SaveButton'
+ type = 'Button'
+ />
+ <widget name = 'SavePath'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'ThemeButton'
+ type = 'Button'
+ />
+ <widget name = 'ThemePath'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'ExtraButton'
+ type = 'Button'
+ />
+ <widget name = 'ExtraPath'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'PluginsButton'
+ type = 'Button'
+ />
+ <widget name = 'PluginsPath'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Misc' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'ThemeButton'
+ type = 'Button'
+ />
+ <widget name = 'CurTheme'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <widget name = 'Renderer'
+ type = 'PopUp'
+ />
+ <widget name = 'AutosavePeriod'
+ type = 'PopUp'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions' overlays = 'screen' inset = '16' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'TabWidget'/>
+ <layout type = 'horizontal' padding = '8, 8, 8, 8'>
+ <space/>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Ok'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Graphics' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'EnableTabCheckbox'
+ type = 'Checkbox'
+ />
+ <import layout = 'Dialog.GlobalOptions_Graphics' />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'EnableTabCheckbox'
+ type = 'Checkbox'
+ />
+ <import layout = 'Dialog.GlobalOptions_Audio' />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_MIDI' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'EnableTabCheckbox'
+ type = 'Checkbox'
+ />
+ <import layout = 'Dialog.GlobalOptions_MIDI' />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Volume' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'EnableTabCheckbox'
+ type = 'Checkbox'
+ />
+ <import layout = 'Dialog.GlobalOptions_Volume' />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Game' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'Id'
+ width = '35'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Domain'
+ type = 'PopUp'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'Name'
+ width = '35'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Desc'
+ type = 'PopUp'
+ />
+ </layout>
+ <space size = '8'/>
+ <widget name = 'Lang'
+ type = 'PopUp'
+ />
+ <widget name = 'Platform'
+ type = 'PopUp'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Paths' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'>
+ <widget name = 'Savepath'
+ type = 'Button'
+ />
+ <widget name = 'SavepathText'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'>
+ <widget name = 'Extrapath'
+ type = 'Button'
+ />
+ <widget name = 'ExtrapathText'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'>
+ <widget name = 'Gamepath'
+ type = 'Button'
+ />
+ <widget name = 'GamepathText'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalMenu' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'>
+ <widget name = 'Title'
+ width = '120'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Version'
+ width = '120'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Resume'
+ width = '70'
+ height = 'Globals.Button.Height'
+ />
+ <space size = '4'/>
+ <widget name = 'Options'
+ width = '70'
+ height = 'Globals.Button.Height'
+ />
+ <widget name = 'About'
+ width = '70'
+ height = 'Globals.Button.Height'
+ />
+ <space size = '4'/>
+ <widget name = 'RTL'
+ width = '70'
+ height = 'Globals.Button.Height'
+ />
+ <widget name = 'Quit'
+ width = '70'
+ height = 'Globals.Button.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummMain' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'Resume'
+ type = 'Button'
+ />
+ <space size = '4'/>
+ <widget name = 'Load'
+ type = 'Button'
+ />
+ <widget name = 'Save'
+ type = 'Button'
+ />
+ <space size = '4'/>
+ <widget name = 'Options'
+ type = 'Button'
+ />
+ <widget name = 'Help'
+ type = 'Button'
+ />
+ <widget name = 'About'
+ type = 'Button'
+ />
+ <space size = '4'/>
+ <widget name = 'Quit'
+ type = 'Button'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummConfig' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'vcMusicText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcMusicSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcMusicLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'vcSfxText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcSfxSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcSfxLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'vcSpeechText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcSpeechSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcSpeechLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'subToggleDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'subToggleButton'
+ width = '92'
+ height = 'Globals.Slider.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'subSubtitleSpeedDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'subSubtitleSpeedSlider'
+ type = 'Slider'
+ />
+ <widget name = 'subSubtitleSpeedLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <space size = '20'/>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <space size = 'Globals.Button.Width' />
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Ok'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummSaveLoad' overlays = 'screen' inset = '16'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'>
+ <widget name = 'Title' height = 'Globals.Line.Height'/>
+ <widget name = 'List' />
+ <layout type = 'horizontal' padding = '0, 0, 16, 0'>
+ <space/>
+ <widget name = 'Delete'
+ type = 'Button'
+ />
+ <space size = '16'/>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Choose'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummHelp' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'Title'
+ width = '180'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'HelpText'
+ height = '170'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 4, 0'>
+ <widget name = 'Prev'
+ type = 'Button'
+ />
+ <widget name = 'Next'
+ type = 'Button'
+ />
+ <space size = '32'/>
+ <widget name = 'Close'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+</layout_info> \ No newline at end of file
diff --git a/gui/themes/scummodern.zip b/gui/themes/scummodern.zip
new file mode 100644
index 0000000000..70141bfce9
--- /dev/null
+++ b/gui/themes/scummodern.zip
Binary files differ
diff --git a/gui/themes/scummodern/THEMERC b/gui/themes/scummodern/THEMERC
new file mode 100644
index 0000000000..d11c959867
--- /dev/null
+++ b/gui/themes/scummodern/THEMERC
@@ -0,0 +1 @@
+[SCUMMVM_THEME_V23:ScummVM Modern Theme:No Author] \ No newline at end of file
diff --git a/gui/themes/scummodern/checkbox.bmp b/gui/themes/scummodern/checkbox.bmp
new file mode 100644
index 0000000000..a0b91b569f
--- /dev/null
+++ b/gui/themes/scummodern/checkbox.bmp
Binary files differ
diff --git a/gui/themes/scummodern/cursor.bmp b/gui/themes/scummodern/cursor.bmp
new file mode 100644
index 0000000000..e7bdb60cad
--- /dev/null
+++ b/gui/themes/scummodern/cursor.bmp
Binary files differ
diff --git a/gui/themes/scummodern/cursor_small.bmp b/gui/themes/scummodern/cursor_small.bmp
new file mode 100644
index 0000000000..5f25f32f1a
--- /dev/null
+++ b/gui/themes/scummodern/cursor_small.bmp
Binary files differ
diff --git a/gui/themes/scummodern/helvr12-l1.fcc b/gui/themes/scummodern/helvr12-l1.fcc
new file mode 100644
index 0000000000..651a25934a
--- /dev/null
+++ b/gui/themes/scummodern/helvr12-l1.fcc
Binary files differ
diff --git a/gui/themes/scummodern/logo.bmp b/gui/themes/scummodern/logo.bmp
new file mode 100644
index 0000000000..659ec47d03
--- /dev/null
+++ b/gui/themes/scummodern/logo.bmp
Binary files differ
diff --git a/gui/themes/scummodern/logo_small.bmp b/gui/themes/scummodern/logo_small.bmp
new file mode 100644
index 0000000000..eaa998a165
--- /dev/null
+++ b/gui/themes/scummodern/logo_small.bmp
Binary files differ
diff --git a/gui/themes/scummodern/scummodern_gfx.stx b/gui/themes/scummodern/scummodern_gfx.stx
new file mode 100644
index 0000000000..b8eff77aa1
--- /dev/null
+++ b/gui/themes/scummodern/scummodern_gfx.stx
@@ -0,0 +1,489 @@
+/* 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$
+ *
+ */
+
+<render_info>
+ <palette>
+ <color name = 'darkred'
+ rgb = '169, 42, 12'
+ />
+ <color name = 'brightred'
+ rgb = '203, 126, 107'
+ />
+ <color name = 'xtrabrightred'
+ rgb = '251, 241, 206'
+ />
+ <color name = 'blandyellow'
+ rgb = '246, 224, 139'
+ />
+ <color name = 'bgreen'
+ rgb = '100, 162, 8'
+ />
+ <color name = 'black'
+ rgb = '0, 0, 0'
+ />
+ <color name = 'white'
+ rgb = '255, 255, 255'
+ />
+ <color name = 'shadowcolor'
+ rgb = '63, 60, 17'
+ />
+ </palette>
+
+ <bitmaps>
+ <bitmap filename = 'logo.bmp'/>
+ <bitmap filename = 'cursor.bmp'/>
+ <bitmap filename = 'cursor_small.bmp'/>
+ <bitmap filename = 'checkbox.bmp'/>
+ <bitmap filename = 'logo_small.bmp'/>
+ </bitmaps>
+
+ <fonts>
+ <font id = 'text_default'
+ file = 'default'
+ color = 'black'
+ />
+ <font id = 'text_hover'
+ file = 'default'
+ color = 'bgreen'
+ />
+ <font id = 'text_disabled'
+ file = 'default'
+ color = '128, 128, 128'
+ />
+ <font id = 'text_inverted'
+ file = 'default'
+ color = '0, 0, 0'
+ />
+ <font id = 'text_button'
+ file = 'default'
+ color = 'white'
+ />
+ <font id = 'text_button_hover'
+ file = 'default'
+ color = 'blandyellow'
+ />
+ <font id = 'text_normal'
+ file = 'helvr12-l1.bdf'
+ color = 'black'
+ />
+ </fonts>
+
+ <defaults fill = 'gradient' fg_color = 'white' bevel_color = '237, 169, 72'/>
+
+ <cursor file = 'cursor.bmp' hotspot = '0, 0' scale = '3'/>
+ <cursor resolution = '320xY, 256x240' file = 'cursor_small.bmp' hotspot = '0, 0' scale = '3'/>
+
+ <drawdata id = 'text_selection' cache = false>
+ <drawstep func = 'square'
+ fill = 'foreground'
+ fg_color = 'bgreen'
+ />
+ </drawdata>
+
+ <drawdata id = 'mainmenu_bg' cache = false>
+ <drawstep func = 'fill'
+ fill = 'gradient'
+ gradient_start = '208, 112, 8'
+ gradient_end = '232, 192, 16'
+ />
+ </drawdata>
+
+ <drawdata id = 'special_bg' cache = false>
+ <drawstep func = 'roundedsq'
+ radius = '4'
+ fill = 'gradient'
+ stroke = '0'
+ gradient_start = '208, 112, 8'
+ gradient_end = '232, 192, 16'
+ shadow = '3'
+ gradient_factor = '3'
+ />
+ </drawdata>
+
+ <drawdata id = 'separator' cache = false>
+ <drawstep func = 'square'
+ fill = 'foreground'
+ height = '1'
+ ypos = 'center'
+ fg_color = 'black'
+ />
+ </drawdata>
+
+ <drawdata id = 'scrollbar_base' cache = false>
+ <drawstep func = 'roundedsq'
+ stroke = 1
+ radius = 6
+ fill = 'background'
+ fg_color = '176, 164, 160'
+ bg_color = '240, 228, 160'
+ />
+ </drawdata>
+
+ <drawdata id = 'scrollbar_handle_hover' cache = false>
+ <drawstep func = 'roundedsq'
+ stroke = 1
+ radius = 6
+ fill = 'gradient'
+ fg_color = 'blandyellow'
+ gradient_start = 'xtrabrightred'
+ gradient_end = 'darkred'
+ />
+ </drawdata>
+
+ <drawdata id = 'scrollbar_handle_idle' cache = false>
+ <drawstep func = 'roundedsq'
+ stroke = 1
+ radius = 6
+ fill = 'gradient'
+ fg_color = 'blandyellow'
+ gradient_start = 'brightred'
+ gradient_end = 'darkred'
+ />
+ </drawdata>
+
+ <drawdata id = 'scrollbar_button_idle' cache = false>
+ <drawstep func = 'roundedsq'
+ radius = '4'
+ fill = 'none'
+ fg_color = '176, 164, 160'
+ stroke = 1
+ />
+ <drawstep func = 'triangle'
+ fg_color = '0, 0, 0'
+ fill = 'foreground'
+ width = 'auto'
+ height = 'auto'
+ xpos = 'center'
+ ypos = 'center'
+ orientation = 'top'
+ />
+ </drawdata>
+
+ <drawdata id = 'scrollbar_button_hover' cache = false>
+ <drawstep func = 'roundedsq'
+ radius = '4'
+ fill = 'background'
+ fg_color = '120, 120, 120'
+ bg_color = '206, 121, 99'
+ stroke = 1
+ />
+ <drawstep func = 'triangle'
+ fg_color = '0, 0, 0'
+ fill = 'foreground'
+ width = 'auto'
+ height = 'auto'
+ xpos = 'center'
+ ypos = 'center'
+ orientation = 'top'
+ />
+ </drawdata>
+
+ <drawdata id = 'tab_active' cache = false>
+ <text font = 'text_default'
+ vertical_align = 'center'
+ horizontal_align = 'center'
+ />
+ <drawstep func = 'tab'
+ radius = '4'
+ stroke = '0'
+ fill = 'gradient'
+ gradient_end = 'xtrabrightred'
+ gradient_start = 'blandyellow'
+ shadow = 3
+ />
+ </drawdata>
+
+ <drawdata id = 'tab_inactive' cache = false>
+ <text font = 'text_default'
+ vertical_align = 'center'
+ horizontal_align = 'center'
+ />
+ <drawstep func = 'tab'
+ radius = '4'
+ stroke = '0'
+ fill = 'foreground'
+ fg_color = '240, 205, 118'
+ shadow = 3
+ />
+ </drawdata>
+
+ <drawdata id = 'tab_background' cache = false>
+ <drawstep func = 'tab'
+ radius = '6'
+ stroke = '0'
+ fill = 'foreground'
+ fg_color = '232, 180, 81'
+ shadow = 3
+ />
+ </drawdata>
+
+ <drawdata id = 'widget_slider' cache = false>
+ <drawstep func = 'roundedsq'
+ stroke = 0
+ radius = 4
+ fill = 'foreground'
+ fg_color = 'blandyellow'
+ bevel = 1
+ bevel_color = 'shadowcolor'
+ />
+ </drawdata>
+
+ <drawdata id = 'slider_full' cache = false>
+ <drawstep func = 'roundedsq'
+ stroke = 1
+ radius = 4
+ fill = 'gradient'
+ fg_color = '123, 112, 56'
+ gradient_start = 'brightred'
+ gradient_end = 'darkred'
+ />
+ </drawdata>
+
+ <drawdata id = 'slider_hover' cache = false>
+ <drawstep func = 'roundedsq'
+ stroke = 1
+ radius = 4
+ fill = 'gradient'
+ fg_color = '123, 112, 56'
+ gradient_start = 'xtrabrightred'
+ gradient_end = 'darkred'
+ />
+ </drawdata>
+
+ <drawdata id = 'slider_disabled' cache = false>
+ <drawstep func = 'roundedsq'
+ stroke = 1
+ radius = 4
+ fill = 'gradient'
+ fg_color = '123, 112, 56'
+ gradient_start = 'xtrabrightred'
+ gradient_end = 'darkred'
+ />
+ </drawdata>
+
+ <drawdata id = 'popup_idle' cache = false>
+ <drawstep func = 'roundedsq'
+ stroke = 0
+ radius = 4
+ fill = 'foreground'
+ fg_color = '250, 237, 190'
+ shadow = 2
+ />
+ <drawstep func = 'triangle'
+ fg_color = '63, 60, 52'
+ fill = 'foreground'
+ width = 'height'
+ height = 'auto'
+ xpos = 'right'
+ ypos = 'center'
+ orientation = 'bottom'
+ />
+ <text font = 'text_default'
+ vertical_align = 'center'
+ horizontal_align = 'left'
+ />
+ </drawdata>
+
+
+ <drawdata id = 'popup_hover' cache = false>
+ <drawstep func = 'roundedsq'
+ stroke = 0
+ radius = 4
+ fill = 'gradient'
+ gradient_start = 'blandyellow'
+ gradient_end = '250, 237, 190'
+ shadow = 0
+ />
+ <drawstep func = 'triangle'
+ fg_color = '63, 60, 52'
+ fill = 'foreground'
+ width = 'height'
+ height = 'auto'
+ xpos = 'right'
+ ypos = 'center'
+ orientation = 'bottom'
+ />
+ <text font = 'text_hover'
+ vertical_align = 'center'
+ horizontal_align = 'left'
+ />
+ </drawdata>
+
+ <drawdata id = 'widget_textedit' cache = false>
+ <drawstep func = 'roundedsq'
+ fill = 'foreground'
+ radius = 4
+ fg_color = 'blandyellow'
+ shadow = 0
+ bevel = 1
+ bevel_color = 'shadowcolor'
+ />
+ </drawdata>
+
+ <drawdata id = 'plain_bg' cache = false>
+ <drawstep func = 'roundedsq'
+ radius = 6
+ stroke = 0
+ gradient_start = 'blandyellow'
+ gradient_end = 'xtrabrightred'
+ fill = 'gradient'
+ shadow = 3
+ />
+ </drawdata>
+
+ <drawdata id = 'caret' cache = false>
+ <drawstep func = 'square'
+ fill = 'foreground'
+ fg_color = 'black'
+ />
+ </drawdata>
+
+ <drawdata id = 'default_bg' cache = false>
+ <drawstep func = 'roundedsq'
+ radius = 12
+ stroke = 0
+ fg_color = 'xtrabrightred'
+ fill = 'foreground'
+ shadow = 3
+ />
+ </drawdata>
+
+ <drawdata id = 'button_idle' cache = false>
+ <text font = 'text_button'
+ vertical_align = 'center'
+ horizontal_align = 'center'
+ />
+ <drawstep func = 'roundedsq'
+ radius = '3'
+ stroke = 1
+ fill = 'gradient'
+ shadow = 0
+ fg_color = 'shadowcolor'
+ gradient_start = 'brightred'
+ gradient_end = 'darkred'
+ bevel = 1
+ />
+ </drawdata>
+
+ <drawdata id = 'button_hover' cache = false>
+ <text font = 'text_button_hover'
+ vertical_align = 'center'
+ horizontal_align = 'center'
+ />
+ <drawstep func = 'roundedsq'
+ radius = '3'
+ gradient_factor = 1
+ stroke = 1
+ fill = 'gradient'
+ shadow = 0
+ fg_color = 'shadowcolor'
+ gradient_start = 'xtrabrightred'
+ gradient_end = 'darkred'
+ bevel_color = 'xtrabrightred'
+ bevel = 1
+ />
+ </drawdata>
+
+ <drawdata id = 'button_disabled' cache = false>
+ <text font = 'text_disabled'
+ vertical_align = 'center'
+ horizontal_align = 'center'
+ />
+ <drawstep func = 'roundedsq'
+ radius = '3'
+ stroke = 1
+ fill = 'gradient'
+ shadow = 0
+ fg_color = 'shadowcolor'
+ gradient_start = 'brightred'
+ gradient_end = 'darkred'
+ bevel = 1
+ />
+ </drawdata>
+
+ <drawdata id = 'checkbox_disabled' cache = false>
+ <text font = 'text_disabled'
+ vertical_align = 'top'
+ horizontal_align = 'left'
+ />
+ <drawstep func = 'roundedsq'
+ fill = 'none'
+ radius = 4
+ fg_color = 'black'
+ shadow = 0
+ bevel = 1
+ bevel_color = 'shadowcolor'
+ />
+ </drawdata>
+
+ <drawdata id = 'checkbox_selected' cache = false>
+ <text font = 'text_default'
+ vertical_align = 'top'
+ horizontal_align = 'left'
+ />
+ <drawstep func = 'bitmap'
+ file = 'checkbox.bmp'
+ />
+ </drawdata>
+
+ <drawdata id = 'checkbox_default' cache = false>
+ <text font = 'text_default'
+ vertical_align = 'top'
+ horizontal_align = 'left'
+ />
+ <drawstep func = 'roundedsq'
+ fill = 'foreground'
+ radius = 4
+ fg_color = 'blandyellow'
+ shadow = 0
+ bevel = 1
+ bevel_color = 'shadowcolor'
+ />
+ </drawdata>
+
+ <drawdata id = 'widget_default' cache = false>
+ <drawstep func = 'roundedsq'
+ radius = 8
+ stroke = 0
+ gradient_start = 'blandyellow'
+ gradient_end = '251, 241, 206'
+ gradient_factor = '6'
+ fill = 'gradient'
+ shadow = 3
+ />
+ </drawdata>
+
+ <drawdata id = 'widget_small' cache = false>
+ <drawstep func = 'roundedsq'
+ radius = 8
+ stroke = 0
+ gradient_start = 'blandyellow'
+ gradient_end = 'xtrabrightred'
+ gradient_factor = '6'
+ fill = 'gradient'
+ shadow = 3
+ />
+ </drawdata>
+</render_info> \ No newline at end of file
diff --git a/gui/themes/scummodern/scummodern_layout.stx b/gui/themes/scummodern/scummodern_layout.stx
new file mode 100644
index 0000000000..03d920ac05
--- /dev/null
+++ b/gui/themes/scummodern/scummodern_layout.stx
@@ -0,0 +1,647 @@
+/* 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$
+ *
+ */
+
+<layout_info resolution = '-320xY, -256x240'>
+ <globals>
+ <def var = 'Line.Height' value = '16' />
+ <def var = 'Font.Height' value = '16' />
+ <def var = 'TabLabelWidth' value = '110' />
+
+ <def var = 'WidgetSize' value = 'kBigWidgetSize' />
+
+ <def var = 'Padding.Bottom' value = '16' />
+ <def var = 'Padding.Left' value = '16' />
+ <def var = 'Padding.Right' value = '16' />
+ <def var = 'Padding.Top' value = '16' />
+
+ <def var = 'About.OuterBorder' value = '80'/>
+
+ <def var = 'ListWidget.hlLeftPadding' value = '0'/>
+ <def var = 'ListWidget.hlRightPadding' value = '0'/>
+ <def var = 'PopUpWidget.labelSpacing' value = '10' />
+
+ <def var = 'ShowLauncherLogo' value = '1'/>
+ <def var = 'ShowGlobalMenuLogo' value = '1'/>
+
+ <def var = 'ScummSaveLoad.ExtInfo.Visible' value = '1'/>
+
+ <widget name = 'OptionsLabel'
+ size = '110, Globals.Line.Height'
+ />
+ <widget name = 'SmallLabel'
+ size = '24, Globals.Line.Height'
+ />
+
+ <widget name = 'Button'
+ size = 'kBigButtonWidth, kBigButtonHeight'
+ />
+
+
+ <widget name = 'Slider'
+ size = 'kBigSliderWidth, kBigSliderHeight'
+ />
+ <widget name = 'PopUp'
+ size = '-1, 19'
+ />
+ <widget name = 'Checkbox'
+ size = '-1, Globals.Line.Height'
+ />
+ <widget name = 'ListWidget'
+ padding = '5, 0, 8, 0'
+ />
+ <widget name = 'PopUpWidget'
+ padding = '7, 5, 0, 0'
+ />
+ <widget name = 'EditTextWidget'
+ padding = '5, 5, 0, 0'
+ />
+ <widget name = 'Console'
+ padding = '7, 5, 5, 5'
+ />
+ <widget name = 'TabWidget.Tab'
+ size = '75, 27'
+ padding = '0, 0, 8, 0'
+ />
+ <widget name = 'TabWidget.NavButton'
+ size = '15, 18'
+ padding = '0, 3, 4, 0'
+ />
+ </globals>
+
+ <dialog name = 'Launcher' overlays = 'screen'>
+ <layout type = 'vertical' center = 'true' padding = '23, 23, 8, 23'>
+ <widget name = 'Version'
+ width = '247'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Logo'
+ width = '283'
+ height = '80'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'GameList'/>
+ <layout type = 'vertical' padding = '10, 0, 0, 0'>
+ <widget name = 'StartButton'
+ type = 'Button'
+ />
+ <widget name = 'LoadGameButton'
+ type = 'Button'
+ />
+ <space size = '10' />
+ <widget name = 'AddGameButton'
+ type = 'Button'
+ />
+ <widget name = 'EditGameButton'
+ type = 'Button'
+ />
+ <widget name = 'RemoveGameButton'
+ type = 'Button'
+ />
+ <space size = '10' />
+ <widget name = 'OptionsButton'
+ type = 'Button'
+ />
+ <widget name = 'AboutButton'
+ type = 'Button'
+ />
+ <space size = '10' />
+ <widget name = 'QuitButton'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'Browser' overlays = 'Dialog.Launcher.GameList' shading = 'dim'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'Headline'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Path'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'List'/>
+ <layout type = 'horizontal' padding = '0, 0, 16, 0'>
+ <widget name = 'Up'
+ type = 'Button'
+ />
+ <space/>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Choose'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions' overlays = 'Dialog.Launcher.GameList' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0'>
+ <widget name = 'TabWidget'/>
+ <layout type = 'horizontal' padding = '16, 16, 16, 16'>
+ <space/>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Ok'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Graphics' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'grModePopup'
+ type = 'PopUp'
+ />
+ <widget name = 'grRenderPopup'
+ type = 'PopUp'
+ />
+ <widget name = 'grAspectCheckbox'
+ type = 'Checkbox'
+ />
+ <widget name = 'grFullscreenCheckbox'
+ type = 'Checkbox'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'auMidiPopup'
+ type = 'PopUp'
+ />
+ <widget name = 'auSampleRatePopup'
+ type = 'PopUp'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'subToggleDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'subToggleButton'
+ width = '150'
+ height = 'Globals.Slider.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'subSubtitleSpeedDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'subSubtitleSpeedSlider'
+ type = 'Slider'
+ />
+ <widget name = 'subSubtitleSpeedLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Volume' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'vcMusicText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcMusicSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcMusicLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'vcSfxText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcSfxSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcSfxLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'vcSpeechText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcSpeechSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcSpeechLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_MIDI' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'mcFontButton'
+ type = 'Button'
+ />
+ <widget name = 'mcFontPath'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'mcFontClearButton'
+ height = 'Globals.Line.Height'
+ width = 'Globals.Line.Height'
+ />
+ </layout>
+ <widget name = 'mcMixedCheckbox'
+ type = 'Checkbox'
+ />
+ <widget name = 'mcMt32Checkbox'
+ type = 'Checkbox'
+ />
+ <widget name = 'mcGSCheckbox'
+ type = 'Checkbox'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'mcMidiGainText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'mcMidiGainSlider'
+ type = 'Slider'
+ />
+ <widget name = 'mcMidiGainLabel'
+ width = '32'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Paths' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'SaveButton'
+ type = 'Button'
+ />
+ <widget name = 'SavePath'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'ThemeButton'
+ type = 'Button'
+ />
+ <widget name = 'ThemePath'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'ExtraButton'
+ type = 'Button'
+ />
+ <widget name = 'ExtraPath'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'PluginsButton'
+ type = 'Button'
+ />
+ <widget name = 'PluginsPath'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Misc' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'ThemeButton'
+ type = 'Button'
+ />
+ <widget name = 'CurTheme'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <widget name = 'Renderer'
+ type = 'PopUp'
+ />
+ <widget name = 'AutosavePeriod'
+ type = 'PopUp'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions' overlays = 'Dialog.Launcher.GameList' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'TabWidget'/>
+ <layout type = 'horizontal' padding = '16, 16, 16, 4'>
+ <space/>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Ok'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Graphics' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'EnableTabCheckbox'
+ type = 'Checkbox'
+ />
+ <import layout = 'Dialog.GlobalOptions_Graphics' />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'EnableTabCheckbox'
+ type = 'Checkbox'
+ />
+ <import layout = 'Dialog.GlobalOptions_Audio' />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_MIDI' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'EnableTabCheckbox'
+ type = 'Checkbox'
+ />
+ <import layout = 'Dialog.GlobalOptions_MIDI' />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Volume' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'EnableTabCheckbox'
+ type = 'Checkbox'
+ />
+ <import layout = 'Dialog.GlobalOptions_Volume' />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Game' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'Id'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'Domain'
+ type = 'PopUp'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'Name'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'Desc'
+ type = 'PopUp'
+ />
+ </layout>
+ <widget name = 'Lang'
+ type = 'PopUp'
+ />
+ <widget name = 'Platform'
+ type = 'PopUp'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Paths' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'>
+ <widget name = 'Savepath'
+ type = 'Button'
+ />
+ <widget name = 'SavepathText'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'>
+ <widget name = 'Extrapath'
+ type = 'Button'
+ />
+ <widget name = 'ExtrapathText'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'>
+ <widget name = 'Gamepath'
+ type = 'Button'
+ />
+ <widget name = 'GamepathText'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalMenu' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' center = 'true'>
+ <widget name = 'Logo'
+ width = '210'
+ height = '40'
+ />
+ <widget name = 'Version'
+ width = '210'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Resume'
+ width = '150'
+ height = 'Globals.Button.Height'
+ />
+ <space size = '10'/>
+ <widget name = 'Options'
+ width = '150'
+ height = 'Globals.Button.Height'
+ />
+ <widget name = 'About'
+ width = '150'
+ height = 'Globals.Button.Height'
+ />
+ <space size = '10'/>
+ <widget name = 'RTL'
+ width = '150'
+ height = 'Globals.Button.Height'
+ />
+ <widget name = 'Quit'
+ width = '150'
+ height = 'Globals.Button.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummMain' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'Resume'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Load'
+ type = 'Button'
+ />
+ <widget name = 'Save'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Options'
+ type = 'Button'
+ />
+ <widget name = 'Help'
+ type = 'Button'
+ />
+ <widget name = 'About'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Quit'
+ type = 'Button'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummConfig' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'vcMusicText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcMusicSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcMusicLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'vcSfxText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcSfxSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcSfxLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'vcSpeechText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcSpeechSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcSpeechLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'subToggleDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'subToggleButton'
+ width = '158'
+ height = 'Globals.Slider.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'subSubtitleSpeedDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'subSubtitleSpeedSlider'
+ type = 'Slider'
+ />
+ <widget name = 'subSubtitleSpeedLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <space size = '60'/>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <space size = 'Globals.Button.Width' />
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Ok'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummSaveLoad' overlays = 'screen' inset = '16'>
+ <layout type = 'vertical' padding = '8, 8, 8, 32' center = 'true'>
+ <widget name = 'Title'
+ height = 'Globals.Line.Height'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 0, 16' spacing = '16'>
+ <widget name = 'List' />
+ <widget name = 'Thumbnail'
+ width = '180'
+ height = '200'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <space/>
+ <widget name = 'Delete'
+ type = 'Button'
+ />
+ <space size = '32'/>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Choose'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummHelp' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'>
+ <widget name = 'Title'
+ width = '320'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'HelpText'
+ height = '220'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 16, 0'>
+ <widget name = 'Prev'
+ type = 'Button'
+ />
+ <widget name = 'Next'
+ type = 'Button'
+ />
+ <space size = '32'/>
+ <widget name = 'Close'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+</layout_info> \ No newline at end of file
diff --git a/gui/themes/scummodern/scummodern_layout_320.stx b/gui/themes/scummodern/scummodern_layout_320.stx
new file mode 100644
index 0000000000..b92ded6097
--- /dev/null
+++ b/gui/themes/scummodern/scummodern_layout_320.stx
@@ -0,0 +1,625 @@
+/* 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$
+ *
+ */
+
+<layout_info resolution = "320xY, 256x240">
+ <globals>
+ <def var = 'Line.Height' value = '12' />
+ <def var = 'Font.Height' value = '10' />
+ <def var = 'TabLabelWidth' value = '100' />
+
+ <def var = 'WidgetSize' value = 'kNormalWidgetSize' />
+ <def var = 'About.OuterBorder' value = '10'/>
+ <def var = 'PopUpWidget.labelSpacing' value = '6' />
+
+ <def var = 'ShowLauncherLogo' value = '0'/>
+ <def var = 'ShowGlobalMenuLogo' value = '0'/>
+ <def var = 'ScummSaveLoad.ExtInfo.Visible' value = '0'/>
+
+ <widget name = 'Button'
+ size = 'kButtonWidth, kButtonHeight'
+ />
+
+ <widget name = 'Slider'
+ size = 'kSliderWidth, kSliderHeight'
+ />
+
+ <widget name = 'OptionsLabel'
+ size = '110, Globals.Line.Height'
+ />
+ <widget name = 'SmallLabel'
+ size = '18, Globals.Line.Height'
+ />
+ <widget name = 'PopUp'
+ size = '-1, 15'
+ />
+ <widget name = 'Checkbox'
+ size = '-1, Globals.Line.Height'
+ />
+ <widget name = 'ListWidget'
+ padding = '5, 0, 8, 0'
+ />
+ <widget name = 'PopUpWidget'
+ padding = '7, 5, 0, 0'
+ />
+ <widget name = 'EditTextWidget'
+ padding = '5, 5, 0, 0'
+ />
+ <widget name = 'Console'
+ padding = '7, 5, 5, 5'
+ />
+ <widget name = 'TabWidget.Tab'
+ size = '45, 16'
+ padding = '0, 0, 2, 0'
+ />
+ <widget name = 'TabWidget.NavButton'
+ size = '32, 18'
+ padding = '0, 3, 4, 0'
+ />
+ </globals>
+
+ <dialog name = 'Launcher' overlays = 'screen'>
+ <layout type = 'vertical' center = 'true' padding = '8, 8, 8, 4' spacing = '8'>
+ <widget name = 'Version'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'GameList'/>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6'>
+ <widget name = 'LoadGameButton'
+ height = 'Globals.Button.Height'
+ />
+ <widget name = 'AddGameButton'
+ height = 'Globals.Button.Height'
+ />
+ <widget name = 'EditGameButton'
+ height = 'Globals.Button.Height'
+ />
+ <widget name = 'RemoveGameButton'
+ height = 'Globals.Button.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'QuitButton'
+ height = 'Globals.Button.Height'
+ />
+ <widget name = 'AboutButton'
+ height = 'Globals.Button.Height'
+ />
+ <widget name = 'OptionsButton'
+ height = 'Globals.Button.Height'
+ />
+ <widget name = 'StartButton'
+ height = 'Globals.Button.Height'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'Browser' overlays = 'screen' inset = '16' shading = 'dim'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'Headline'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Path'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'List'/>
+ <layout type = 'horizontal' padding = '0, 0, 16, 0'>
+ <widget name = 'Up'
+ type = 'Button'
+ />
+ <space/>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+
+ <widget name = 'Choose'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions' overlays = 'screen' inset = '16' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0'>
+ <widget name = 'TabWidget'/>
+ <layout type = 'horizontal' padding = '8, 8, 8, 8'>
+ <space/>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+
+ <widget name = 'Ok'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Graphics' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'grModePopup'
+ type = 'PopUp'
+ />
+ <widget name = 'grRenderPopup'
+ type = 'PopUp'
+ />
+ <widget name = 'grAspectCheckbox'
+ type = 'Checkbox'
+ />
+ <widget name = 'grFullscreenCheckbox'
+ type = 'Checkbox'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'auMidiPopup'
+ type = 'PopUp'
+ />
+ <widget name = 'auSampleRatePopup'
+ type = 'PopUp'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'subToggleDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'subToggleButton'
+ width = 'Globals.Slider.Width'
+ height = 'Globals.Slider.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'subSubtitleSpeedDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'subSubtitleSpeedSlider'
+ type = 'Slider'
+ />
+ <widget name = 'subSubtitleSpeedLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Volume' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'vcMusicText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcMusicSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcMusicLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'vcSfxText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcSfxSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcSfxLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'vcSpeechText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcSpeechSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcSpeechLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_MIDI' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'mcFontButton'
+ type = 'Button'
+ />
+ <widget name = 'mcFontPath'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'mcFontClearButton'
+ height = 'Globals.Line.Height'
+ width = 'Globals.Line.Height'
+ />
+ </layout>
+ <widget name = 'mcMixedCheckbox'
+ type = 'Checkbox'
+ />
+ <widget name = 'mcMt32Checkbox'
+ type = 'Checkbox'
+ />
+ <widget name = 'mcGSCheckbox'
+ type = 'Checkbox'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'mcMidiGainText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'mcMidiGainSlider'
+ type = 'Slider'
+ />
+ <widget name = 'mcMidiGainLabel'
+ width = '32'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Paths' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'SaveButton'
+ type = 'Button'
+ />
+ <widget name = 'SavePath'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'ThemeButton'
+ type = 'Button'
+ />
+ <widget name = 'ThemePath'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'ExtraButton'
+ type = 'Button'
+ />
+ <widget name = 'ExtraPath'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'PluginsButton'
+ type = 'Button'
+ />
+ <widget name = 'PluginsPath'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalOptions_Misc' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'ThemeButton'
+ type = 'Button'
+ />
+ <widget name = 'CurTheme'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <widget name = 'Renderer'
+ type = 'PopUp'
+ />
+ <widget name = 'AutosavePeriod'
+ type = 'PopUp'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions' overlays = 'screen' inset = '16' shading = 'dim'>
+ <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'TabWidget'/>
+ <layout type = 'horizontal' padding = '8, 8, 8, 8'>
+ <space/>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Ok'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Graphics' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'EnableTabCheckbox'
+ type = 'Checkbox'
+ />
+ <import layout = 'Dialog.GlobalOptions_Graphics' />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'EnableTabCheckbox'
+ type = 'Checkbox'
+ />
+ <import layout = 'Dialog.GlobalOptions_Audio' />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_MIDI' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'EnableTabCheckbox'
+ type = 'Checkbox'
+ />
+ <import layout = 'Dialog.GlobalOptions_MIDI' />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Volume' overlays = 'Dialog.GlobalOptions.TabWidget'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
+ <widget name = 'EnableTabCheckbox'
+ type = 'Checkbox'
+ />
+ <import layout = 'Dialog.GlobalOptions_Volume' />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Game' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'Id'
+ width = '35'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Domain'
+ type = 'PopUp'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16'>
+ <widget name = 'Name'
+ width = '35'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Desc'
+ type = 'PopUp'
+ />
+ </layout>
+ <space size = '8'/>
+ <widget name = 'Lang'
+ type = 'PopUp'
+ />
+ <widget name = 'Platform'
+ type = 'PopUp'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'GameOptions_Paths' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'>
+ <layout type = 'vertical' padding = '16, 16, 16, 16'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'>
+ <widget name = 'Savepath'
+ type = 'Button'
+ />
+ <widget name = 'SavepathText'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'>
+ <widget name = 'Extrapath'
+ type = 'Button'
+ />
+ <widget name = 'ExtrapathText'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'>
+ <widget name = 'Gamepath'
+ type = 'Button'
+ />
+ <widget name = 'GamepathText'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'GlobalMenu' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'>
+ <widget name = 'Title'
+ width = '120'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Version'
+ width = '120'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Resume'
+ width = '70'
+ height = 'Globals.Button.Height'
+ />
+ <space size = '4'/>
+ <widget name = 'Options'
+ width = '70'
+ height = 'Globals.Button.Height'
+ />
+ <widget name = 'About'
+ width = '70'
+ height = 'Globals.Button.Height'
+ />
+ <space size = '4'/>
+ <widget name = 'RTL'
+ width = '70'
+ height = 'Globals.Button.Height'
+ />
+ <widget name = 'Quit'
+ width = '70'
+ height = 'Globals.Button.Height'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummMain' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '4, 4, 4, 4'>
+ <widget name = 'Resume'
+ type = 'Button'
+ />
+ <space size = '8'/>
+ <widget name = 'Load'
+ type = 'Button'
+ />
+ <widget name = 'Save'
+ type = 'Button'
+ />
+ <space size = '8'/>
+ <widget name = 'Options'
+ type = 'Button'
+ />
+ <widget name = 'Help'
+ type = 'Button'
+ />
+ <widget name = 'About'
+ type = 'Button'
+ />
+ <space size = '8'/>
+ <widget name = 'Quit'
+ type = 'Button'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummConfig' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'vcMusicText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcMusicSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcMusicLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'vcSfxText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcSfxSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcSfxLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'vcSpeechText'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'vcSpeechSlider'
+ type = 'Slider'
+ />
+ <widget name = 'vcSpeechLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'subToggleDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'subToggleButton'
+ width = '92'
+ height = 'Globals.Slider.Height'
+ />
+ </layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <widget name = 'subSubtitleSpeedDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'subSubtitleSpeedSlider'
+ type = 'Slider'
+ />
+ <widget name = 'subSubtitleSpeedLabel'
+ type = 'SmallLabel'
+ />
+ </layout>
+ <space size = '20'/>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '8'>
+ <space size = 'Globals.Button.Width' />
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Ok'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummSaveLoad' overlays = 'screen' inset = '16'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'>
+ <widget name = 'Title' height = 'Globals.Line.Height'/>
+ <widget name = 'List' />
+ <layout type = 'horizontal' padding = '0, 0, 16, 0'>
+ <space/>
+ <widget name = 'Delete'
+ type = 'Button'
+ />
+ <space size = '16'/>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Choose'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummHelp' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'Title'
+ width = '180'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'HelpText'
+ height = '170'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 4, 0'>
+ <widget name = 'Prev'
+ type = 'Button'
+ />
+ <widget name = 'Next'
+ type = 'Button'
+ />
+ <space size = '32'/>
+ <widget name = 'Close'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+</layout_info>
diff --git a/gui/themes/scummtheme.py b/gui/themes/scummtheme.py
new file mode 100644
index 0000000000..6199289e66
--- /dev/null
+++ b/gui/themes/scummtheme.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+# encoding: utf-8
+import sys
+import re
+import os
+import zipfile
+
+THEME_FILE_EXTENSIONS = ('.stx', '.bmp', '.fcc')
+
+def buildTheme(themeName):
+ if not os.path.isdir(themeName) or not os.path.isfile(os.path.join(themeName, "THEMERC")):
+ print "Invalid theme name: " + themeName
+ return
+
+ zf = zipfile.ZipFile(themeName + ".zip", 'w')
+
+ print "Building '" + themeName + "' theme:"
+ os.chdir(themeName)
+
+ zf.write('THEMERC', './THEMERC')
+
+ for filename in os.listdir('.'):
+ if os.path.isfile(filename) and not filename[0] == '.' and filename.endswith(THEME_FILE_EXTENSIONS):
+ zf.write(filename, './' + filename)
+ print " Adding file: " + filename
+
+ os.chdir('../')
+
+ zf.close()
+
+def buildAllThemes():
+ for f in os.listdir('.'):
+ if os.path.isdir(os.path.join('.', f)) and not f[0] == '.':
+ buildTheme(f)
+
+def parseSTX(theme_file, def_file):
+ comm = re.compile("\/\*(.*?)\*\/", re.DOTALL)
+
+ output = ""
+ for line in theme_file:
+ output += line.rstrip("\r\n\t ").lstrip() + " \n"
+
+ output = re.sub(comm, "", output).replace("\t", " ").replace(" ", " ").replace("\"", "'").splitlines()
+
+ for line in output:
+ if line and not line.isspace():
+ def_file.write("\"" + line + "\"\n")
+
+def buildDefTheme(themeName):
+ def_file = open("default.inc", "w")
+
+ if not os.path.isdir(themeName):
+ print "Cannot open default theme dir."
+
+ for filename in os.listdir(themeName):
+ filename = os.path.join(themeName, filename)
+ if os.path.isfile(filename) and filename.endswith(".stx"):
+ theme_file = open(filename, "r")
+ parseSTX(theme_file, def_file)
+ theme_file.close()
+
+ def_file.close()
+
+def printUsage():
+ print "==============================="
+ print "ScummVM Theme Generation Script"
+ print "==============================="
+ print "Usage:"
+ print "scummtheme.py makeall"
+ print " Builds all the available themes.\n"
+ print "scummtheme.py make [themename]"
+ print " Builds the theme called 'themename'.\n"
+ print "scummtheme.py default [themename]"
+ print " Creates a 'default.inc' file to embed the given theme in the source code.\n"
+
+def main():
+
+ if len(sys.argv) == 2 and sys.argv[1] == "makeall":
+ buildAllThemes()
+
+ elif len(sys.argv) == 3 and sys.argv[1] == "make":
+ buildTheme(sys.argv[2])
+
+ elif len(sys.argv) == 3 and sys.argv[1] == "default":
+ buildDefTheme(sys.argv[2])
+
+ else:
+ printUsage()
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/gui/widget.cpp b/gui/widget.cpp
index 31f76eac6f..818676dbf4 100644
--- a/gui/widget.cpp
+++ b/gui/widget.cpp
@@ -26,22 +26,21 @@
#include "graphics/fontman.h"
#include "gui/widget.h"
#include "gui/dialog.h"
-#include "gui/eval.h"
#include "gui/newgui.h"
+#include "gui/ThemeEval.h"
+
namespace GUI {
Widget::Widget(GuiObject *boss, int x, int y, int w, int h)
: GuiObject(x, y, w, h), _type(0), _boss(boss),
- _id(0), _flags(0), _hints(THEME_HINT_FIRST_DRAW),
- _hasFocus(false), _state(Theme::kStateEnabled) {
+ _id(0), _flags(0), _hasFocus(false), _state(Theme::kStateEnabled) {
init();
}
Widget::Widget(GuiObject *boss, const Common::String &name)
: GuiObject(name), _type(0), _boss(boss),
- _id(0), _flags(0), _hints(THEME_HINT_FIRST_DRAW),
- _hasFocus(false), _state(Theme::kStateDisabled) {
+ _id(0), _flags(0), _hasFocus(false), _state(Theme::kStateDisabled) {
init();
}
@@ -49,8 +48,6 @@ void Widget::init() {
// Insert into the widget list of the boss
_next = _boss->_firstWidget;
_boss->_firstWidget = this;
- // HACK: we enable background saving for all widgets by default for now
- _hints = THEME_HINT_FIRST_DRAW | THEME_HINT_SAVE_BACKGROUND;
}
Widget::~Widget() {
@@ -99,7 +96,7 @@ void Widget::draw() {
// Draw border
if (_flags & WIDGET_BORDER) {
- gui->theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), _hints, Theme::kWidgetBackgroundBorder);
+ gui->theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), 0, Theme::kWidgetBackgroundBorder);
_x += 4;
_y += 4;
_w -= 8;
@@ -126,8 +123,6 @@ void Widget::draw() {
w->draw();
w = w->_next;
}
-
- clearHints(THEME_HINT_FIRST_DRAW);
}
Widget *Widget::findWidgetInChain(Widget *w, int x, int y) {
@@ -153,14 +148,14 @@ Widget *Widget::findWidgetInChain(Widget *w, const char *name) {
}
bool Widget::isEnabled() const {
- if (g_gui.evaluator()->getVar(_name + ".enabled") == 0) {
+ if (g_gui.xmlEval()->getVar("Dialog." + _name + ".Enabled", 1) == 0) {
return false;
}
return ((_flags & WIDGET_ENABLED) != 0);
}
bool Widget::isVisible() const {
- if (g_gui.evaluator()->getVar(_name + ".visible") == 0)
+ if (g_gui.xmlEval()->getVar("Dialog." + _name + ".Visible", 1) == 0)
return false;
return !(_flags & WIDGET_INVISIBLE);
@@ -181,10 +176,7 @@ StaticTextWidget::StaticTextWidget(GuiObject *boss, const Common::String &name,
_type = kStaticTextWidget;
_label = text;
- _align = (Graphics::TextAlignment)g_gui.evaluator()->getVar(name + ".align");
-
- if (_align == (int)EVAL_UNDEF_VAR)
- _align = kTextAlignLeft;
+ _align = (Graphics::TextAlignment)g_gui.xmlEval()->getVar(name + ".Align", kTextAlignLeft);
}
void StaticTextWidget::setValue(int value) {
@@ -226,7 +218,6 @@ ButtonWidget::ButtonWidget(GuiObject *boss, const Common::String &name, const Co
: StaticTextWidget(boss, name, label), CommandSender(boss),
_cmd(cmd), _hotkey(hotkey) {
setFlags(WIDGET_ENABLED/* | WIDGET_BORDER*/ | WIDGET_CLEARBG);
- _hints = THEME_HINT_USE_SHADOW;
_type = kButtonWidget;
}
@@ -236,7 +227,7 @@ void ButtonWidget::handleMouseUp(int x, int y, int button, int clickCount) {
}
void ButtonWidget::drawWidget() {
- g_gui.theme()->drawButton(Common::Rect(_x, _y, _x+_w, _y+_h), _label, _state, _hints);
+ g_gui.theme()->drawButton(Common::Rect(_x, _y, _x+_w, _y+_h), _label, _state, 0);
}
#pragma mark -
@@ -336,20 +327,12 @@ GraphicsWidget::GraphicsWidget(GuiObject *boss, int x, int y, int w, int h)
: Widget(boss, x, y, w, h), _gfx(), _alpha(256), _transparency(false) {
setFlags(WIDGET_ENABLED | WIDGET_CLEARBG);
_type = kGraphicsWidget;
- // HACK: Don't save the background. We want to be sure that redrawing
- // the widget updates the screen, even when there isn't any image
- // to draw.
- _hints &= ~THEME_HINT_SAVE_BACKGROUND;
}
GraphicsWidget::GraphicsWidget(GuiObject *boss, const Common::String &name)
: Widget(boss, name), _gfx(), _alpha(256), _transparency(false) {
setFlags(WIDGET_ENABLED | WIDGET_CLEARBG);
_type = kGraphicsWidget;
- // HACK: Don't save the background. We want to be sure that redrawing
- // the widget updates the screen, even when there isn't any image
- // to draw.
- _hints &= ~THEME_HINT_SAVE_BACKGROUND;
}
GraphicsWidget::~GraphicsWidget() {
@@ -403,7 +386,7 @@ ContainerWidget::ContainerWidget(GuiObject *boss, const Common::String &name) :
}
void ContainerWidget::drawWidget() {
- g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x + _w, _y + _h), _hints, Theme::kWidgetBackgroundBorder);
+ g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x + _w, _y + _h), 0, Theme::kWidgetBackgroundBorder);
}
} // End of namespace GUI
diff --git a/gui/widget.h b/gui/widget.h
index 00bf800857..3e111f28d4 100644
--- a/gui/widget.h
+++ b/gui/widget.h
@@ -93,7 +93,6 @@ protected:
GuiObject *_boss;
Widget *_next;
uint16 _id;
- uint16 _hints;
bool _hasFocus;
Theme::WidgetStateInfo _state;
@@ -142,10 +141,6 @@ public:
void clearFlags(int flags);
int getFlags() const { return _flags; }
- void setHints(int hints) { _hints |= hints; }
- void clearHints(int hints) { _hints &= ~hints; }
- int getHints() const { return _hints; }
-
void setEnabled(bool e) { if (e) setFlags(WIDGET_ENABLED); else clearFlags(WIDGET_ENABLED); }
bool isEnabled() const;
bool isVisible() const;