1 /* ScummVM - Graphic Adventure Engine
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 #include "gui/ThemeEngine.h"
27 #include "gui/ThemeEval.h"
28 #include "gui/ThemeParser.h"
29 #include "gui/GuiManager.h"
31 #include "graphics/VectorRenderer.h"
40 static const TextDataInfo kTextDataDefaults
[] = {
41 {kTextDataDefault
, "text_default"},
42 {kTextDataHover
, "text_hover"},
43 {kTextDataDisabled
, "text_disabled"},
44 {kTextDataInverted
, "text_inverted"},
45 {kTextDataButton
, "text_button"},
46 {kTextDataButtonHover
, "text_button_hover"},
47 {kTextDataNormalFont
, "text_normal"}
51 static TextData
parseTextDataId(const Common::String
&name
) {
52 for (int i
= 0; i
< kTextDataMAX
; ++i
)
53 if (name
.compareToIgnoreCase(kTextDataDefaults
[i
].name
) == 0)
54 return kTextDataDefaults
[i
].id
;
59 static Graphics::TextAlign
parseTextHAlign(const Common::String
&val
) {
61 return Graphics::kTextAlignLeft
;
62 else if (val
== "right")
63 return Graphics::kTextAlignRight
;
64 else if (val
== "center")
65 return Graphics::kTextAlignCenter
;
67 return Graphics::kTextAlignInvalid
;
70 static GUI::ThemeEngine::TextAlignVertical
parseTextVAlign(const Common::String
&val
) {
72 return GUI::ThemeEngine::kTextAlignVTop
;
73 else if (val
== "center")
74 return GUI::ThemeEngine::kTextAlignVCenter
;
75 else if (val
== "bottom")
76 return GUI::ThemeEngine::kTextAlignVBottom
;
78 return GUI::ThemeEngine::kTextAlignVInvalid
;
82 ThemeParser::ThemeParser(ThemeEngine
*parent
) : XMLParser() {
83 _defaultStepGlobal
= defaultDrawStep();
84 _defaultStepLocal
= 0;
88 ThemeParser::~ThemeParser() {
89 delete _defaultStepGlobal
;
90 delete _defaultStepLocal
;
93 void ThemeParser::cleanup() {
94 delete _defaultStepGlobal
;
95 delete _defaultStepLocal
;
97 _defaultStepGlobal
= defaultDrawStep();
98 _defaultStepLocal
= 0;
102 Graphics::DrawStep
*ThemeParser::defaultDrawStep() {
103 Graphics::DrawStep
*step
= new Graphics::DrawStep
;
105 memset(step
, 0, sizeof(Graphics::DrawStep
));
107 step
->xAlign
= Graphics::DrawStep::kVectorAlignManual
;
108 step
->yAlign
= Graphics::DrawStep::kVectorAlignManual
;
110 step
->autoWidth
= true;
111 step
->autoHeight
= true;
112 step
->fillMode
= Graphics::VectorRenderer::kFillDisabled
;
113 step
->scale
= (1 << 16);
119 Graphics::DrawStep
*ThemeParser::newDrawStep() {
120 assert(_defaultStepGlobal
);
121 Graphics::DrawStep
*step
= 0 ; //new DrawStep;
123 if (_defaultStepLocal
) {
124 step
= new Graphics::DrawStep(*_defaultStepLocal
);
126 step
= new Graphics::DrawStep(*_defaultStepGlobal
);
132 bool ThemeParser::parserCallback_defaults(ParserNode
*node
) {
133 ParserNode
*parentNode
= getParentNode(node
);
134 Graphics::DrawStep
*step
= 0;
136 if (parentNode
->name
== "render_info") {
137 step
= _defaultStepGlobal
;
138 } else if (parentNode
->name
== "drawdata") {
139 if (_defaultStepLocal
== 0)
140 _defaultStepLocal
= new Graphics::DrawStep(*_defaultStepGlobal
);
142 step
= _defaultStepLocal
;
144 return parserError("<default> key out of scope. Must be inside <drawdata> or <render_info> keys.");
147 return parseDrawStep(node
, step
, false);
150 bool ThemeParser::parserCallback_font(ParserNode
*node
) {
151 int red
, green
, blue
;
153 if (resolutionCheck(node
->values
["resolution"]) == false) {
158 if (_palette
.contains(node
->values
["color"]))
159 getPaletteColor(node
->values
["color"], red
, green
, blue
);
160 else if (!parseIntegerKey(node
->values
["color"].c_str(), 3, &red
, &green
, &blue
))
161 return parserError("Error parsing color value for font definition.");
163 TextData textDataId
= parseTextDataId(node
->values
["id"]);
164 if (!_theme
->addFont(textDataId
, node
->values
["file"], red
, green
, blue
))
165 return parserError("Error loading Font in theme engine.");
170 bool ThemeParser::parserCallback_fonts(ParserNode
*node
) {
174 bool ThemeParser::parserCallback_cursor(ParserNode
*node
) {
175 if (resolutionCheck(node
->values
["resolution"]) == false) {
180 int spotx
, spoty
, scale
;
182 if (!parseIntegerKey(node
->values
["hotspot"].c_str(), 2, &spotx
, &spoty
))
183 return parserError("Error parsing cursor Hot Spot coordinates.");
185 if (!parseIntegerKey(node
->values
["scale"].c_str(), 1, &scale
))
186 return parserError("Error parsing cursor scale.");
188 if (!_theme
->createCursor(node
->values
["file"], spotx
, spoty
, scale
))
189 return parserError("Error creating Bitmap Cursor.");
194 bool ThemeParser::parserCallback_bitmap(ParserNode
*node
) {
195 if (resolutionCheck(node
->values
["resolution"]) == false) {
200 if (!_theme
->addBitmap(node
->values
["filename"]))
201 return parserError("Error loading Bitmap file '%s'", node
->values
["filename"].c_str());
206 bool ThemeParser::parserCallback_text(ParserNode
*node
) {
207 Graphics::TextAlign alignH
;
208 GUI::ThemeEngine::TextAlignVertical alignV
;
210 if ((alignH
= parseTextHAlign(node
->values
["horizontal_align"])) == Graphics::kTextAlignInvalid
)
211 return parserError("Invalid value for text alignment.");
213 if ((alignV
= parseTextVAlign(node
->values
["vertical_align"])) == GUI::ThemeEngine::kTextAlignVInvalid
)
214 return parserError("Invalid value for text alignment.");
216 Common::String id
= getParentNode(node
)->values
["id"];
217 TextData textDataId
= parseTextDataId(node
->values
["font"]);
219 if (!_theme
->addTextData(id
, textDataId
, alignH
, alignV
))
220 return parserError("Error adding Text Data for '%s'.", id
.c_str());
225 bool ThemeParser::parserCallback_render_info(ParserNode
*node
) {
226 if (resolutionCheck(node
->values
["resolution"]) == false)
232 bool ThemeParser::parserCallback_layout_info(ParserNode
*node
) {
233 if (resolutionCheck(node
->values
["resolution"]) == false)
239 bool ThemeParser::parserCallback_palette(ParserNode
*node
) {
243 bool ThemeParser::parserCallback_color(ParserNode
*node
) {
244 Common::String name
= node
->values
["name"];
246 if (_palette
.contains(name
))
247 return parserError("Color '%s' has already been defined.", name
.c_str());
249 int red
, green
, blue
;
251 if (parseIntegerKey(node
->values
["rgb"].c_str(), 3, &red
, &green
, &blue
) == false ||
252 red
< 0 || red
> 255 || green
< 0 || green
> 255 || blue
< 0 || blue
> 255)
253 return parserError("Error parsing RGB values for palette color '%s'", name
.c_str());\
255 _palette
[name
].r
= red
;
256 _palette
[name
].g
= green
;
257 _palette
[name
].b
= blue
;
263 static Graphics::DrawingFunctionCallback
getDrawingFunctionCallback(const Common::String
&name
) {
265 if (name
== "circle")
266 return &Graphics::VectorRenderer::drawCallback_CIRCLE
;
267 if (name
== "square")
268 return &Graphics::VectorRenderer::drawCallback_SQUARE
;
269 if (name
== "roundedsq")
270 return &Graphics::VectorRenderer::drawCallback_ROUNDSQ
;
271 if (name
== "bevelsq")
272 return &Graphics::VectorRenderer::drawCallback_BEVELSQ
;
274 return &Graphics::VectorRenderer::drawCallback_LINE
;
275 if (name
== "triangle")
276 return &Graphics::VectorRenderer::drawCallback_TRIANGLE
;
278 return &Graphics::VectorRenderer::drawCallback_FILLSURFACE
;
280 return &Graphics::VectorRenderer::drawCallback_TAB
;
282 return &Graphics::VectorRenderer::drawCallback_VOID
;
283 if (name
== "bitmap")
284 return &Graphics::VectorRenderer::drawCallback_BITMAP
;
286 return &Graphics::VectorRenderer::drawCallback_CROSS
;
292 bool ThemeParser::parserCallback_drawstep(ParserNode
*node
) {
293 Graphics::DrawStep
*drawstep
= newDrawStep();
295 Common::String functionName
= node
->values
["func"];
297 drawstep
->drawingCall
= getDrawingFunctionCallback(functionName
);
299 if (drawstep
->drawingCall
== 0)
300 return parserError("%s is not a valid drawing function name", functionName
.c_str());
302 if (!parseDrawStep(node
, drawstep
, true))
305 _theme
->addDrawStep(getParentNode(node
)->values
["id"], *drawstep
);
311 bool ThemeParser::parserCallback_drawdata(ParserNode
*node
) {
314 if (resolutionCheck(node
->values
["resolution"]) == false) {
319 if (node
->values
.contains("cache")) {
320 if (node
->values
["cache"] == "true")
322 else if (node
->values
["cache"] == "false")
324 else return parserError("'Parsed' value must be either true or false.");
327 if (_theme
->addDrawData(node
->values
["id"], cached
) == false)
328 return parserError("Error adding Draw Data set: Invalid DrawData name.");
330 if (_defaultStepLocal
) {
331 delete _defaultStepLocal
;
332 _defaultStepLocal
= 0;
338 bool ThemeParser::parseDrawStep(ParserNode
*stepNode
, Graphics::DrawStep
*drawstep
, bool functionSpecific
) {
339 int red
, green
, blue
, x
;
343 * @def __PARSER_ASSIGN_INT(struct_name, key_name, force)
344 * Helper macro to sanitize and assign an integer value from a key
347 * @param struct_name Name of the field of a DrawStep struct that must be
349 * @param key_name Name as STRING of the key identifier as it appears in the
350 * theme description format.
351 * @param force Sets if the key is optional or necessary.
353 #define __PARSER_ASSIGN_INT(struct_name, key_name, force) \
354 if (stepNode->values.contains(key_name)) { \
355 if (!parseIntegerKey(stepNode->values[key_name].c_str(), 1, &x)) \
356 return parserError("Error parsing key value for '%s'.", key_name); \
358 drawstep->struct_name = x; \
359 } else if (force) { \
360 return parserError("Missing necessary key '%s'.", key_name); \
364 * Helper macro to sanitize and assign a RGB value from a key to the draw
365 * step. RGB values have the following syntax: "R, G, B".
367 * @param struct_name Name of the field of a DrawStep struct that must be
369 * @param key_name Name as STRING of the key identifier as it appears in the
370 * theme description format.
372 #define __PARSER_ASSIGN_RGB(struct_name, key_name) \
373 if (stepNode->values.contains(key_name)) { \
374 val = stepNode->values[key_name]; \
375 if (_palette.contains(val)) { \
376 red = _palette[val].r; \
377 green = _palette[val].g; \
378 blue = _palette[val].b; \
379 } else if (parseIntegerKey(val.c_str(), 3, &red, &green, &blue) == false || \
380 red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255) \
381 return parserError("Error parsing color struct '%s'", val.c_str());\
383 drawstep->struct_name.r = red; \
384 drawstep->struct_name.g = green; \
385 drawstep->struct_name.b = blue; \
386 drawstep->struct_name.set = true; \
389 __PARSER_ASSIGN_INT(stroke
, "stroke", false);
390 __PARSER_ASSIGN_INT(bevel
, "bevel", false);
391 __PARSER_ASSIGN_INT(shadow
, "shadow", false);
392 __PARSER_ASSIGN_INT(factor
, "gradient_factor", false);
394 __PARSER_ASSIGN_RGB(fgColor
, "fg_color");
395 __PARSER_ASSIGN_RGB(bgColor
, "bg_color");
396 __PARSER_ASSIGN_RGB(gradColor1
, "gradient_start");
397 __PARSER_ASSIGN_RGB(gradColor2
, "gradient_end");
398 __PARSER_ASSIGN_RGB(bevelColor
, "bevel_color");
400 if (functionSpecific
) {
401 assert(stepNode
->values
.contains("func"));
402 Common::String functionName
= stepNode
->values
["func"];
404 if (functionName
== "bitmap") {
405 if (!stepNode
->values
.contains("file"))
406 return parserError("Need to specify a filename for Bitmap blitting.");
408 drawstep
->blitSrc
= _theme
->getBitmap(stepNode
->values
["file"]);
410 if (!drawstep
->blitSrc
)
411 return parserError("The given filename hasn't been loaded into the GUI.");
414 if (functionName
== "roundedsq" || functionName
== "circle" || functionName
== "tab") {
415 if (stepNode
->values
.contains("radius") && stepNode
->values
["radius"] == "auto") {
416 drawstep
->radius
= 0xFF;
418 __PARSER_ASSIGN_INT(radius
, "radius", true);
422 if (functionName
== "triangle") {
423 drawstep
->extraData
= Graphics::VectorRenderer::kTriangleUp
;
425 if (stepNode
->values
.contains("orientation")) {
426 val
= stepNode
->values
["orientation"];
429 drawstep
->extraData
= Graphics::VectorRenderer::kTriangleUp
;
430 else if (val
== "bottom")
431 drawstep
->extraData
= Graphics::VectorRenderer::kTriangleDown
;
432 else if (val
== "left")
433 drawstep
->extraData
= Graphics::VectorRenderer::kTriangleLeft
;
434 else if (val
== "right")
435 drawstep
->extraData
= Graphics::VectorRenderer::kTriangleRight
;
437 return parserError("'%s' is not a valid value for triangle orientation.", val
.c_str());
441 if (stepNode
->values
.contains("size")) {
442 warning("The <size> keyword has been deprecated. Use <width> and <height> instead");
445 if (stepNode
->values
.contains("width") && stepNode
->values
["width"] != "auto") {
446 drawstep
->autoWidth
= false;
448 val
= stepNode
->values
["width"];
449 if (parseIntegerKey(val
.c_str(), 1, &x
))
451 else if (val
== "height")
453 else return parserError("Invalid value for vector width.");
455 if (stepNode
->values
.contains("xpos")) {
456 val
= stepNode
->values
["xpos"];
458 if (parseIntegerKey(val
.c_str(), 1, &x
))
460 else if (val
== "center")
461 drawstep
->xAlign
= Graphics::DrawStep::kVectorAlignCenter
;
462 else if (val
== "left")
463 drawstep
->xAlign
= Graphics::DrawStep::kVectorAlignLeft
;
464 else if (val
== "right")
465 drawstep
->xAlign
= Graphics::DrawStep::kVectorAlignRight
;
467 return parserError("Invalid value for X Position");
469 return parserError("When width is not set to 'auto', a <xpos> tag must be included.");
473 if (stepNode
->values
.contains("height") && stepNode
->values
["height"] != "auto") {
474 drawstep
->autoHeight
= false;
476 val
= stepNode
->values
["height"];
477 if (parseIntegerKey(val
.c_str(), 1, &x
))
479 else if (val
== "width")
481 else return parserError("Invalid value for vector height.");
483 if (stepNode
->values
.contains("ypos")) {
484 val
= stepNode
->values
["ypos"];
486 if (parseIntegerKey(val
.c_str(), 1, &x
))
488 else if (val
== "center")
489 drawstep
->yAlign
= Graphics::DrawStep::kVectorAlignCenter
;
490 else if (val
== "top")
491 drawstep
->yAlign
= Graphics::DrawStep::kVectorAlignTop
;
492 else if (val
== "bottom")
493 drawstep
->yAlign
= Graphics::DrawStep::kVectorAlignBottom
;
495 return parserError("Invalid value for Y Position");
497 return parserError("When height is not set to 'auto', a <ypos> tag must be included.");
501 if (drawstep
->h
== -1 && drawstep
->w
== -1)
502 return parserError("Cross-reference in Vector Size: Height is set to width and width is set to height.");
505 if (stepNode
->values
.contains("fill")) {
506 val
= stepNode
->values
["fill"];
508 drawstep
->fillMode
= Graphics::VectorRenderer::kFillDisabled
;
509 else if (val
== "foreground")
510 drawstep
->fillMode
= Graphics::VectorRenderer::kFillForeground
;
511 else if (val
== "background")
512 drawstep
->fillMode
= Graphics::VectorRenderer::kFillBackground
;
513 else if (val
== "gradient")
514 drawstep
->fillMode
= Graphics::VectorRenderer::kFillGradient
;
516 return parserError("'%s' is not a valid fill mode for a shape.", stepNode
->values
["fill"].c_str());
519 #undef __PARSER_ASSIGN_INT
520 #undef __PARSER_ASSIGN_RGB
525 bool ThemeParser::parserCallback_def(ParserNode
*node
) {
526 if (resolutionCheck(node
->values
["resolution"]) == false) {
531 Common::String var
= "Globals." + node
->values
["var"];
534 if (_theme
->getEvaluator()->hasVar(node
->values
["value"]) == true)
535 value
= _theme
->getEvaluator()->getVar(node
->values
["value"]);
537 else if (!parseIntegerKey(node
->values
["value"].c_str(), 1, &value
))
538 return parserError("Invalid definition for '%s'.", var
.c_str());
540 _theme
->getEvaluator()->setVar(var
, value
);
544 bool ThemeParser::parserCallback_widget(ParserNode
*node
) {
547 if (getParentNode(node
)->name
== "globals") {
549 if (resolutionCheck(node
->values
["resolution"]) == false) {
554 var
= "Globals." + node
->values
["name"] + ".";
555 if (!parseCommonLayoutProps(node
, var
))
556 return parserError("Error parsing Layout properties of '%s'.", var
.c_str());
559 // FIXME: Shouldn't we distinguish the name/id and the label of a widget?
560 var
= node
->values
["name"];
565 if (node
->values
.contains("enabled")) {
566 if (node
->values
["enabled"] == "false")
568 else if (node
->values
["enabled"] != "true")
569 return parserError("Invalid value for Widget enabling (expecting true/false)");
572 if (node
->values
.contains("width")) {
573 if (_theme
->getEvaluator()->hasVar(node
->values
["width"]) == true)
574 width
= _theme
->getEvaluator()->getVar(node
->values
["width"]);
576 else if (!parseIntegerKey(node
->values
["width"].c_str(), 1, &width
))
577 return parserError("Corrupted width value in key for %s", var
.c_str());
580 if (node
->values
.contains("height")) {
581 if (_theme
->getEvaluator()->hasVar(node
->values
["height"]) == true)
582 height
= _theme
->getEvaluator()->getVar(node
->values
["height"]);
584 else if (!parseIntegerKey(node
->values
["height"].c_str(), 1, &height
))
585 return parserError("Corrupted height value in key for %s", var
.c_str());
588 Graphics::TextAlign alignH
= Graphics::kTextAlignLeft
;
590 if (node
->values
.contains("textalign")) {
591 if((alignH
= parseTextHAlign(node
->values
["textalign"])) == Graphics::kTextAlignInvalid
)
592 return parserError("Invalid value for text alignment.");
595 _theme
->getEvaluator()->addWidget(var
, width
, height
, node
->values
["type"], enabled
, alignH
);
601 bool ThemeParser::parserCallback_dialog(ParserNode
*node
) {
602 Common::String var
= "Dialog." + node
->values
["name"];
606 if (resolutionCheck(node
->values
["resolution"]) == false) {
611 if (node
->values
.contains("enabled")) {
612 if (node
->values
["enabled"] == "false")
614 else if (node
->values
["enabled"] != "true")
615 return parserError("Invalid value for Dialog enabling (expecting true/false)");
618 if (node
->values
.contains("inset")) {
619 if (!parseIntegerKey(node
->values
["inset"].c_str(), 1, &inset
))
623 _theme
->getEvaluator()->addDialog(var
, node
->values
["overlays"], enabled
, inset
);
625 if (node
->values
.contains("shading")) {
627 if (node
->values
["shading"] == "dim")
629 else if (node
->values
["shading"] == "luminance")
631 else return parserError("Invalid value for Dialog background shading.");
633 _theme
->getEvaluator()->setVar(var
+ ".Shading", shading
);
639 bool ThemeParser::parserCallback_import(ParserNode
*node
) {
641 if (!_theme
->getEvaluator()->addImportedLayout(node
->values
["layout"]))
642 return parserError("Error importing external layout");
646 bool ThemeParser::parserCallback_layout(ParserNode
*node
) {
649 if (node
->values
.contains("spacing")) {
650 if (!parseIntegerKey(node
->values
["spacing"].c_str(), 1, &spacing
))
654 if (node
->values
["type"] == "vertical")
655 _theme
->getEvaluator()->addLayout(GUI::ThemeLayout::kLayoutVertical
, spacing
, node
->values
["center"] == "true");
656 else if (node
->values
["type"] == "horizontal")
657 _theme
->getEvaluator()->addLayout(GUI::ThemeLayout::kLayoutHorizontal
, spacing
, node
->values
["center"] == "true");
659 return parserError("Invalid layout type. Only 'horizontal' and 'vertical' layouts allowed.");
662 if (node
->values
.contains("padding")) {
663 int paddingL
, paddingR
, paddingT
, paddingB
;
665 if (!parseIntegerKey(node
->values
["padding"].c_str(), 4, &paddingL
, &paddingR
, &paddingT
, &paddingB
))
668 _theme
->getEvaluator()->addPadding(paddingL
, paddingR
, paddingT
, paddingB
);
674 bool ThemeParser::parserCallback_space(ParserNode
*node
) {
677 if (node
->values
.contains("size")) {
678 if (_theme
->getEvaluator()->hasVar(node
->values
["size"]))
679 size
= _theme
->getEvaluator()->getVar(node
->values
["size"]);
681 else if (!parseIntegerKey(node
->values
["size"].c_str(), 1, &size
))
682 return parserError("Invalid value for Spacing size.");
685 _theme
->getEvaluator()->addSpace(size
);
689 bool ThemeParser::closedKeyCallback(ParserNode
*node
) {
690 if (node
->name
== "layout")
691 _theme
->getEvaluator()->closeLayout();
692 else if (node
->name
== "dialog")
693 _theme
->getEvaluator()->closeDialog();
698 bool ThemeParser::parseCommonLayoutProps(ParserNode
*node
, const Common::String
&var
) {
699 if (node
->values
.contains("size")) {
702 if (!parseIntegerKey(node
->values
["size"].c_str(), 2, &width
, &height
)) {
703 Common::StringTokenizer
tokenizer(node
->values
["size"], " ,");
704 Common::String wtoken
, htoken
;
707 wtoken
= tokenizer
.nextToken();
709 if (_theme
->getEvaluator()->hasVar(wtoken
)) {
710 width
= _theme
->getEvaluator()->getVar(wtoken
);
712 width
= strtol(wtoken
.c_str(), &parseEnd
, 10);
714 if (*parseEnd
!= 0 && !(*parseEnd
== '%' && *(parseEnd
+ 1) == 0))
717 if (wtoken
.lastChar() == '%')
718 width
= g_system
->getOverlayWidth() * width
/ 100;
721 htoken
= tokenizer
.nextToken();
723 if (_theme
->getEvaluator()->hasVar(htoken
)) {
724 height
= _theme
->getEvaluator()->getVar(htoken
);
726 height
= strtol(htoken
.c_str(), &parseEnd
, 10);
728 if (*parseEnd
!= 0 && !(*parseEnd
== '%' && *(parseEnd
+ 1) == 0))
731 if (htoken
.lastChar() == '%')
732 height
= g_system
->getOverlayHeight() * height
/ 100;
735 if (!tokenizer
.empty())
740 _theme
->getEvaluator()->setVar(var
+ "Width", width
);
741 _theme
->getEvaluator()->setVar(var
+ "Height", height
);
744 if (node
->values
.contains("pos")) {
747 if (!parseIntegerKey(node
->values
["pos"].c_str(), 2, &x
, &y
)) {
748 Common::StringTokenizer
tokenizer(node
->values
["pos"], " ,");
749 Common::String xpos
, ypos
;
752 xpos
= tokenizer
.nextToken();
754 if (xpos
== "center") {
755 if (!_theme
->getEvaluator()->hasVar(var
+ "Width"))
758 x
= (g_system
->getOverlayWidth() / 2) - (_theme
->getEvaluator()->getVar(var
+ "Width") / 2);
760 } else if (_theme
->getEvaluator()->hasVar(xpos
)) {
761 x
= _theme
->getEvaluator()->getVar(xpos
);
763 x
= strtol(xpos
.c_str(), &parseEnd
, 10);
765 if (*parseEnd
!= 0 && !(*parseEnd
== 'r' && *(parseEnd
+ 1) == 0))
768 if (xpos
.lastChar() == 'r')
769 x
= g_system
->getOverlayWidth() - x
;
772 ypos
= tokenizer
.nextToken();
774 if (ypos
== "center") {
775 if (!_theme
->getEvaluator()->hasVar(var
+ "Height"))
778 y
= (g_system
->getOverlayHeight() / 2) - (_theme
->getEvaluator()->getVar(var
+ "Height") / 2);
780 } else if (_theme
->getEvaluator()->hasVar(ypos
)) {
781 y
= _theme
->getEvaluator()->getVar(ypos
);
783 y
= strtol(ypos
.c_str(), &parseEnd
, 10);
785 if (*parseEnd
!= 0 && !(*parseEnd
== 'b' && *(parseEnd
+ 1) == 0))
788 if (ypos
.lastChar() == 'b')
789 y
= g_system
->getOverlayHeight() - y
;
792 if (!tokenizer
.empty())
796 _theme
->getEvaluator()->setVar(var
+ "X", x
);
797 _theme
->getEvaluator()->setVar(var
+ "Y", y
);
800 if (node
->values
.contains("padding")) {
801 int paddingL
, paddingR
, paddingT
, paddingB
;
803 if (!parseIntegerKey(node
->values
["padding"].c_str(), 4, &paddingL
, &paddingR
, &paddingT
, &paddingB
))
806 _theme
->getEvaluator()->setVar(var
+ "Padding.Left", paddingL
);
807 _theme
->getEvaluator()->setVar(var
+ "Padding.Right", paddingR
);
808 _theme
->getEvaluator()->setVar(var
+ "Padding.Top", paddingT
);
809 _theme
->getEvaluator()->setVar(var
+ "Padding.Bottom", paddingB
);
813 if (node
->values
.contains("textalign")) {
814 Graphics::TextAlign alignH
= Graphics::kTextAlignLeft
;
816 if((alignH
= parseTextHAlign(node
->values
["textalign"])) == Graphics::kTextAlignInvalid
)
817 return parserError("Invalid value for text alignment.");
819 _theme
->getEvaluator()->setVar(var
+ "Align", alignH
);
824 bool ThemeParser::resolutionCheck(const Common::String
&resolution
) {
825 if (resolution
.empty())
828 Common::StringTokenizer
globTokenizer(resolution
, ", ");
829 Common::String cur
, w
, h
;
830 bool definedRes
= false;
832 while (!globTokenizer
.empty()) {
834 cur
= globTokenizer
.nextToken();
843 Common::StringTokenizer
resTokenizer(cur
, "x");
844 w
= resTokenizer
.nextToken();
845 h
= resTokenizer
.nextToken();
847 if ((w
== "X" || atoi(w
.c_str()) == g_system
->getOverlayWidth()) &&
848 (h
== "Y" || atoi(h
.c_str()) == g_system
->getOverlayHeight()))
855 } // End of namespace GUI