aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--graphics/VectorRenderer.cpp14
-rw-r--r--graphics/VectorRenderer.h20
-rw-r--r--gui/InterfaceManager.cpp42
-rw-r--r--gui/ThemeParser.cpp41
-rw-r--r--gui/ThemeParser.h287
5 files changed, 343 insertions, 61 deletions
diff --git a/graphics/VectorRenderer.cpp b/graphics/VectorRenderer.cpp
index abfd53edcd..0194231427 100644
--- a/graphics/VectorRenderer.cpp
+++ b/graphics/VectorRenderer.cpp
@@ -54,19 +54,19 @@ VectorRenderer *createRenderer(int mode) {
void VectorRenderer::drawStep(const Common::Rect &area, const DrawStep &step) {
if (step.flags & DrawStep::kStepCallbackOnly) {
- (this->*(step.drawing_call))(area, step);
+ (this->*(step.drawingCall))(area, step);
return;
}
if (step.flags & DrawStep::kStepSetBG)
- setBgColor(step.color2.r, step.color2.g, step.color2.b);
+ setBgColor(step.bgColor.r, step.bgColor.g, step.bgColor.b);
if (step.flags & DrawStep::kStepSetFG)
- setFgColor(step.color1.r, step.color1.g, step.color1.b);
+ setFgColor(step.fgColor.r, step.fgColor.g, step.fgColor.b);
if (step.flags & DrawStep::kStepSetGradient)
- setGradientColors(step.color1.r, step.color1.g, step.color1.b,
- step.color2.r, step.color2.g, step.color2.b);
+ setGradientColors(step.gradColor1.r, step.gradColor1.g, step.gradColor1.b,
+ step.gradColor2.r, step.gradColor2.g, step.gradColor2.b);
if (step.flags & DrawStep::kStepSetShadow)
shadowEnable(step.shadow);
@@ -78,12 +78,12 @@ void VectorRenderer::drawStep(const Common::Rect &area, const DrawStep &step) {
setStrokeWidth(step.stroke);
if (step.flags & DrawStep::kStepSetFillMode)
- setFillMode((FillMode)step.fill_mode);
+ setFillMode((FillMode)step.fillMode);
if (step.flags & DrawStep::kStepSettingsOnly)
return;
- (this->*(step.drawing_call))(area, step);
+ (this->*(step.drawingCall))(area, step);
}
/********************************************************************
diff --git a/graphics/VectorRenderer.h b/graphics/VectorRenderer.h
index 310f32f856..b4c4bb656d 100644
--- a/graphics/VectorRenderer.h
+++ b/graphics/VectorRenderer.h
@@ -45,10 +45,12 @@ struct DrawStep {
struct {
uint8 r, g, b;
}
- color1, /** Foreground color/gradient start */
- color2; /** Background color/gradient end */
+ fgColor, /** Foreground color */
+ bgColor, /** backgroudn color */
+ gradColor1, /** gradient start*/
+ gradColor2; /** gradient end */
- bool fill_area; /** If enabled, the draw step occupies the whole drawing area */
+ bool fillArea; /** If enabled, the draw step occupies the whole drawing area */
struct {
uint16 pos;
@@ -60,12 +62,12 @@ struct DrawStep {
uint8 shadow, stroke, factor, radius; /** Misc options... */
- uint8 fill_mode; /** active fill mode */
- uint8 extra_data; /** Generic parameter for extra options (orientation/bevel) */
+ uint8 fillMode; /** active fill mode */
+ uint8 extraData; /** Generic parameter for extra options (orientation/bevel) */
uint32 scale; /** scale of all the coordinates in FIXED POINT with 16 bits mantissa */
- void (VectorRenderer::*drawing_call)(const Common::Rect &, const DrawStep &); /** Pointer to drawing function */
+ void (VectorRenderer::*drawingCall)(const Common::Rect &, const DrawStep &); /** Pointer to drawing function */
enum DrawStepFlags {
kStepCallbackOnly = (1 << 0),
@@ -330,7 +332,7 @@ public:
}
void stepGetPositions(const DrawStep &step, const Common::Rect &area, uint16 &in_x, uint16 &in_y, uint16 &in_w, uint16 &in_h) {
- if (step.fill_area) {
+ if (step.fillArea) {
in_x = area.left;
in_y = area.top;
in_w = area.width();
@@ -392,13 +394,13 @@ public:
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.extra_data);
+ 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, step.extra_data);
+ drawBeveledSquare(x, y, w, h, step.extraData);
}
/**
diff --git a/gui/InterfaceManager.cpp b/gui/InterfaceManager.cpp
index 380f1d4644..ae52387502 100644
--- a/gui/InterfaceManager.cpp
+++ b/gui/InterfaceManager.cpp
@@ -163,43 +163,43 @@ int InterfaceManager::runGUI() {
Graphics::DrawStep *steps = new Graphics::DrawStep[5];
- steps[0].color1.r = 214;
- steps[0].color1.g = 113;
- steps[0].color1.b = 8;
- steps[0].color2.r = 240;
- steps[0].color2.g = 200;
- steps[0].color2.b = 25;
- steps[0].fill_mode = VectorRenderer::kFillGradient;
- steps[0].drawing_call = &VectorRenderer::drawCallback_FILLSURFACE;
+ steps[0].gradColor1.r = 214;
+ steps[0].gradColor1.g = 113;
+ steps[0].gradColor1.b = 8;
+ steps[0].gradColor2.r = 240;
+ steps[0].gradColor2.g = 200;
+ steps[0].gradColor2.b = 25;
+ steps[0].fillMode = VectorRenderer::kFillGradient;
+ steps[0].drawingCall = &VectorRenderer::drawCallback_FILLSURFACE;
steps[0].flags = DrawStep::kStepSetGradient | DrawStep::kStepSetFillMode;
- steps[1].color1.r = 206;
- steps[1].color1.g = 121;
- steps[1].color1.b = 99;
- steps[1].color2.r = 173;
- steps[1].color2.g = 40;
- steps[1].color2.b = 8;
+ steps[1].gradColor1.r = 206;
+ steps[1].gradColor1.g = 121;
+ steps[1].gradColor1.b = 99;
+ steps[1].gradColor2.r = 173;
+ steps[1].gradColor2.g = 40;
+ steps[1].gradColor2.b = 8;
steps[1].radius = 8; // radius
- steps[1].fill_area = true;
- steps[1].drawing_call = &VectorRenderer::drawCallback_ROUNDSQ;
+ steps[1].fillArea = true;
+ steps[1].drawingCall = &VectorRenderer::drawCallback_ROUNDSQ;
steps[1].flags = DrawStep::kStepSetGradient;
steps[1].scale = (1 << 16);
steps[2].radius = 8; // radius
- steps[2].fill_area = false;
+ steps[2].fillArea = false;
steps[2].x.relative = true;
steps[2].x.pos = 32;
steps[2].y.relative = false;
steps[2].y.pos = 32;
steps[2].w = 128;
steps[2].h = 32;
- steps[2].drawing_call = &VectorRenderer::drawCallback_ROUNDSQ;
+ steps[2].drawingCall = &VectorRenderer::drawCallback_ROUNDSQ;
steps[2].flags = DrawStep::kStepCallbackOnly;
steps[2].scale = (1 << 16);
- steps[3].color1.r = 255;
- steps[3].color1.g = 255;
- steps[3].color1.b = 255;
+ steps[3].fgColor.r = 255;
+ steps[3].fgColor.g = 255;
+ steps[3].fgColor.b = 255;
steps[3].flags = DrawStep::kStepSettingsOnly | DrawStep::kStepSetFG;
Common::Rect area = Common::Rect(32, 32, 256, 256);
diff --git a/gui/ThemeParser.cpp b/gui/ThemeParser.cpp
index 498679c88f..267efba371 100644
--- a/gui/ThemeParser.cpp
+++ b/gui/ThemeParser.cpp
@@ -44,10 +44,10 @@ namespace GUI {
void ThemeParser::debug_testEval() {
static const char *debugConfigText =
- "</* lol this is just a moronic test */drawdata id = \"background_default\" cache = true>"
- "<draw func = \"roundedsq\" /*/fill = \"gradient\" gradient_start = \"255, 255, 128\" gradient_end = \"128, 128, 128\" size = \"auto\"/>"
- "<draw func = \"roundedsq\" fill = \"none\" color = /*\"0, 0, 0\"*/\"0, 1, 2\" size = \"auto\"/>"
- "</ drawdata>/* lol this is just a simple test*/";
+ "</* lol this is just a moronic test */drawdata id = \"background_default\" cache = true>\n"
+ "<drawstep func = \"roundedsq\" fill = \"gradient\" gradient_start = \"255, 255, 128\" gradient_end = \"128, 128, 128\" size = \"auto\"/>\n"
+ "//<drawstep func = \"roundedsq\" fill = \"none\" color = /*\"0, 0, 0\"*/\"0, 1, 2\" size = \"auto\"/>\n"
+ "</ drawdata>/* lol this is just a simple test*/\n";
_text = strdup(debugConfigText);
parse();
@@ -59,7 +59,7 @@ void ThemeParser::parserError(const char *error_string) {
printf("PARSER ERROR: %s\n", error_string);
}
-void ThemeParser::parserCallback_DRAW() {
+void ThemeParser::parserCallback_DRAWSTEP() {
printf("Draw callback!\n");
}
@@ -68,29 +68,28 @@ void ThemeParser::parserCallback_DRAWDATA() {
}
void ThemeParser::parseActiveKey(bool closed) {
- printf("Parsed key %s.\n", _activeKey.top().c_str());
+ printf("Parsed key %s.\n", _activeKey.top()->name.c_str());
- if (!_callbacks.contains(_activeKey.top())) {
+ if (!_callbacks.contains(_activeKey.top()->name)) {
parserError("Unhandled value inside key.");
return;
}
// Don't you just love C++ syntax? Water clear.
- (this->*(_callbacks[_activeKey.top()]))();
+ (this->*(_callbacks[_activeKey.top()->name]))();
- for (Common::StringMap::const_iterator t = _keyValues.top().begin(); t != _keyValues.top().end(); ++t)
+ for (Common::StringMap::const_iterator t = _activeKey.top()->values.begin(); t != _activeKey.top()->values.end(); ++t)
printf(" Key %s = %s\n", t->_key.c_str(), t->_value.c_str());
if (closed) {
- _keyValues.pop();
- _activeKey.pop();
+ delete _activeKey.pop();
}
}
bool ThemeParser::parseKeyValue(Common::String keyName) {
- assert(_keyValues.empty() == false);
+ assert(_activeKey.empty() == false);
- if (_keyValues.top().contains(keyName))
+ if (_activeKey.top()->values.contains(keyName))
return false;
_token.clear();
@@ -109,7 +108,7 @@ bool ThemeParser::parseKeyValue(Common::String keyName) {
return false;
}
- _keyValues.top()[keyName] = _token;
+ _activeKey.top()->values[keyName] = _token;
return true;
}
@@ -120,7 +119,6 @@ bool ThemeParser::parse() {
_state = kParserNeedKey;
_pos = 0;
- _keyValues.clear();
_activeKey.clear();
while (_text[_pos]) {
@@ -160,11 +158,12 @@ bool ThemeParser::parse() {
}
if (activeClosure) {
- if (_activeKey.empty() || _token != _activeKey.top())
+ if (_activeKey.empty() || _token != _activeKey.top()->name)
parserError("Unexpected closure.");
} else {
- _keyValues.push(Common::StringMap());
- _activeKey.push(_token);
+ ParserNode *node = new ParserNode;
+ node->name = _token;
+ _activeKey.push(node);
}
_state = kParserNeedPropertyName;
@@ -173,8 +172,7 @@ bool ThemeParser::parse() {
case kParserNeedPropertyName:
if (activeClosure) {
activeClosure = false;
- _activeKey.pop();
- _keyValues.pop();
+ delete _activeKey.pop();
if (_text[_pos++] != '>')
parserError("Invalid syntax in key closure.");
@@ -215,6 +213,9 @@ bool ThemeParser::parse() {
_state = kParserNeedPropertyName;
break;
+
+ default:
+ break;
}
}
diff --git a/gui/ThemeParser.h b/gui/ThemeParser.h
index 334677fd39..956a6d1df2 100644
--- a/gui/ThemeParser.h
+++ b/gui/ThemeParser.h
@@ -34,6 +34,272 @@
#include "common/hash-str.h"
#include "common/stack.h"
+/**
+ *********************************************
+ ** Theme Description File format overview. **
+ *********************************************
+ This document is a work in progress.
+ A more complete version will be posted on the wiki soon.
+
+In the new version of the Graphical User Interface for ScummVM, almost
+all properties regarding looks, design and positioning of the UI
+elements are defined in a set of external files.
+
+The chosen syntax for theme description is a basic subset of XML.
+The process of theme description is divided in two main parts: Drawing
+specifications for the vector renderer and theme design/layout
+information for the actual theme engine.
+
+These two core sections of a theme's description may be placed in a
+single file or split for convenience across several files.
+
+_DRAWING SPECIFICATIONS_
+
+The process of rendering a widget on the screen is discretized into
+several phases called "drawing steps". A set of such steps, which
+generate a basic widget shape on screen is called a Draw Data set. The
+GUI Engine loads all the different data sets for a given
+widget and takes care of rendering it into the screen based on its
+current state.
+
+For example, the basic Button widget may be composed of several sets
+of data: Drawing data for the button's idle state, drawing data for
+when the button is hovered and drawing data for when the button is
+pressed.
+
+The functionality of each set of Drawing Data is hard-coded into the
+Graphical User Interface; the most up to date version of all the
+drawing sets may be found extensively commented in the
+"gui/InterfaceManager.h" file, in the DrawData enumeration inside the
+InterfaceManager class.
+
+In order to successfully parse and load a custom theme definition, the
+whole list of Draw Data sets must be specified.
+
+_THEME LAYOUT SPECIFICATIONS_
+
+#######
+
+_SYNTAX OVERVIEW AND PARAMETERS_
+
+As stated before, all the theme description is done through a XML-like
+syntax. The files are parsed left-to-right, ignoring extra whitespaces
+and newlines. Parser data is interpreted during the parsing. As a
+general guideline, theme files are composed of keys which may or not
+contain specific values for the key and which may parent several
+subkeys; independently of this, all keys must be properly closed with
+the '/' operator.
+
+ <parent_key value1 = "sample">
+
+ <child_key1>
+ <self_closed_child value2 = 124 />
+
+ <external_closed_child value3 = 245>
+
+ </external_closed_child>
+ </child_key1>
+
+ <child_key2 with_value = "sample">
+ <subchild/>
+ </child_key2>
+
+ </parent_key>
+
+Note how keys which contain no children may be closed by themselves
+or with an external closure.
+
+- Comments
+The parser supports the same comment syntax as the C++ programming
+language. Comment blocks may be specified by surrounding them with the
+'/ *' and '* /' operators, while whole lines may be commented out by
+preceding them with the // operator.
+
+Block comments are parsed in a non-hungry manner, i.e. the first
+comment closure is understood to close the whole commenting block, so
+syntax like
+
+ / * hey look this comment finishes here * / or maybe here?? * /
+
+is invalid.
+
+- Section keys.
+The section key is the root level of a theme description file. Each
+file may contain one or more of these keys, which specifies the nature
+of all their children, namely if the children keys specify drawing or
+layout information. Its syntax is as follows:
+
+ <layout_info platform = "NDS" resolution = "320x240">
+ // ...
+ </layout_info>
+
+ <render_info platform = "NDS" resolution = "320x240">
+ // ...
+ </render_info>
+
+The "layout_info" key specifies that all children keys contain
+information regarding the layout of the theme, while the "render_info"
+key specifies that all children keys contain information regarding the
+looks of the theme.
+
+Both keys support the two optional parameters "platform" and
+"resolution", in order to make a certain layout apply to a single
+resolution or to a single platform. To make a key apply for more than
+one specific platform or resolution at the same time, you may separate
+their names with commas.
+
+ <render_info platform = "nds, palmos, pocketpc">
+
+
+- Render Info keys:
+The children of a "render_info" key are expected to be one of these
+kind:
+
+ -- DrawData key:
+ DrawData keys are the core of the rendering engine. They specifiy
+ via their own children the looks of all the UI elements. Here's
+ their syntax:
+
+ <drawdata id = "button_idle" cache = true platform = "NDS"
+ resolution = "320x240">
+
+ </drawdata>
+
+ All drawdata keys must contain an "id" value, specifying which set
+ of drawing data they implement. Here's a list of all possible ids.
+
+ #########
+
+ Remember that all these ids must me implemented in order for the
+ parsing to be considered succesful.
+
+ DrawData keys may also contain an optional boolean value "cache",
+ which states if the set of DrawingSteps may be cached into the
+ memory so it can be blit into the Overlay each frame or if the set
+ of Drawing Steps should be performed individually each frame. If
+ omitted, the "cache" value defaults to false.
+
+ Also, just like the <render_info> key, DrawData keys may also
+ contain optional "platform" and "resolution" values, making such
+ draw steps specific for a single or several platforms or
+ resolutions. In order to specify several platforms or resolutions,
+ they must be separated by commas inside the key's value.
+
+ <drawdata id = "background_default" cache = true platform = "nds, palmos">
+ </drawdata>
+
+ When making a set of Drawing Data for a widget specific to a
+ single platform or resolution, remember that the set must be also
+ implemented later generically for other platforms, or the
+ rendering of the theme will fail in such platforms.
+
+ Lastly, each DrawData key must contain at least a children
+ "drawstep" subkey, with the necessary info for the
+ VectorRenderer.
+
+ - The DrawStep key
+ The DrawStep key is probably the most complex definition of
+ a ThemeDescription file. It contains enough information to
+ allow the Vector Renderer to draw a basic or complex shape
+ into the screen.
+
+ DrawStep keys are supposed to have no children, so they must
+ be either self-closed or closed externally.
+
+ Their basic syntax is as follows:
+
+ <drawstep func = "roundedsq">
+ </drawstep>
+
+ The only required value is the function "func" which states
+ the drawing function that will be used, and it must be
+ accompanied by a set of parameters specific to each drawing
+ step. Here's a list of such parameters:
+
+Common parameters for all functions:
+
+fill = "none|foreground|background|gradient"
+ Specifies the fill mode for the drawn shape.
+ Possible values:
+
+ "none": Disables filling so only the stroke is shown.
+ "foreground" (default): Fills the whole shape with the active foreground
+ color.
+ "background": Fills the whole shape with the active background
+ color.
+ "gradient": Fills the whole shape with the active gradient.
+
+gradient_start = "R, G, B" | "color name"
+gradient_end = "R, G, B" | "color name"
+fg_color = "R, G, B" | "color name"
+bg_color = "R, G, B" | "color name"
+ Sets the active gradient, foreground or backgroud colors. Colors
+ may be specified with their three components (red, green, blue)
+ ranging each from 0 to 255, or via a color name which has
+ previously been defined in the palette section.
+
+ These colours have no default values.
+
+stroke = width (integer)
+ Sets the active stroke width; strokes may be disabled by setting
+ this value to 0. All shapes are automatically stroked with the
+ given width and the active foreground color. Defaults to 1.
+
+shadow = offset (integer)
+ Sets the shadow offset. In the rendering engines that support it,
+ drawn shapes will have a soft shadow offseted the given amount on
+ their bottom-right corner. Defaults to 0 (disabled).
+
+factor = amount (integer)
+ The factor value specifies the displacement of the active
+ gradient, i.e. its zoom level. It is only taken into account if
+ the active fill mode is set to gradient. Defaults to 1.
+
+Standard primitive drawing functions:
+
+func = "circle"
+ Draws a primitive circle. Requires the additional parameter
+ "radius", with an integer defining the radius of the circle or
+ the "auto" value.
+
+func = "square"
+ Draws a primitive square/rectangle. Requires no additional parameters.
+
+func = "roundedsq"
+ Draws a square/rectangle with rounded corners. Requires the
+ additional parameter "radius" defining the radius of the rounded
+ corners.
+
+func = "bevelsq"
+ Draws a square/rectangle with beveled borders. This square
+ ignores the active fill mode, as it is never filled. Requires the
+ additional parameter "bevel" with the amount of bevel.
+
+func = "line"
+ Draws a line. If the "size" parameter is specified, the line will
+ be drawn ranging from the bottom-left corner to the top-right
+ corner of the defined box. Optionally, you may define the ending
+ point of the line with the "end" parameter.
+
+func = "triangle"
+ Draws a triangle. Triangles are always isosceles, meaning they
+ are drawn inside the square defined by the position and size
+ values, with the given width as the base of the triangle and the
+ given height as the height of the triangle.
+
+ The optional parameter
+
+ orientation = "top|left|right|bottom"
+
+ may be specified to define the way in which the triangle is
+ pointing. Defaults to top.
+
+func = "fill"
+ This call ignores position and size parameters, as it completely
+ fills the active drawing surface taken into account the active
+ fill mode and colors.
+*/
+
namespace GUI {
class ThemeParser {
@@ -44,7 +310,7 @@ class ThemeParser {
public:
ThemeParser() {
_callbacks["drawdata"] = &ThemeParser::parserCallback_DRAWDATA;
- _callbacks["draw"] = &ThemeParser::parserCallback_DRAW;
+ _callbacks["drawstep"] = &ThemeParser::parserCallback_DRAWSTEP;
}
~ThemeParser() {}
@@ -64,7 +330,7 @@ public:
void debug_testEval();
protected:
- void parserCallback_DRAW();
+ void parserCallback_DRAWSTEP();
void parserCallback_DRAWDATA();
bool parseKeyValue(Common::String keyName);
@@ -87,9 +353,19 @@ protected:
while (_text[_pos++]) {
if (_text[_pos - 2] == '*' && _text[_pos - 1] == '/')
break;
+ if (_text[_pos] == 0)
+ parserError("Comment has no closure.");
}
return true;
}
+
+ if (_text[_pos] == '/' && _text[_pos + 1] == '/') {
+ _pos += 2;
+ while (_text[_pos] && _text[_pos] != '\n')
+ _pos++;
+ return true;
+ }
+
return false;
}
@@ -113,9 +389,12 @@ protected:
Common::String _error;
Common::String _token;
- Common::FixedStack<Common::String, kParserMaxDepth> _activeKey;
- Common::FixedStack<Common::StringMap, kParserMaxDepth> _keyValues;
+ struct ParserNode {
+ Common::String name;
+ Common::StringMap values;
+ };
+ Common::FixedStack<ParserNode*, kParserMaxDepth> _activeKey;
Common::HashMap<Common::String, ParserCallback, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _callbacks;
};