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


Generated on Sat Feb 16 2019 05:01:09 for ResidualVM by doxygen 1.7.1
curved edge   curved edge