ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

ThemeParser.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "gui/ThemeEngine.h"
00024 #include "gui/ThemeEval.h"
00025 #include "gui/ThemeParser.h"
00026 
00027 #include "graphics/VectorRenderer.h"
00028 
00029 #include "common/system.h"
00030 #include "common/tokenizer.h"
00031 
00032 namespace GUI {
00033 
00034 struct TextDataInfo {
00035     TextData id;
00036     const char *name;
00037 };
00038 
00039 static const TextDataInfo kTextDataDefaults[] = {
00040     { kTextDataDefault,         "text_default" },
00041     { kTextDataButton,          "text_button" },
00042     { kTextDataNormalFont,      "text_normal" },
00043     { kTextDataTooltip,         "tooltip_normal" },
00044     { kTextDataConsole,         "console" }
00045 };
00046 
00047 
00048 static TextData parseTextDataId(const Common::String &name) {
00049     for (int i = 0; i < kTextDataMAX; ++i)
00050         if (name.compareToIgnoreCase(kTextDataDefaults[i].name) == 0)
00051             return kTextDataDefaults[i].id;
00052 
00053     return kTextDataNone;
00054 }
00055 
00056 struct TextColorDataInfo {
00057     TextColor id;
00058     const char *name;
00059 };
00060 
00061 static const TextColorDataInfo kTextColorDefaults[] = {
00062     { kTextColorNormal,                 "color_normal" },
00063     { kTextColorNormalInverted,         "color_normal_inverted" },
00064     { kTextColorNormalHover,            "color_normal_hover" },
00065     { kTextColorNormalDisabled,         "color_normal_disabled" },
00066     { kTextColorAlternative,            "color_alternative" },
00067     { kTextColorAlternativeInverted,    "color_alternative_inverted" },
00068     { kTextColorAlternativeHover,       "color_alternative_hover" },
00069     { kTextColorAlternativeDisabled,    "color_alternative_disabled" },
00070     { kTextColorButton,                 "color_button" },
00071     { kTextColorButtonHover,            "color_button_hover" },
00072     { kTextColorButtonDisabled,         "color_button_disabled" }
00073 };
00074 
00075 static TextColor parseTextColorId(const Common::String &name) {
00076     for (int i = 0; i < kTextColorMAX; ++i)
00077         if (name.compareToIgnoreCase(kTextColorDefaults[i].name) == 0)
00078             return kTextColorDefaults[i].id;
00079 
00080     return kTextColorMAX;
00081 }
00082 
00083 static Graphics::TextAlign parseTextHAlign(const Common::String &val) {
00084     if (val == "left")
00085         return Graphics::kTextAlignLeft;
00086     else if (val == "right")
00087         return Graphics::kTextAlignRight;
00088     else if (val == "center")
00089         return Graphics::kTextAlignCenter;
00090     else
00091         return Graphics::kTextAlignInvalid;
00092 }
00093 
00094 static GUI::ThemeEngine::TextAlignVertical parseTextVAlign(const Common::String &val) {
00095     if (val == "top")
00096         return GUI::ThemeEngine::kTextAlignVTop;
00097     else if (val == "center")
00098         return GUI::ThemeEngine::kTextAlignVCenter;
00099     else if (val == "bottom")
00100         return GUI::ThemeEngine::kTextAlignVBottom;
00101     else
00102         return GUI::ThemeEngine::kTextAlignVInvalid;
00103 }
00104 
00105 
00106 ThemeParser::ThemeParser(ThemeEngine *parent) : XMLParser() {
00107     _defaultStepGlobal = defaultDrawStep();
00108     _defaultStepLocal = 0;
00109     _theme = parent;
00110 }
00111 
00112 ThemeParser::~ThemeParser() {
00113     delete _defaultStepGlobal;
00114     delete _defaultStepLocal;
00115 }
00116 
00117 void ThemeParser::cleanup() {
00118     delete _defaultStepGlobal;
00119     delete _defaultStepLocal;
00120 
00121     _defaultStepGlobal = defaultDrawStep();
00122     _defaultStepLocal = 0;
00123     _palette.clear();
00124 }
00125 
00126 Graphics::DrawStep *ThemeParser::defaultDrawStep() {
00127     Graphics::DrawStep *step = new Graphics::DrawStep;
00128 
00129     memset(step, 0, sizeof(Graphics::DrawStep));
00130 
00131     step->xAlign = Graphics::DrawStep::kVectorAlignManual;
00132     step->yAlign = Graphics::DrawStep::kVectorAlignManual;
00133     step->factor = 1;
00134     step->autoWidth = true;
00135     step->autoHeight = true;
00136     step->fillMode = Graphics::VectorRenderer::kFillDisabled;
00137     step->scale = (1 << 16);
00138     step->radius = 0xFF;
00139 
00140     return step;
00141 }
00142 
00143 Graphics::DrawStep *ThemeParser::newDrawStep() {
00144     assert(_defaultStepGlobal);
00145     Graphics::DrawStep *step = 0; //new DrawStep;
00146 
00147     if (_defaultStepLocal) {
00148         step = new Graphics::DrawStep(*_defaultStepLocal);
00149     } else {
00150         step = new Graphics::DrawStep(*_defaultStepGlobal);
00151     }
00152 
00153     return step;
00154 }
00155 
00156 bool ThemeParser::parserCallback_defaults(ParserNode *node) {
00157     ParserNode *parentNode = getParentNode(node);
00158     Graphics::DrawStep *step = 0;
00159 
00160     if (parentNode->name == "render_info") {
00161         step = _defaultStepGlobal;
00162     } else if (parentNode->name == "drawdata") {
00163         if (_defaultStepLocal == 0)
00164             _defaultStepLocal = new Graphics::DrawStep(*_defaultStepGlobal);
00165 
00166         step = _defaultStepLocal;
00167     } else {
00168         return parserError("<default> key out of scope. Must be inside <drawdata> or <render_info> keys.");
00169     }
00170 
00171     return parseDrawStep(node, step, false);
00172 }
00173 
00174 bool ThemeParser::parserCallback_font(ParserNode *node) {
00175     if (resolutionCheck(node->values["resolution"]) == false) {
00176         node->ignore = true;
00177         return true;
00178     }
00179 
00180     // Default to a point size of 12.
00181     int pointsize = 12;
00182     if (node->values.contains("point_size")) {
00183         if (sscanf(node->values["point_size"].c_str(), "%d", &pointsize) != 1 || pointsize <= 0)
00184             return parserError(Common::String::format("Font \"%s\" has invalid point size \"%s\"", node->values["id"].c_str(), node->values["point_size"].c_str()));
00185     }
00186 
00187     TextData textDataId = parseTextDataId(node->values["id"]);
00188     if (!_theme->addFont(textDataId, node->values["file"], node->values["scalable_file"], pointsize))
00189         return parserError("Error loading Font in theme engine.");
00190 
00191     return true;
00192 }
00193 
00194 bool ThemeParser::parserCallback_text_color(ParserNode *node) {
00195     int red, green, blue;
00196 
00197     TextColor colorId = parseTextColorId(node->values["id"]);
00198     if (colorId == kTextColorMAX)
00199         return parserError("Error text color is not defined.");
00200 
00201     if (_palette.contains(node->values["color"]))
00202         getPaletteColor(node->values["color"], red, green, blue);
00203     else if (!parseIntegerKey(node->values["color"], 3, &red, &green, &blue))
00204         return parserError("Error parsing color value for text color definition.");
00205 
00206     if (!_theme->addTextColor(colorId, red, green, blue))
00207         return parserError("Error while adding text color information.");
00208 
00209     return true;
00210 }
00211 
00212 bool ThemeParser::parserCallback_fonts(ParserNode *node) {
00213     return true;
00214 }
00215 
00216 bool ThemeParser::parserCallback_cursor(ParserNode *node) {
00217     if (resolutionCheck(node->values["resolution"]) == false) {
00218         node->ignore = true;
00219         return true;
00220     }
00221 
00222     int spotx, spoty;
00223 
00224     if (!parseIntegerKey(node->values["hotspot"], 2, &spotx, &spoty))
00225         return parserError("Error parsing cursor Hot Spot coordinates.");
00226 
00227     if (!_theme->createCursor(node->values["file"], spotx, spoty))
00228         return parserError("Error creating Bitmap Cursor.");
00229 
00230     return true;
00231 }
00232 
00233 bool ThemeParser::parserCallback_bitmap(ParserNode *node) {
00234     if (resolutionCheck(node->values["resolution"]) == false) {
00235         node->ignore = true;
00236         return true;
00237     }
00238 
00239     if (!_theme->addBitmap(node->values["filename"]))
00240         return parserError("Error loading Bitmap file '" + node->values["filename"] + "'");
00241 
00242     return true;
00243 }
00244 
00245 bool ThemeParser::parserCallback_alphabitmap(ParserNode *node) {
00246     if (resolutionCheck(node->values["resolution"]) == false) {
00247         node->ignore = true;
00248         return true;
00249     }
00250 
00251     if (!_theme->addAlphaBitmap(node->values["filename"]))
00252         return parserError("Error loading Bitmap file '" + node->values["filename"] + "'");
00253 
00254     return true;
00255 }
00256 
00257 bool ThemeParser::parserCallback_text(ParserNode *node) {
00258     Graphics::TextAlign alignH;
00259     GUI::ThemeEngine::TextAlignVertical alignV;
00260 
00261     if ((alignH = parseTextHAlign(node->values["horizontal_align"])) == Graphics::kTextAlignInvalid)
00262         return parserError("Invalid value for text alignment.");
00263 
00264     if ((alignV = parseTextVAlign(node->values["vertical_align"])) == GUI::ThemeEngine::kTextAlignVInvalid)
00265         return parserError("Invalid value for text alignment.");
00266 
00267     Common::String id = getParentNode(node)->values["id"];
00268     TextData textDataId = parseTextDataId(node->values["font"]);
00269     TextColor textColorId = parseTextColorId(node->values["text_color"]);
00270 
00271     if (!_theme->addTextData(id, textDataId, textColorId, alignH, alignV))
00272         return parserError("Error adding Text Data for '" + id + "'.");
00273 
00274     return true;
00275 }
00276 
00277 bool ThemeParser::parserCallback_render_info(ParserNode *node) {
00278     if (resolutionCheck(node->values["resolution"]) == false)
00279         node->ignore = true;
00280 
00281     return true;
00282 }
00283 
00284 bool ThemeParser::parserCallback_layout_info(ParserNode *node) {
00285     if (resolutionCheck(node->values["resolution"]) == false)
00286         node->ignore = true;
00287 
00288     return true;
00289 }
00290 
00291 bool ThemeParser::parserCallback_palette(ParserNode *node) {
00292     return true;
00293 }
00294 
00295 bool ThemeParser::parserCallback_color(ParserNode *node) {
00296     Common::String name = node->values["name"];
00297 
00298     if (_palette.contains(name))
00299         return parserError("Color '" + name + "' has already been defined.");
00300 
00301     int red, green, blue;
00302 
00303     if (parseIntegerKey(node->values["rgb"], 3, &red, &green, &blue) == false ||
00304         red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255)
00305         return parserError("Error parsing RGB values for palette color '" + name + "'");
00306 
00307     _palette[name].r = red;
00308     _palette[name].g = green;
00309     _palette[name].b = blue;
00310 
00311     return true;
00312 }
00313 
00314 
00315 static Graphics::DrawingFunctionCallback getDrawingFunctionCallback(const Common::String &name) {
00316 
00317     if (name == "circle")
00318         return &Graphics::VectorRenderer::drawCallback_CIRCLE;
00319     if (name == "square")
00320         return &Graphics::VectorRenderer::drawCallback_SQUARE;
00321     if (name == "roundedsq")
00322         return &Graphics::VectorRenderer::drawCallback_ROUNDSQ;
00323     if (name == "bevelsq")
00324         return &Graphics::VectorRenderer::drawCallback_BEVELSQ;
00325     if (name == "line")
00326         return &Graphics::VectorRenderer::drawCallback_LINE;
00327     if (name == "triangle")
00328         return &Graphics::VectorRenderer::drawCallback_TRIANGLE;
00329     if (name == "fill")
00330         return &Graphics::VectorRenderer::drawCallback_FILLSURFACE;
00331     if (name == "tab")
00332         return &Graphics::VectorRenderer::drawCallback_TAB;
00333     if (name == "void")
00334         return &Graphics::VectorRenderer::drawCallback_VOID;
00335     if (name == "bitmap")
00336         return &Graphics::VectorRenderer::drawCallback_BITMAP;
00337     if (name == "cross")
00338         return &Graphics::VectorRenderer::drawCallback_CROSS;
00339     if (name == "alphabitmap")
00340         return &Graphics::VectorRenderer::drawCallback_ALPHABITMAP;
00341 
00342     return 0;
00343 }
00344 
00345 
00346 bool ThemeParser::parserCallback_drawstep(ParserNode *node) {
00347     Graphics::DrawStep *drawstep = newDrawStep();
00348 
00349     Common::String functionName = node->values["func"];
00350 
00351     drawstep->drawingCall = getDrawingFunctionCallback(functionName);
00352 
00353     if (drawstep->drawingCall == 0) {
00354         delete drawstep;
00355         return parserError(functionName + " is not a valid drawing function name");
00356     }
00357 
00358     if (!parseDrawStep(node, drawstep, true)) {
00359         delete drawstep;
00360         return false;
00361     }
00362 
00363     _theme->addDrawStep(getParentNode(node)->values["id"], *drawstep);
00364     delete drawstep;
00365 
00366     return true;
00367 }
00368 
00369 bool ThemeParser::parserCallback_drawdata(ParserNode *node) {
00370     bool cached = false;
00371 
00372     if (resolutionCheck(node->values["resolution"]) == false) {
00373         node->ignore = true;
00374         return true;
00375     }
00376 
00377     if (node->values.contains("cache")) {
00378         if (!Common::parseBool(node->values["cache"], cached))
00379             return parserError("'Parsed' value must be either true or false.");
00380     }
00381 
00382     if (_theme->addDrawData(node->values["id"], cached) == false)
00383         return parserError("Error adding Draw Data set: Invalid DrawData name.");
00384 
00385     delete _defaultStepLocal;
00386     _defaultStepLocal = 0;
00387 
00388     return true;
00389 }
00390 
00391 bool ThemeParser::parseDrawStep(ParserNode *stepNode, Graphics::DrawStep *drawstep, bool functionSpecific) {
00392     int red, green, blue, x;
00393     Common::String val;
00394 
00405 #define PARSER_ASSIGN_INT(struct_name, key_name, force) \
00406     if (stepNode->values.contains(key_name)) { \
00407         if (!parseIntegerKey(stepNode->values[key_name], 1, &x)) \
00408             return parserError("Error parsing key value for '" + Common::String(key_name) + "'."); \
00409         \
00410         drawstep->struct_name = x; \
00411     } else if (force) { \
00412         return parserError("Missing necessary key '" + Common::String(key_name) + "'."); \
00413     }
00414 
00424 #define PARSER_ASSIGN_RGB(struct_name, key_name) \
00425     if (stepNode->values.contains(key_name)) { \
00426         val = stepNode->values[key_name]; \
00427         if (_palette.contains(val)) { \
00428             red = _palette[val].r; \
00429             green = _palette[val].g; \
00430             blue = _palette[val].b; \
00431         } else if (parseIntegerKey(val, 3, &red, &green, &blue) == false || \
00432             red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255) \
00433             return parserError("Error parsing color struct '" + val + "'");\
00434         \
00435         drawstep->struct_name.r = red; \
00436         drawstep->struct_name.g = green; \
00437         drawstep->struct_name.b = blue; \
00438         drawstep->struct_name.set = true; \
00439     }
00440 
00441     PARSER_ASSIGN_INT(stroke, "stroke", false);
00442     PARSER_ASSIGN_INT(bevel, "bevel", false);
00443     PARSER_ASSIGN_INT(shadow, "shadow", false);
00444     PARSER_ASSIGN_INT(factor, "gradient_factor", false);
00445 
00446     PARSER_ASSIGN_RGB(fgColor, "fg_color");
00447     PARSER_ASSIGN_RGB(bgColor, "bg_color");
00448     PARSER_ASSIGN_RGB(gradColor1, "gradient_start");
00449     PARSER_ASSIGN_RGB(gradColor2, "gradient_end");
00450     PARSER_ASSIGN_RGB(bevelColor, "bevel_color");
00451 
00452     if (functionSpecific) {
00453         assert(stepNode->values.contains("func"));
00454         Common::String functionName = stepNode->values["func"];
00455 
00456         if (functionName == "bitmap") {
00457             if (!stepNode->values.contains("file"))
00458                 return parserError("Need to specify a filename for Bitmap blitting.");
00459 
00460             drawstep->blitSrc = _theme->getBitmap(stepNode->values["file"]);
00461 
00462             if (!drawstep->blitSrc)
00463                 return parserError("The given filename hasn't been loaded into the GUI.");
00464         }
00465 
00466         if (functionName == "alphabitmap") {
00467             if (!stepNode->values.contains("file"))
00468                 return parserError("Need to specify a filename for AlphaBitmap blitting.");
00469 
00470             drawstep->blitAlphaSrc = _theme->getAlphaBitmap(stepNode->values["file"]);
00471 
00472             if (!drawstep->blitAlphaSrc)
00473                 return parserError("The given filename hasn't been loaded into the GUI.");
00474 
00475             if (stepNode->values.contains("autoscale")) {
00476                 if (stepNode->values["autoscale"] == "true" || stepNode->values["autoscale"] == "stretch") {
00477                     drawstep->autoscale = ThemeEngine::kAutoScaleStretch;
00478                 } else if (stepNode->values["autoscale"] == "fit") {
00479                     drawstep->autoscale = ThemeEngine::kAutoScaleFit;
00480                 } else if (stepNode->values["autoscale"] == "9patch") {
00481                     drawstep->autoscale = ThemeEngine::kAutoScaleNinePatch;
00482                 } else {
00483                     drawstep->autoscale = ThemeEngine::kAutoScaleNone;
00484                 }
00485             }
00486 
00487             if (stepNode->values.contains("xpos")) {
00488                 val = stepNode->values["xpos"];
00489 
00490                 if (parseIntegerKey(val, 1, &x))
00491                     drawstep->x = x;
00492                 else if (val == "center")
00493                     drawstep->xAlign = Graphics::DrawStep::kVectorAlignCenter;
00494                 else if (val == "left")
00495                     drawstep->xAlign = Graphics::DrawStep::kVectorAlignLeft;
00496                 else if (val == "right")
00497                     drawstep->xAlign = Graphics::DrawStep::kVectorAlignRight;
00498                 else
00499                     return parserError("Invalid value for X Position");
00500             }
00501 
00502             if (stepNode->values.contains("ypos")) {
00503                 val = stepNode->values["ypos"];
00504 
00505                 if (parseIntegerKey(val, 1, &x))
00506                     drawstep->y = x;
00507                 else if (val == "center")
00508                     drawstep->yAlign = Graphics::DrawStep::kVectorAlignCenter;
00509                 else if (val == "top")
00510                     drawstep->yAlign = Graphics::DrawStep::kVectorAlignTop;
00511                 else if (val == "bottom")
00512                     drawstep->yAlign = Graphics::DrawStep::kVectorAlignBottom;
00513                 else
00514                     return parserError("Invalid value for Y Position");
00515             }
00516         }
00517 
00518         if (functionName == "roundedsq" || functionName == "circle" || functionName == "tab") {
00519             if (stepNode->values.contains("radius") && stepNode->values["radius"] == "auto") {
00520                 drawstep->radius = 0xFF;
00521             } else {
00522                 PARSER_ASSIGN_INT(radius, "radius", true);
00523             }
00524         }
00525 
00526         if (functionName == "triangle") {
00527             drawstep->extraData = Graphics::VectorRenderer::kTriangleUp;
00528 
00529             if (stepNode->values.contains("orientation")) {
00530                 val = stepNode->values["orientation"];
00531 
00532                 if (val == "top")
00533                     drawstep->extraData = Graphics::VectorRenderer::kTriangleUp;
00534                 else if (val == "bottom")
00535                     drawstep->extraData = Graphics::VectorRenderer::kTriangleDown;
00536                 else if (val == "left")
00537                     drawstep->extraData = Graphics::VectorRenderer::kTriangleLeft;
00538                 else if (val == "right")
00539                     drawstep->extraData = Graphics::VectorRenderer::kTriangleRight;
00540                 else
00541                     return parserError("'" + val + "' is not a valid value for triangle orientation.");
00542             }
00543         }
00544 
00545         if (stepNode->values.contains("size")) {
00546             warning("The <size> keyword has been deprecated. Use <width> and <height> instead");
00547         }
00548 
00549         if (stepNode->values.contains("width") && stepNode->values["width"] != "auto") {
00550             drawstep->autoWidth = false;
00551 
00552             val = stepNode->values["width"];
00553             if (parseIntegerKey(val, 1, &x))
00554                 drawstep->w = x;
00555             else if (val == "height")
00556                 drawstep->w = -1;
00557             else return parserError("Invalid value for vector width.");
00558 
00559             if (stepNode->values.contains("xpos")) {
00560                 val = stepNode->values["xpos"];
00561 
00562                 if (parseIntegerKey(val, 1, &x))
00563                     drawstep->x = x;
00564                 else if (val == "center")
00565                     drawstep->xAlign = Graphics::DrawStep::kVectorAlignCenter;
00566                 else if (val == "left")
00567                     drawstep->xAlign = Graphics::DrawStep::kVectorAlignLeft;
00568                 else if (val == "right")
00569                     drawstep->xAlign = Graphics::DrawStep::kVectorAlignRight;
00570                 else
00571                     return parserError("Invalid value for X Position");
00572             } else {
00573                 return parserError("When width is not set to 'auto', a <xpos> tag must be included.");
00574             }
00575         }
00576 
00577         if (stepNode->values.contains("height") && stepNode->values["height"] != "auto") {
00578             drawstep->autoHeight = false;
00579 
00580             val = stepNode->values["height"];
00581             if (parseIntegerKey(val, 1, &x))
00582                 drawstep->h = x;
00583             else if (val == "width")
00584                 drawstep->h = -1;
00585             else return parserError("Invalid value for vector height.");
00586 
00587             if (stepNode->values.contains("ypos")) {
00588                 val = stepNode->values["ypos"];
00589 
00590                 if (parseIntegerKey(val, 1, &x))
00591                     drawstep->y = x;
00592                 else if (val == "center")
00593                     drawstep->yAlign = Graphics::DrawStep::kVectorAlignCenter;
00594                 else if (val == "top")
00595                     drawstep->yAlign = Graphics::DrawStep::kVectorAlignTop;
00596                 else if (val == "bottom")
00597                     drawstep->yAlign = Graphics::DrawStep::kVectorAlignBottom;
00598                 else
00599                     return parserError("Invalid value for Y Position");
00600             } else {
00601                 return parserError("When height is not set to 'auto', a <ypos> tag must be included.");
00602             }
00603         }
00604 
00605         if (drawstep->h == -1 && drawstep->w == -1)
00606             return parserError("Cross-reference in Vector Size: Height is set to width and width is set to height.");
00607     }
00608 
00609     if (stepNode->values.contains("fill")) {
00610         val = stepNode->values["fill"];
00611         if (val == "none")
00612             drawstep->fillMode = Graphics::VectorRenderer::kFillDisabled;
00613         else if (val == "foreground")
00614             drawstep->fillMode = Graphics::VectorRenderer::kFillForeground;
00615         else if (val == "background")
00616             drawstep->fillMode = Graphics::VectorRenderer::kFillBackground;
00617         else if (val == "gradient")
00618             drawstep->fillMode = Graphics::VectorRenderer::kFillGradient;
00619         else
00620             return parserError("'" + stepNode->values["fill"] + "' is not a valid fill mode for a shape.");
00621     }
00622 
00623     if (stepNode->values.contains("padding")) {
00624         val = stepNode->values["padding"];
00625         int pr, pt, pl, pb;
00626         if (parseIntegerKey(val, 4, &pl, &pt, &pr, &pb)) {
00627             drawstep->padding.left = pl;
00628             drawstep->padding.top = pt;
00629             drawstep->padding.right = pr;
00630             drawstep->padding.bottom = pb;
00631         }
00632     }
00633 
00634     if (stepNode->values.contains("clip")) {
00635         val = stepNode->values["clip"];
00636         int cl, ct, cr, cb;
00637         if (parseIntegerKey(val, 4, &cl, &ct, &cr, &cb)) {
00638             drawstep->clip.left = cl;
00639             drawstep->clip.top = ct;
00640             drawstep->clip.right = cr;
00641             drawstep->clip.bottom = cb;
00642         }
00643     }
00644 
00645 #undef PARSER_ASSIGN_INT
00646 #undef PARSER_ASSIGN_RGB
00647 
00648     return true;
00649 }
00650 
00651 bool ThemeParser::parserCallback_def(ParserNode *node) {
00652     if (resolutionCheck(node->values["resolution"]) == false) {
00653         node->ignore = true;
00654         return true;
00655     }
00656 
00657     Common::String var = "Globals." + node->values["var"];
00658     int value;
00659 
00660     if (_theme->getEvaluator()->hasVar(node->values["value"]) == true)
00661         value = _theme->getEvaluator()->getVar(node->values["value"]);
00662 
00663     else if (!parseIntegerKey(node->values["value"], 1, &value))
00664         return parserError("Invalid definition for '" + var + "'.");
00665 
00666     _theme->getEvaluator()->setVar(var, value);
00667     return true;
00668 }
00669 
00670 bool ThemeParser::parserCallback_widget(ParserNode *node) {
00671     Common::String var;
00672 
00673     if (getParentNode(node)->name == "globals") {
00674 
00675         if (resolutionCheck(node->values["resolution"]) == false) {
00676             node->ignore = true;
00677             return true;
00678         }
00679 
00680         var = "Globals." + node->values["name"] + ".";
00681         if (!parseCommonLayoutProps(node, var))
00682             return parserError("Error parsing Layout properties of '" + var + "'.");
00683 
00684     } else {
00685         // FIXME: Shouldn't we distinguish the name/id and the label of a widget?
00686         var = node->values["name"];
00687         int width = -1;
00688         int height = -1;
00689         bool enabled = true;
00690 
00691         if (node->values.contains("enabled")) {
00692             if (!Common::parseBool(node->values["enabled"], enabled))
00693                 return parserError("Invalid value for Widget enabling (expecting true/false)");
00694         }
00695 
00696         if (node->values.contains("width")) {
00697             if (_theme->getEvaluator()->hasVar(node->values["width"]) == true)
00698                 width = _theme->getEvaluator()->getVar(node->values["width"]);
00699 
00700             else if (!parseIntegerKey(node->values["width"], 1, &width))
00701                 return parserError("Corrupted width value in key for " + var);
00702         }
00703 
00704         if (node->values.contains("height")) {
00705             if (_theme->getEvaluator()->hasVar(node->values["height"]) == true)
00706                 height = _theme->getEvaluator()->getVar(node->values["height"]);
00707 
00708             else if (!parseIntegerKey(node->values["height"], 1, &height))
00709                 return parserError("Corrupted height value in key for " + var);
00710         }
00711 
00712         Graphics::TextAlign alignH = Graphics::kTextAlignLeft;
00713 
00714         if (node->values.contains("textalign")) {
00715             if ((alignH = parseTextHAlign(node->values["textalign"])) == Graphics::kTextAlignInvalid)
00716                 return parserError("Invalid value for text alignment.");
00717         }
00718 
00719         _theme->getEvaluator()->addWidget(var, width, height, node->values["type"], enabled, alignH);
00720     }
00721 
00722     return true;
00723 }
00724 
00725 bool ThemeParser::parserCallback_dialog(ParserNode *node) {
00726     Common::String var = "Dialog." + node->values["name"];
00727     bool enabled = true;
00728     int inset = 0;
00729 
00730     if (resolutionCheck(node->values["resolution"]) == false) {
00731         node->ignore = true;
00732         return true;
00733     }
00734 
00735     if (node->values.contains("enabled")) {
00736         if (!Common::parseBool(node->values["enabled"], enabled))
00737             return parserError("Invalid value for Dialog enabling (expecting true/false)");
00738     }
00739 
00740     if (node->values.contains("inset")) {
00741         if (!parseIntegerKey(node->values["inset"], 1, &inset))
00742             return false;
00743     }
00744 
00745     _theme->getEvaluator()->addDialog(var, node->values["overlays"], enabled, inset);
00746 
00747     if (node->values.contains("shading")) {
00748         int shading = 0;
00749         if (node->values["shading"] == "dim")
00750             shading = 1;
00751         else if (node->values["shading"] == "luminance")
00752             shading = 2;
00753         else return parserError("Invalid value for Dialog background shading.");
00754 
00755         _theme->getEvaluator()->setVar(var + ".Shading", shading);
00756     }
00757 
00758     return true;
00759 }
00760 
00761 bool ThemeParser::parserCallback_import(ParserNode *node) {
00762 
00763     if (!_theme->getEvaluator()->addImportedLayout(node->values["layout"]))
00764         return parserError("Error importing external layout");
00765     return true;
00766 }
00767 
00768 bool ThemeParser::parserCallback_layout(ParserNode *node) {
00769     int spacing = -1;
00770     bool center = false;
00771 
00772     if (node->values.contains("spacing")) {
00773         if (!parseIntegerKey(node->values["spacing"], 1, &spacing))
00774             return false;
00775     }
00776 
00777     (void)Common::parseBool(node->values["center"], center);
00778 
00779     if (node->values["type"] == "vertical")
00780         _theme->getEvaluator()->addLayout(GUI::ThemeLayout::kLayoutVertical, spacing, center);
00781     else if (node->values["type"] == "horizontal")
00782         _theme->getEvaluator()->addLayout(GUI::ThemeLayout::kLayoutHorizontal, spacing, center);
00783     else
00784         return parserError("Invalid layout type. Only 'horizontal' and 'vertical' layouts allowed.");
00785 
00786 
00787     if (node->values.contains("padding")) {
00788         int paddingL, paddingR, paddingT, paddingB;
00789 
00790         if (!parseIntegerKey(node->values["padding"], 4, &paddingL, &paddingR, &paddingT, &paddingB))
00791             return false;
00792 
00793         _theme->getEvaluator()->addPadding(paddingL, paddingR, paddingT, paddingB);
00794     }
00795 
00796     return true;
00797 }
00798 
00799 bool ThemeParser::parserCallback_space(ParserNode *node) {
00800     int size = -1;
00801 
00802     if (node->values.contains("size")) {
00803         if (_theme->getEvaluator()->hasVar(node->values["size"]))
00804             size = _theme->getEvaluator()->getVar(node->values["size"]);
00805 
00806         else if (!parseIntegerKey(node->values["size"], 1, &size))
00807             return parserError("Invalid value for Spacing size.");
00808     }
00809 
00810     _theme->getEvaluator()->addSpace(size);
00811     return true;
00812 }
00813 
00814 bool ThemeParser::closedKeyCallback(ParserNode *node) {
00815     if (node->name == "layout")
00816         _theme->getEvaluator()->closeLayout();
00817     else if (node->name == "dialog")
00818         _theme->getEvaluator()->closeDialog();
00819 
00820     return true;
00821 }
00822 
00823 bool ThemeParser::parseCommonLayoutProps(ParserNode *node, const Common::String &var) {
00824     if (node->values.contains("size")) {
00825         int width, height;
00826 
00827         if (!parseIntegerKey(node->values["size"], 2, &width, &height)) {
00828             Common::StringTokenizer tokenizer(node->values["size"], " ,");
00829             Common::String wtoken, htoken;
00830             char *parseEnd;
00831 
00832             wtoken = tokenizer.nextToken();
00833 
00834             if (_theme->getEvaluator()->hasVar(wtoken)) {
00835                 width = _theme->getEvaluator()->getVar(wtoken);
00836             } else {
00837                 width = strtol(wtoken.c_str(), &parseEnd, 10);
00838 
00839                 if (*parseEnd != 0 && !(*parseEnd == '%' && *(parseEnd + 1) == 0))
00840                     return false;
00841 
00842                 if (wtoken.lastChar() == '%')
00843                     width = g_system->getOverlayWidth() * width / 100;
00844             }
00845 
00846             htoken = tokenizer.nextToken();
00847 
00848             if (_theme->getEvaluator()->hasVar(htoken)) {
00849                 height = _theme->getEvaluator()->getVar(htoken);
00850             } else {
00851                 height = strtol(htoken.c_str(), &parseEnd, 10);
00852 
00853                 if (*parseEnd != 0 && !(*parseEnd == '%' && *(parseEnd + 1) == 0))
00854                     return false;
00855 
00856                 if (htoken.lastChar() == '%')
00857                     height = g_system->getOverlayHeight() * height / 100;
00858             }
00859 
00860             if (!tokenizer.empty())
00861                 return false;
00862         }
00863 
00864 
00865         _theme->getEvaluator()->setVar(var + "Width", width);
00866         _theme->getEvaluator()->setVar(var + "Height", height);
00867     }
00868 
00869     if (node->values.contains("pos")) {
00870         int x, y;
00871 
00872         if (!parseIntegerKey(node->values["pos"], 2, &x, &y)) {
00873             Common::StringTokenizer tokenizer(node->values["pos"], " ,");
00874             Common::String xpos, ypos;
00875             char *parseEnd;
00876 
00877             xpos = tokenizer.nextToken();
00878 
00879             if (xpos == "center") {
00880                 if (!_theme->getEvaluator()->hasVar(var + "Width"))
00881                     return false;
00882 
00883                 x = (g_system->getOverlayWidth() / 2) - (_theme->getEvaluator()->getVar(var + "Width") / 2);
00884 
00885             } else if (_theme->getEvaluator()->hasVar(xpos)) {
00886                 x = _theme->getEvaluator()->getVar(xpos);
00887             } else {
00888                 x = strtol(xpos.c_str(), &parseEnd, 10);
00889 
00890                 if (*parseEnd != 0 && !(*parseEnd == 'r' && *(parseEnd + 1) == 0))
00891                     return false;
00892 
00893                 if (xpos.lastChar() == 'r')
00894                     x = g_system->getOverlayWidth() - x;
00895             }
00896 
00897             ypos = tokenizer.nextToken();
00898 
00899             if (ypos == "center") {
00900                 if (!_theme->getEvaluator()->hasVar(var + "Height"))
00901                     return false;
00902 
00903                 y = (g_system->getOverlayHeight() / 2) - (_theme->getEvaluator()->getVar(var + "Height") / 2);
00904 
00905             } else if (_theme->getEvaluator()->hasVar(ypos)) {
00906                 y = _theme->getEvaluator()->getVar(ypos);
00907             } else {
00908                 y = strtol(ypos.c_str(), &parseEnd, 10);
00909 
00910                 if (*parseEnd != 0 && !(*parseEnd == 'b' && *(parseEnd + 1) == 0))
00911                     return false;
00912 
00913                 if (ypos.lastChar() == 'b')
00914                     y = g_system->getOverlayHeight() - y;
00915             }
00916 
00917             if (!tokenizer.empty())
00918                 return false;
00919         }
00920 
00921         _theme->getEvaluator()->setVar(var + "X", x);
00922         _theme->getEvaluator()->setVar(var + "Y", y);
00923     }
00924 
00925     if (node->values.contains("padding")) {
00926         int paddingL, paddingR, paddingT, paddingB;
00927 
00928         if (!parseIntegerKey(node->values["padding"], 4, &paddingL, &paddingR, &paddingT, &paddingB))
00929             return false;
00930 
00931         _theme->getEvaluator()->setVar(var + "Padding.Left", paddingL);
00932         _theme->getEvaluator()->setVar(var + "Padding.Right", paddingR);
00933         _theme->getEvaluator()->setVar(var + "Padding.Top", paddingT);
00934         _theme->getEvaluator()->setVar(var + "Padding.Bottom", paddingB);
00935     }
00936 
00937 
00938     if (node->values.contains("textalign")) {
00939         Graphics::TextAlign alignH = Graphics::kTextAlignLeft;
00940 
00941         if ((alignH = parseTextHAlign(node->values["textalign"])) == Graphics::kTextAlignInvalid)
00942             return parserError("Invalid value for text alignment.");
00943 
00944         _theme->getEvaluator()->setVar(var + "Align", alignH);
00945     }
00946     return true;
00947 }
00948 
00949 bool ThemeParser::resolutionCheck(const Common::String &resolution) {
00950     if (resolution.empty())
00951         return true;
00952 
00953     Common::StringTokenizer globTokenizer(resolution, ", ");
00954     Common::String cur;
00955 
00956     while (!globTokenizer.empty()) {
00957         cur = globTokenizer.nextToken();
00958 
00959         bool lt;
00960         int val;
00961 
00962         if (cur.size() < 5) {
00963             warning("Invalid theme 'resolution' token '%s'", resolution.c_str());
00964             return false;
00965         }
00966 
00967         if (cur[0] == 'x') {
00968             val = g_system->getOverlayWidth();
00969         } else if (cur[0] == 'y') {
00970             val = g_system->getOverlayHeight();
00971         } else {
00972             warning("Error parsing theme 'resolution' token '%s'", resolution.c_str());
00973             return false;
00974         }
00975 
00976         if (cur[1] == '<') {
00977             lt = true;
00978         } else if (cur[1] == '>') {
00979             lt = false;
00980         } else {
00981             warning("Error parsing theme 'resolution' token '%s'", resolution.c_str());
00982             return false;
00983         }
00984 
00985         int token = atoi(cur.c_str() + 2);
00986 
00987         // check inverse for unfulfilled requirements
00988         if (lt) {
00989             if (val >= token)
00990                 return false;
00991         } else {
00992             if (val <= token)
00993                 return false;
00994         }
00995     }
00996 
00997     return true;
00998 }
00999 
01000 } // End of namespace GUI


Generated on Sat Dec 14 2019 05:00:51 for ResidualVM by doxygen 1.7.1
curved edge   curved edge