diff options
author | Vicent Marti | 2008-10-09 11:49:35 +0000 |
---|---|---|
committer | Vicent Marti | 2008-10-09 11:49:35 +0000 |
commit | 1f2ce8b1881078b3de82b63f8ecdc1777f4ab9d1 (patch) | |
tree | 3b454a1b1e0dca09eada21287ed7b7e8a7cf4226 | |
parent | 5dd381932f3ed501a27fe97f48ef30331b2924d5 (diff) | |
parent | 000eedb0737dbe400d016edf213928dbb1a227d3 (diff) | |
download | scummvm-rg350-1f2ce8b1881078b3de82b63f8ecdc1777f4ab9d1.tar.gz scummvm-rg350-1f2ce8b1881078b3de82b63f8ecdc1777f4ab9d1.tar.bz2 scummvm-rg350-1f2ce8b1881078b3de82b63f8ecdc1777f4ab9d1.zip |
Manual merge of the GSoC2008 GUI branch. (71 files)
svn-id: r34757
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 §ion, 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 Binary files differdeleted file mode 100644 index 329e3a2c1b..0000000000 --- a/gui/themes/modern.zip +++ /dev/null diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip Binary files differnew file mode 100644 index 0000000000..e285958029 --- /dev/null +++ b/gui/themes/scummclassic.zip 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 Binary files differnew file mode 100644 index 0000000000..70141bfce9 --- /dev/null +++ b/gui/themes/scummodern.zip 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 Binary files differnew file mode 100644 index 0000000000..a0b91b569f --- /dev/null +++ b/gui/themes/scummodern/checkbox.bmp diff --git a/gui/themes/scummodern/cursor.bmp b/gui/themes/scummodern/cursor.bmp Binary files differnew file mode 100644 index 0000000000..e7bdb60cad --- /dev/null +++ b/gui/themes/scummodern/cursor.bmp diff --git a/gui/themes/scummodern/cursor_small.bmp b/gui/themes/scummodern/cursor_small.bmp Binary files differnew file mode 100644 index 0000000000..5f25f32f1a --- /dev/null +++ b/gui/themes/scummodern/cursor_small.bmp diff --git a/gui/themes/scummodern/helvr12-l1.fcc b/gui/themes/scummodern/helvr12-l1.fcc Binary files differnew file mode 100644 index 0000000000..651a25934a --- /dev/null +++ b/gui/themes/scummodern/helvr12-l1.fcc diff --git a/gui/themes/scummodern/logo.bmp b/gui/themes/scummodern/logo.bmp Binary files differnew file mode 100644 index 0000000000..659ec47d03 --- /dev/null +++ b/gui/themes/scummodern/logo.bmp diff --git a/gui/themes/scummodern/logo_small.bmp b/gui/themes/scummodern/logo_small.bmp Binary files differnew file mode 100644 index 0000000000..eaa998a165 --- /dev/null +++ b/gui/themes/scummodern/logo_small.bmp 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; |