diff options
author | Eugene Sandulenko | 2006-03-07 03:31:31 +0000 |
---|---|---|
committer | Eugene Sandulenko | 2006-03-07 03:31:31 +0000 |
commit | ebd583333556b2d13b1de280aabce2561ae97c4d (patch) | |
tree | 9a6eae89daf49382ee9306cb56c9e221838c40d0 | |
parent | 4c16b73bd1181f1e7daa5ff206af153ae2ef7b7f (diff) | |
download | scummvm-rg350-ebd583333556b2d13b1de280aabce2561ae97c4d.tar.gz scummvm-rg350-ebd583333556b2d13b1de280aabce2561ae97c4d.tar.bz2 scummvm-rg350-ebd583333556b2d13b1de280aabce2561ae97c4d.zip |
WIP for arbitrary widget positions. See
http://wiki.scummvm.org/index.php/GUI_Themes
Code is not yet used.
svn-id: r21115
-rw-r--r-- | gui/ThemeNew.cpp | 5 | ||||
-rw-r--r-- | gui/eval.cpp | 292 | ||||
-rw-r--r-- | gui/eval.h | 107 | ||||
-rw-r--r-- | gui/module.mk | 4 | ||||
-rw-r--r-- | gui/theme-config.cpp | 175 | ||||
-rw-r--r-- | gui/theme.cpp | 4 | ||||
-rw-r--r-- | gui/theme.h | 57 | ||||
-rw-r--r-- | gui/themes/default-theme.ini | 6 |
8 files changed, 635 insertions, 15 deletions
diff --git a/gui/ThemeNew.cpp b/gui/ThemeNew.cpp index e9d0a51c8a..24a31e5454 100644 --- a/gui/ThemeNew.cpp +++ b/gui/ThemeNew.cpp @@ -301,6 +301,11 @@ bool ThemeNew::init() { _font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont); } } + + if (isThemeLoadingRequired()) { + loadTheme(_defaultConfig); + loadTheme(_configFile, false); // Don't reset + } return true; } diff --git a/gui/eval.cpp b/gui/eval.cpp new file mode 100644 index 0000000000..6828823e68 --- /dev/null +++ b/gui/eval.cpp @@ -0,0 +1,292 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2006 The ScummVM project + * + * 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/stdafx.h" +#include "common/system.h" +#include "gui/eval.h" +#include "gui/widget.h" +#include "gui/newgui.h" + +namespace GUI { + +static bool isdelim(char c) { + if (strchr(" ;,+-<>/*%^=()", c) || c == 9 || c == '\n' || !c) + return true; + + return false; +} + +Eval::Eval() { +} + +Eval::~Eval() { + reset(); +} + +int Eval::eval(const String &input, const String §ion, const String &name, int startpos) { + int result; + + debug(3, "<%s>", input.c_str()); + + strncpy(_input, input.c_str(), 256); + _section = section; + _name = name; + _startpos = startpos; + + _pos = 0; + + getToken(); + + if (!*_token) + exprError(eBadExpr); + + level2(&result); + + debug(3, "Result: %d", result); + + return result; +} + +void Eval::level2(int *result) { + char op; + int hold; + + level3(result); + + while ((op = *_token) == '+' || op == '-') { + getToken(); + level3(&hold); + arith(op, result, &hold); + } +} + +void Eval::level3(int *result) { + char op; + int hold; + + level4(result); + + while ((op = *_token) == '*' || op == '/' || op == '%') { + getToken(); + level4(&hold); + arith(op, result, &hold); + } +} + +void Eval::level4(int *result) { + char op; + + op = 0; + if ((_tokenType == tDelimiter) && *_token == '+' || *_token == '-') { + op = *_token; + getToken(); + } + + level5(result); + + if (op) + unary(op, result); +} + +void Eval::level5(int *result) { + if ((*_token == '(') && (_tokenType == tDelimiter)) { + getToken(); + + level2(result); + + if (*_token != ')') + exprError(eUnclosedBracket); + getToken(); + } else { + primitive(result); + } +} + +void Eval::primitive(int *result) { + if (*_token == ')') + exprError(eExtraBracket); + + switch (_tokenType) { + case tVariable: + *result = lookupVar(_token); + if (*result == EVAL_UNDEF_VAR) + exprError(eUndefVar); + getToken(); + return; + case tNumber: + *result = atoi(_token); + getToken(); + return; + default: + exprError(eSyntaxError); + } +} + +void Eval::arith(char op, int *r, int *h) { + int t; + + switch (op) { + case '-': + *r = *r - *h; + break; + case '+': + *r = *r + *h; + break; + case '*': + *r = *r * *h; + break; + case '/': + *r = (*r) / (*h); + break; + case '%': + t = (*r) / (*h); + *r = *r - (t * (*h)); + break; + } +} + +void Eval::unary(char op, int *r) { + if (op == '-') + *r = -(*r); +} + +void Eval::getToken() { + char *temp; + + _tokenType = 0; + temp = _token; + + if (_input[_pos] == 0) { + *_token = 0; + _tokenType = tDelimiter; + return; + } + while (isspace(_input[_pos])) + _pos++; + + if (isdigit(_input[_pos])) { + while (!isdelim(_input[_pos])) + *temp++ = _input[_pos++]; + *temp = 0; + + _tokenType = tNumber; + return; + } + + if (isalpha(_input[_pos])) { + while (!isdelim(_input[_pos])) + *temp++ = _input[_pos++]; + *temp = 0; + _tokenType = tVariable; + return; + } + + + if (!_tokenType && isdelim(_input[_pos])) { + *temp++ = _input[_pos++]; + *temp = 0; + _tokenType = tDelimiter; + } +} + +void Eval::exprError(int err) { + static const char *errors[] = { + "Syntax error", + "Extra ')'", + "Missing ')'", + "Bad expression", + "Undefined variable" + }; + + error("%s in section [%s] expression: \"%s\" start is at: %d near token '%s'", + errors[err], _section.c_str(), _name.c_str(), _pos + _startpos, _token); +} + +struct BuiltinConsts { + const char *name; + int value; +}; + +static const BuiltinConsts builtinConsts[] = { + {"kButtonWidth", GUI::kButtonWidth}, + {"kButtonHeight", GUI::kButtonHeight}, + {"kSliderWidth", GUI::kSliderWidth}, + {"kSliderHeight", GUI::kSliderHeight}, + + {"kBigButtonWidth", GUI::kBigButtonWidth}, + {"kBigButtonHeight", GUI::kBigButtonHeight}, + {"kBigSliderWidth", GUI::kBigSliderWidth}, + {"kBigSliderHeight", GUI::kBigSliderHeight}, + {NULL, 0} +}; + +int Eval::getBuiltinVar(const char *s) { + if (!strcmp(s, "w")) + return g_system->getOverlayWidth(); + + if (!strcmp(s, "h")) + return g_system->getOverlayHeight(); + + return EVAL_UNDEF_VAR; +} + +int Eval::lookupVar(const char *s, bool includeAliases) { + int i; + int val; + + for (i = 0; builtinConsts[i].name; i++) + if (!scumm_stricmp(s, builtinConsts[i].name)) + return builtinConsts[i].value; + + val = getBuiltinVar(s); + + if (val != EVAL_UNDEF_VAR) + return val; + + String var = String(s); + if (includeAliases && _aliases.contains(var)) + var = _aliases[var]; + + if (_vars.contains(var)) + return _vars[var]; + + return EVAL_UNDEF_VAR; +} + +void Eval::setAlias(const String §ion, const String name, const String value) { + String var = String(&(name.c_str()[4])); + + _aliases[var] = value; +} + +void Eval::setVariable(const String §ion, const String name, const String value) { + String var = String(&(name.c_str()[4])); + + _vars[var] = eval(value, section, name, 0); +} + +void Eval::reset() { + _vars.clear(); + _aliases.clear(); +} + +} // end of namespace GUI diff --git a/gui/eval.h b/gui/eval.h new file mode 100644 index 0000000000..18d2c48394 --- /dev/null +++ b/gui/eval.h @@ -0,0 +1,107 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2006 The ScummVM project + * + * 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_EVAL_H +#define GUI_EVAL_H + +#include "common/stdafx.h" +#include "common/str.h" +#include "common/map.h" + +namespace GUI { + +using Common::String; +using Common::Map; + +#define EVAL_UNDEF_VAR -13375 + +enum tokenTypes { + tDelimiter, + tVariable, + tNumber, + tString +}; + +enum evalErrors { + eSyntaxError, + eExtraBracket, + eUnclosedBracket, + eBadExpr, + eUndefVar +}; + +struct IgnoreCaseComparator { + int operator()(const String& x, const String& y) const { return scumm_stricmp(x.c_str(), y.c_str()); } +}; + +class Eval { +public: + Eval(); + ~Eval(); + + int eval(const String &input, const String §ion, const String &name, int startpos); + void setAlias(const String §ion, const String name, const String value); + void setVariable(const String §ion, const String name, const String value); + + void setParent(const String name); + + void setVariable(const String name, int val) { _vars[name] = val; } + void setAlias(const String name, const String val) { _aliases[name] = val; } + + int lookupVar(String s) { return lookupVar(s.c_str()); }; + + void reset(); + + typedef Map<String, int, IgnoreCaseComparator> VariablesMap; + typedef Map<String, String, IgnoreCaseComparator> AliasesMap; + +private: + void getToken(); + void level2(int *); + void level3(int *); + void level4(int *); + void level5(int *); + void primitive(int *); + void arith(char op, int *r, int *h); + void unary(char op, int *r); + void exprError(int error); + int lookupVar(const char *s, bool includeAliases = true); + int getBuiltinVar(const char *s); + + char _input[256]; + String _section; + String _name; + + int _startpos; + + int _tokenType; + int _pos; + + char _token[256]; + + AliasesMap _aliases; + VariablesMap _vars; +}; + +} // end of namespace GUI + +#endif diff --git a/gui/module.mk b/gui/module.mk index 7ac7ba3784..c527281aa9 100644 --- a/gui/module.mk +++ b/gui/module.mk @@ -8,6 +8,7 @@ MODULE_OBJS := \ dialog.o \ editable.o \ EditTextWidget.o \ + eval.o \ launcher.o \ ListWidget.o \ message.o \ @@ -18,7 +19,8 @@ MODULE_OBJS := \ TabWidget.o \ widget.o \ theme.o \ - ThemeNew.o + ThemeNew.o \ + theme-config.o MODULE_DIRS += \ gui diff --git a/gui/theme-config.cpp b/gui/theme-config.cpp new file mode 100644 index 0000000000..feb2ec6f43 --- /dev/null +++ b/gui/theme-config.cpp @@ -0,0 +1,175 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2006 The ScummVM project + * + * 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/theme.h" +#include "gui/eval.h" + +namespace GUI { + +const char *Theme::_defaultConfigINI = "\n\ +# Define our classic greenish theme here\n\ +[XxY]\n\ +def_buttonHeight=kBigButtonHeight\n\ +def_kLineHeight=16\n\ +chooser_headline=10 6 (w - 2 * 16) (kLineHeight)\n\ +chooser_list=10 (6 + kLineHeight + 2) (w - 2 * 16) (h - self.y - buttonHeight - 12)\n\ +"; + +using Common::String; + +void Theme::processSingleLine(const String §ion, const String name, const String str) { + int level = 0; + int start = 0; + uint i; + int value; + const char *postfixes[] = {"x", "y", "w", "h"}; + int npostfix = 0; + + // Make self.BLAH work + for (i = 0; i < ARRAYSIZE(postfixes); i++) { + String from, to; + + from = String("self.") + postfixes[i]; + to = name + "." + postfixes[i]; + + _evaluator->setAlias(from, to); + _evaluator->setVariable(to, EVAL_UNDEF_VAR); + } + + for (i = 0; i < str.size(); i++) { + if (isspace(str[i]) && level == 0) { + value = _evaluator->eval(String(&(str.c_str()[start]), i - start), section, name, start); + _evaluator->setVariable(name + "." + postfixes[npostfix++], value); + start = i + 1; + } + if (str[i] == '(') + level++; + + if (str[i] == ')') { + if (level == 0) { + error("Extra ')' in section: [%s] expression: \"%s\" start is at: %d", + section.c_str(), name.c_str(), start); + } + level--; + } + } + + if (level > 0) + error("Missing ')' in section: [%s] expression: \"%s\" start is at: %d", + section.c_str(), name.c_str(), start); + + value = _evaluator->eval(String(&(str.c_str()[start]), i - start), section, name, start); + + // process VAR=VALUE construct + if (npostfix == 0) + _evaluator->setVariable(name, value); + else + _evaluator->setVariable(name + "." + postfixes[npostfix], value); + + // If we have all 4 parameters, set .x2 and .y2 + if (npostfix == 4) { + _evaluator->setVariable(name + ".x2", _evaluator->lookupVar(name + ".x") + + _evaluator->lookupVar(name + ".w")); + _evaluator->setVariable(name + ".y2", _evaluator->lookupVar(name + ".y") + + _evaluator->lookupVar(name + ".h")); + } +} + + +void Theme::processResSection(Common::ConfigFile &config, String name, bool skipDefs) { + debug(3, "Reading section: [%s]", name.c_str()); + + const Common::ConfigFile::SectionKeyList &keys = config.getKeys(name); + + Common::ConfigFile::SectionKeyList::const_iterator iterk; + for (iterk = keys.begin(); iterk != keys.end(); ++iterk) { + if (iterk->key == "set_parent") { + setParent(iterk->value); + continue; + } + if (iterk->key.hasPrefix("set_")) { + _evaluator->setAlias(name, iterk->key, iterk->value); + continue; + } + if (iterk->key.hasPrefix("def_")) { + if (!skipDefs) + _evaluator->setVariable(name, iterk->key, iterk->value); + continue; + } + if (iterk->key == "use") { + if (iterk->value == name) + error("Theme section [%s]: cannot use itself", name.c_str()); + if (!config.hasSection(name)) + error("Undefined use of section [%s]", name.c_str()); + processResSection(config, iterk->value, true); + continue; + } + processSingleLine(name, iterk->key, iterk->value); + } +} + +void Theme::setParent(const String &name) { + const char *postfixes[] = {"x", "y", "w", "h", "x2", "y2"}; + int i; + + for (i = 0; i < ARRAYSIZE(postfixes); i++) { + String from, to; + + from = String("parent.") + postfixes[i]; + to = name + "." + postfixes[i]; + + _evaluator->setAlias(from, to); + } +} + +bool Theme::isThemeLoadingRequired() { + int x = g_system->getOverlayWidth(), y = g_system->getOverlayHeight(); + + if (_loadedThemeX == x && _loadedThemeY == y) + return false; + + _loadedThemeX = x; + _loadedThemeY = y; + + return true; +} + +void Theme::loadTheme(Common::ConfigFile &config, bool reset) { + char name[80]; + int x = g_system->getOverlayWidth(), y = g_system->getOverlayHeight(); + + if (reset) + _evaluator->reset(); + + strcpy(name, "XxY"); + if (config.hasSection(name)) + processResSection(config, name); + + sprintf(name, "%dxY", x); + if (config.hasSection(name)) + processResSection(config, name); + + sprintf(name, "%dx%d", x, y); + if (config.hasSection(name)) + processResSection(config, name); +} + +} // End of namespace GUI diff --git a/gui/theme.cpp b/gui/theme.cpp index c384b75163..4eb9159f08 100644 --- a/gui/theme.cpp +++ b/gui/theme.cpp @@ -56,6 +56,10 @@ bool ThemeClassic::init() { _font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont); } } + + if (isThemeLoadingRequired()) + loadTheme(_defaultConfig); + return true; } diff --git a/gui/theme.h b/gui/theme.h index ccf3d31f23..9befabdb87 100644 --- a/gui/theme.h +++ b/gui/theme.h @@ -31,8 +31,12 @@ #include "graphics/surface.h" #include "graphics/fontman.h" +#include "gui/eval.h" + namespace GUI { +typedef Common::String String; + // Hints to the theme engine that the widget is used in a non-standard way. enum { @@ -54,10 +58,17 @@ enum { THEME_HINT_USE_SHADOW = 1 << 4 }; + class Theme { public: - Theme() : _drawArea(), _configFile() {} - virtual ~Theme() {} + Theme() : _drawArea(), _configFile(), _loadedThemeX(0), _loadedThemeY(0) { + Common::MemoryReadStream s((const byte *)_defaultConfigINI, strlen(_defaultConfigINI)); + _defaultConfig.loadFromStream(s); + + _evaluator = new Eval(); + } + + virtual ~Theme() { delete _evaluator;} enum kTextAlign { kTextAlignLeft, @@ -158,9 +169,23 @@ public: return kTextAlignCenter; } + void processResSection(Common::ConfigFile &config, String name, bool skipDefs = false); + void processSingleLine(const String §ion, const String name, const String str); + void setParent(const String &name); + + bool isThemeLoadingRequired(); + void loadTheme(Common::ConfigFile &config, bool reset = true); + protected: Common::Rect _drawArea; Common::ConfigFile _configFile; + Common::ConfigFile _defaultConfig; + + Eval *_evaluator; + +private: + static const char *_defaultConfigINI; + int _loadedThemeX, _loadedThemeY; }; #define OLDGUI_TRANSPARENCY @@ -186,21 +211,24 @@ public: void resetDrawArea(); + + typedef Common::String String; + const Graphics::Font *getFont() const { return _font; } int getFontHeight() const { if (_initOk) return _font->getFontHeight(); return 0; } - int getStringWidth(const Common::String &str) const { if (_initOk) return _font->getStringWidth(str); return 0; } + int getStringWidth(const String &str) const { if (_initOk) return _font->getStringWidth(str); return 0; } int getCharWidth(byte c) const { if (_initOk) return _font->getCharWidth(c); return 0; } void drawDialogBackground(const Common::Rect &r, uint16 hints, kState state); - void drawText(const Common::Rect &r, const Common::String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis); + void drawText(const Common::Rect &r, const String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis); void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, kState state); void drawWidgetBackground(const Common::Rect &r, uint16 hints, kWidgetBackground background, kState state); - void drawButton(const Common::Rect &r, const Common::String &str, kState state); + void drawButton(const Common::Rect &r, const String &str, kState state); void drawSurface(const Common::Rect &r, const Graphics::Surface &surface, kState state); void drawSlider(const Common::Rect &r, int width, kState state); - void drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, kState state); - void drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array<Common::String> &tabs, int active, uint16 hints, kState state); + void drawCheckbox(const Common::Rect &r, const String &str, bool checked, kState state); + void drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array<String> &tabs, int active, uint16 hints, kState state); void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, kScrollbarState, kState state); void drawCaret(const Common::Rect &r, bool erase, kState state); void drawLineSeparator(const Common::Rect &r, kState state); @@ -234,9 +262,10 @@ private: }; #ifndef DISABLE_FANCY_THEMES + class ThemeNew : public Theme { public: - ThemeNew(OSystem *system, Common::String stylefile); + ThemeNew(OSystem *system, String stylefile); virtual ~ThemeNew(); bool init(); @@ -258,19 +287,19 @@ public: const Graphics::Font *getFont() const { return _font; } int getFontHeight() const { if (_font) return _font->getFontHeight(); return 0; } - int getStringWidth(const Common::String &str) const { if (_font) return _font->getStringWidth(str); return 0; } + int getStringWidth(const String &str) const { if (_font) return _font->getStringWidth(str); return 0; } int getCharWidth(byte c) const { if (_font) return _font->getCharWidth(c); return 0; } void drawDialogBackground(const Common::Rect &r, uint16 hints, kState state); - void drawText(const Common::Rect &r, const Common::String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis); + void drawText(const Common::Rect &r, const String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis); void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, kState state); void drawWidgetBackground(const Common::Rect &r, uint16 hints, kWidgetBackground background, kState state); - void drawButton(const Common::Rect &r, const Common::String &str, kState state); + void drawButton(const Common::Rect &r, const String &str, kState state); void drawSurface(const Common::Rect &r, const Graphics::Surface &surface, kState state); void drawSlider(const Common::Rect &r, int width, kState state); - void drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, kState state); - void drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array<Common::String> &tabs, int active, uint16 hints, kState state); + void drawCheckbox(const Common::Rect &r, const String &str, bool checked, kState state); + void drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array<String> &tabs, int active, uint16 hints, kState state); void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, kScrollbarState, kState state); void drawCaret(const Common::Rect &r, bool erase, kState state); void drawLineSeparator(const Common::Rect &r, kState state); @@ -379,7 +408,7 @@ private: kImageHandlesMax }; - const Common::String *_imageHandles; + const String *_imageHandles; const Graphics::Surface **_images; enum kColorHandles { diff --git a/gui/themes/default-theme.ini b/gui/themes/default-theme.ini index 5be2336963..71f9d59891 100644 --- a/gui/themes/default-theme.ini +++ b/gui/themes/default-theme.ini @@ -127,3 +127,9 @@ shadow_left_width=2 shadow_right_width=4 shadow_top_height=2 pshadow_bottom_height=4 + +[XxY] +def_buttonHeight=kBigButtonHeight +def_kLineHeight=16 +chooser_headline=10 6 (w - 2 * 16) (kLineHeight) +chooser_list=10 (6 + kLineHeight + 2) (w - 2 * 16) (h - self.y - buttonHeight - 12) |