2006-03-07 03:31:31 +00:00
|
|
|
/* 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\
|
2006-03-07 05:50:37 +00:00
|
|
|
[320xY]\n\
|
2006-03-08 01:42:02 +00:00
|
|
|
def_widgetSize=kNormalWidgetSize\n\
|
|
|
|
def_buttonWidth=kButtonWidth\n\
|
2006-03-07 05:50:37 +00:00
|
|
|
def_buttonHeight=kButtonHeight\n\
|
2006-03-08 01:42:02 +00:00
|
|
|
def_sliderWidth=kSliderWidth\n\
|
|
|
|
def_sliderHeight=kSliderHeight\n\
|
2006-03-07 05:50:37 +00:00
|
|
|
def_kLineHeight=12\n\
|
2006-03-08 01:42:02 +00:00
|
|
|
def_kFontHeight=10\n\
|
|
|
|
def_globOptionsW=(w - 2 * 10)\n\
|
|
|
|
def_globOptionsH=(h - 1 * 40)\n\
|
|
|
|
def_tabPopupsLabelW=100\n\
|
|
|
|
def_midiControlsSpacing=1\n\
|
2006-03-07 05:50:37 +00:00
|
|
|
use=XxY\n\
|
|
|
|
\n\
|
2006-03-07 03:31:31 +00:00
|
|
|
[XxY]\n\
|
2006-03-08 01:42:02 +00:00
|
|
|
def_widgetSize=kBigWidgetSize\n\
|
|
|
|
def_buttonWidth=kBigButtonWidth\n\
|
2006-03-07 03:31:31 +00:00
|
|
|
def_buttonHeight=kBigButtonHeight\n\
|
2006-03-08 01:42:02 +00:00
|
|
|
def_sliderWidth=kBigSliderWidth\n\
|
|
|
|
def_sliderHeight=kBigSliderHeight\n\
|
2006-03-07 03:31:31 +00:00
|
|
|
def_kLineHeight=16\n\
|
2006-03-08 01:42:02 +00:00
|
|
|
def_kFontHeight=14\n\
|
|
|
|
def_globOptionsW=(w - 2 * 10)\n\
|
|
|
|
def_globOptionsH=(h - 2 * 40)\n\
|
|
|
|
def_tabPopupsLabelW=150\n\
|
|
|
|
def_midiControlsSpacing=2\n\
|
2006-03-07 03:31:31 +00:00
|
|
|
chooser_headline=10 6 (w - 2 * 16) (kLineHeight)\n\
|
|
|
|
chooser_list=10 (6 + kLineHeight + 2) (w - 2 * 16) (h - self.y - buttonHeight - 12)\n\
|
2006-03-08 01:42:02 +00:00
|
|
|
\n\
|
|
|
|
## launcher\n\
|
2006-03-07 05:39:52 +00:00
|
|
|
hBorder=10\n\
|
|
|
|
launcher_version=hBorder 8 (w - 2 * hBorder) kLineHeight\n\
|
|
|
|
top=(h - 8 - buttonHeight)\n\
|
|
|
|
numButtons=4\n\
|
|
|
|
space=8\n\
|
2006-03-08 01:42:02 +00:00
|
|
|
butWidth=((w - 2 * hBorder - space * (numButtons - 1)) / numButtons)\n\
|
|
|
|
launcher_quit_button=hBorder top butWidth buttonHeight\n\
|
|
|
|
launcher_about_button=(prev.x2 + space) top butWidth buttonHeight\n\
|
|
|
|
launcher_options_button=(prev.x2 + space) top butWidth buttonHeight\n\
|
|
|
|
launcher_start_button=(prev.x2 + space) top butWidth buttonHeight\n\
|
2006-03-07 05:39:52 +00:00
|
|
|
top=(top - buttonHeight * 2)\n\
|
|
|
|
numButtons=3\n\
|
|
|
|
space=10\n\
|
2006-03-08 01:42:02 +00:00
|
|
|
butWidth=((w - 2 * hBorder - space * (numButtons - 1)) / numButtons)\n\
|
|
|
|
launcher_addGame_button=hBorder top butWidth buttonHeight\n\
|
|
|
|
launcher_editGame_button=(prev.x2 + space) top butWidth buttonHeight\n\
|
|
|
|
launcher_removeGame_button=(prev.x2 + space) top butWidth buttonHeight\n\
|
2006-03-07 05:39:52 +00:00
|
|
|
launcher_list=hBorder (kLineHeight + 16) (w - 2 * hBorder) (top - kLineHeight - 20)\n\
|
2006-03-08 01:42:02 +00:00
|
|
|
\n\
|
|
|
|
# global options\n\
|
|
|
|
globaloptions=10 40 globOptionsW globOptionsH\n\
|
|
|
|
set_parent=globaloptions\n\
|
|
|
|
vBorder=5\n\
|
|
|
|
globaloptions_tabwidget=0, vBorder parent.w (parent.h - buttonHeight -8 - 2 * vBorder)\n\
|
|
|
|
\n\
|
|
|
|
# graphics tab\n\
|
|
|
|
opYoffset=vBorder\n\
|
|
|
|
opWidth=globOptionsW\n\
|
|
|
|
useWithPrefix=graphicsControls globaloptions_\n\
|
|
|
|
\n\
|
|
|
|
# audio tab\n\
|
|
|
|
opYoffset=vBorder\n\
|
|
|
|
opWidth=globOptionsW\n\
|
|
|
|
useWithPrefix=audioControls globaloptions_\n\
|
|
|
|
useWithPrefix=volumeControls globaloptions_\n\
|
|
|
|
\n\
|
|
|
|
# MIDI tab\n\
|
|
|
|
opYoffset=vBorder\n\
|
|
|
|
opWidth=globOptionsW\n\
|
|
|
|
useWithPrefix=midiControls globaloptions_\n\
|
|
|
|
\n\
|
|
|
|
# paths tab\n\
|
|
|
|
yoffset=vBorder\n\
|
|
|
|
globaloptions_savebutton=5 yoffset (buttonWidth + 5) buttonHeight\n\
|
|
|
|
globaloptions_savepath=(prev.x2 + 20) (vBorder + 3) (parent.w - (5 + buttonWidth + 20) - 10) kLineHeight\n\
|
|
|
|
yoffset=(yoffset + buttonHeight + 4)\n\
|
|
|
|
globaloptions_extrabutton=5 yoffset (buttonWidth + 5) buttonHeight\n\
|
|
|
|
globaloptions_extrapath=(prev.x2 + 20) (vBorder + 3) (parent.w - (5 + buttonWidth + 20) - 10) kLineHeight\n\
|
|
|
|
yoffset=(yoffset + buttonHeight + 4)\n\
|
|
|
|
globaloptions_keysbutton=5 yoffset buttonWidth buttonHeight\n\
|
|
|
|
\n\
|
|
|
|
globaloptions_ok=(parent.w - (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight\n\
|
|
|
|
globaloptions_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight\n\
|
|
|
|
\n\
|
|
|
|
# game options\n\
|
|
|
|
opYoffset=(vBorder + buttonHeight)\n\
|
|
|
|
opWidth=globOptionsW\n\
|
|
|
|
useWithPrefix=graphicsControls gameoptions_\n\
|
|
|
|
\n\
|
|
|
|
opYoffset=(vBorder + buttonHeight)\n\
|
|
|
|
useWithPrefix=audioControls gameoptions_\n\
|
|
|
|
\n\
|
|
|
|
opYoffset=(vBorder + buttonHeight)\n\
|
|
|
|
useWithPrefix=volumeControls gameoptions_\n\
|
|
|
|
\n\
|
|
|
|
opYoffset=(vBorder + buttonHeight)\n\
|
|
|
|
useWithPrefix=midiControls gameoptions_\n\
|
|
|
|
\n\
|
|
|
|
### SCUMM game options\n\
|
|
|
|
opYoffset=8\n\
|
|
|
|
useWithPrefix=volumeControls scummoptions_\n\
|
|
|
|
\n\
|
|
|
|
[graphicsControls]\n\
|
|
|
|
gcx=10\n\
|
|
|
|
gcw=(opWidth - 2 * 10)\n\
|
|
|
|
grModePopup=(gcx - 5) opYoffset (gcw + 5) kLineHeight\n\
|
|
|
|
opYoffset=(opYoffset + kLineHeight + 4)\n\
|
|
|
|
grRenderPopup=(gcx - 5) opYoffset (gcw + 5) kLineHeight\n\
|
|
|
|
opYoffset=(opYoffset + kLineHeight + 4)\n\
|
|
|
|
grFullscreenCheckbox=gcx opYoffset (kFontHeight + 10 + 96) buttonHeight\n\
|
|
|
|
opYoffset=(opYoffset + buttonHeight)\n\
|
|
|
|
grAspectCheckbox=gcx opYoffset (kFontHeight + 10 + 136) buttonHeight\n\
|
|
|
|
opYoffset=(opYoffset + buttonHeight)\n\
|
|
|
|
\n\
|
|
|
|
[audioControls]\n\
|
|
|
|
aux=10\n\
|
|
|
|
auw=(opWidth - 2 * 10)\n\
|
|
|
|
auMidiPopup=(aux - 5) opYoffset (auw + 5) kLineHeight\n\
|
|
|
|
opYoffset=(opYoffset + kLineHeight + 4)\n\
|
|
|
|
auSubtitlesCheckbox=aux opYoffset (kFontHeight + 10 + 102) buttonHeight\n\
|
|
|
|
opYoffset=(opYoffset + buttonHeight + 18)\n\
|
|
|
|
\n\
|
|
|
|
[volumeControls]\n\
|
|
|
|
vctextw=95\n\
|
|
|
|
vcxoff=(vctextw + 15)\n\
|
|
|
|
vcMusicText=10 (opYoffset + 2) vctextw kLineHeight\n\
|
|
|
|
vcMusicSlider=vcxoff opYoffset sliderWidth sliderHeight\n\
|
|
|
|
vcMusicLabel=(vcxoff + prev.w + 10) (opYoffset + 2) 24 kLineHeight\n\
|
|
|
|
opYoffset=(opYoffset + sliderHeight + 4)\n\
|
|
|
|
vcSfxText=10 (opYoffset + 2) vctextw kLineHeight\n\
|
|
|
|
vcSfxSlider=vcxoff opYoffset sliderWidth sliderHeight\n\
|
|
|
|
vcSfxLabel=(vcxoff + prev.w + 10) (opYoffset + 2) 24 kLineHeight\n\
|
|
|
|
opYoffset=(opYoffset + sliderHeight + 4)\n\
|
|
|
|
vcSpeechText=10 (opYoffset + 2) vctextw kLineHeight\n\
|
|
|
|
vcSpeechSlider=vcxoff opYoffset sliderWidth sliderHeight\n\
|
|
|
|
vcSpeechLabel=(vcxoff + prev.w + 10) (opYoffset + 2) 24 kLineHeight\n\
|
|
|
|
opYoffset=(opYoffset + sliderHeight + 4)\n\
|
|
|
|
\n\
|
|
|
|
[midiControls]\n\
|
|
|
|
mcx=10\n\
|
|
|
|
mcFontButton=mcx opYoffset buttonWidth buttonHeight\n\
|
|
|
|
mcFontPath=(prev.x2 + 20) (opYoffset + 3) (opWidth - (buttonWidth + 20) - 10) kLineHeight\n\
|
|
|
|
opYoffset=(opYoffset + buttonHeight + 2 * midiControlsSpacing)\n\
|
|
|
|
mcMixedCheckbox=mcx opYoffset (kFontHeight + 10 + 135) buttonHeight\n\
|
|
|
|
opYoffset=(opYoffset + buttonHeight + midiControlsSpacing)\n\
|
|
|
|
mcMt32Checkbox=mcx opYoffset (kFontHeight + 10 + 256) buttonHeight\n\
|
|
|
|
opYoffset=(opYoffset + buttonHeight + midiControlsSpacing)\n\
|
|
|
|
mcGSCheckbox=mcx opYoffset (kFontHeight + 10 + 142) buttonHeight\n\
|
|
|
|
opYoffset=(opYoffset + buttonHeight + midiControlsSpacing)\n\
|
2006-03-07 03:31:31 +00:00
|
|
|
";
|
|
|
|
|
|
|
|
using Common::String;
|
|
|
|
|
2006-03-08 01:42:02 +00:00
|
|
|
void Theme::processSingleLine(const String §ion, const String prefix, const String name, const String str) {
|
2006-03-07 03:31:31 +00:00
|
|
|
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];
|
2006-03-08 01:42:02 +00:00
|
|
|
to = prefix + name + "." + postfixes[i];
|
2006-03-07 03:31:31 +00:00
|
|
|
|
|
|
|
_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);
|
2006-03-08 01:42:02 +00:00
|
|
|
_evaluator->setVariable(prefix + name + "." + postfixes[npostfix++], value);
|
2006-03-07 03:31:31 +00:00
|
|
|
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
|
2006-03-08 01:42:02 +00:00
|
|
|
_evaluator->setVariable(prefix + name + "." + postfixes[npostfix], value);
|
2006-03-07 03:31:31 +00:00
|
|
|
|
|
|
|
// If we have all 4 parameters, set .x2 and .y2
|
2006-03-07 05:39:52 +00:00
|
|
|
if (npostfix == 3) {
|
2006-03-08 01:42:02 +00:00
|
|
|
_evaluator->setVariable(prefix + name + ".x2",
|
|
|
|
_evaluator->getVar(prefix + name + ".x") + _evaluator->getVar(prefix + name + ".w"));
|
|
|
|
_evaluator->setVariable(prefix + name + ".y2",
|
|
|
|
_evaluator->getVar(prefix +name + ".y") + _evaluator->getVar(prefix + name + ".h"));
|
2006-03-07 03:31:31 +00:00
|
|
|
}
|
2006-03-07 05:39:52 +00:00
|
|
|
|
2006-03-07 13:52:53 +00:00
|
|
|
if (npostfix != 0)
|
2006-03-08 01:42:02 +00:00
|
|
|
setSpecialAlias("prev", prefix + name);
|
2006-03-07 03:31:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-03-07 19:02:42 +00:00
|
|
|
void Theme::processResSection(Common::ConfigFile &config, String name, bool skipDefs, const String prefix) {
|
2006-03-07 03:31:31 +00:00
|
|
|
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") {
|
2006-03-07 19:02:42 +00:00
|
|
|
setSpecialAlias("parent", prefix + iterk->value);
|
2006-03-07 03:31:31 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (iterk->key.hasPrefix("set_")) {
|
2006-03-07 19:02:42 +00:00
|
|
|
_evaluator->setAlias(name, iterk->key, prefix + iterk->value);
|
2006-03-07 03:31:31 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (iterk->key.hasPrefix("def_")) {
|
|
|
|
if (!skipDefs)
|
2006-03-07 19:02:42 +00:00
|
|
|
_evaluator->setVariable(name, prefix + iterk->key, iterk->value);
|
2006-03-07 03:31:31 +00:00
|
|
|
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;
|
|
|
|
}
|
2006-03-07 19:02:42 +00:00
|
|
|
if (iterk->key == "useWithPrefix") {
|
2006-03-07 19:23:38 +00:00
|
|
|
const char *temp = iterk->value.c_str();
|
|
|
|
const char *pos = strrchr(temp, ' ');
|
|
|
|
String n, pref;
|
|
|
|
|
|
|
|
if (pos == NULL)
|
|
|
|
error("2 arguments required for useWithPrefix keyword");
|
|
|
|
|
|
|
|
n = String(temp, strchr(temp, ' ') - temp);
|
|
|
|
pref = String(pos + 1);
|
|
|
|
|
|
|
|
if (n == name)
|
|
|
|
error("Theme section [%s]: cannot use itself", n.c_str());
|
|
|
|
if (!config.hasSection(n))
|
|
|
|
error("Undefined use of section [%s]", n.c_str());
|
|
|
|
processResSection(config, n, true, pref);
|
2006-03-07 19:02:42 +00:00
|
|
|
continue;
|
|
|
|
}
|
2006-03-08 01:42:02 +00:00
|
|
|
processSingleLine(name, prefix, iterk->key, iterk->value);
|
2006-03-07 03:31:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-07 05:39:52 +00:00
|
|
|
void Theme::setSpecialAlias(const String alias, const String &name) {
|
2006-03-07 03:31:31 +00:00
|
|
|
const char *postfixes[] = {"x", "y", "w", "h", "x2", "y2"};
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAYSIZE(postfixes); i++) {
|
|
|
|
String from, to;
|
|
|
|
|
2006-03-07 05:39:52 +00:00
|
|
|
from = alias + "." + postfixes[i];
|
2006-03-07 03:31:31 +00:00
|
|
|
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);
|
|
|
|
|
2006-03-07 18:26:04 +00:00
|
|
|
sprintf(name, "Xx%d", y);
|
|
|
|
if (config.hasSection(name))
|
|
|
|
processResSection(config, name);
|
|
|
|
|
2006-03-07 03:31:31 +00:00
|
|
|
sprintf(name, "%dx%d", x, y);
|
|
|
|
if (config.hasSection(name))
|
|
|
|
processResSection(config, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // End of namespace GUI
|