bool ThingTypeManager::loadOtml(std::string file) { try { file = g_resources.guessFilePath(file, "otml"); OTMLDocumentPtr doc = OTMLDocument::parse(file); for(const OTMLNodePtr& node : doc->children()) { ThingCategory category; if(node->tag() == "creatures") category = ThingCategoryCreature; else if(node->tag() == "items") category = ThingCategoryItem; else if(node->tag() == "effects") category = ThingCategoryEffect; else if(node->tag() == "missiles") category = ThingCategoryMissile; else { throw OTMLException(node, "not a valid thing category"); } for(const OTMLNodePtr& node2 : node->children()) { uint16 id = stdext::safe_cast<uint16>(node2->tag()); ThingTypePtr type = getThingType(id, category); if(!type) throw OTMLException(node2, "thing not found"); type->unserializeOtml(node2); } } return true; } catch(std::exception& e) { g_logger.error(stdext::format("Failed to read dat otml '%s': %s'", file, e.what())); return false; } }
void OTMLParser::parse() { if(!in.good()) throw OTMLException(doc, "cannot read from input stream"); while(!in.eof()) parseLine(getNextLine()); }
OTMLNodePtr OTMLNode::at(const std::string& childTag) { OTMLNodePtr res; for(const OTMLNodePtr& child : m_children) { if(child->tag() == childTag && !child->isNull()) { res = child; break; } } if(!res) throw OTMLException(asOTMLNode(), stdext::format("child node with tag '%s' not found", childTag)); return res; }
int OTMLParser::getLineDepth(const std::string& line, bool multilining) { // count number of spaces at the line beginning std::size_t spaces = 0; while(line[spaces] == ' ') spaces++; // pre calculate depth int depth = spaces / 2; if(!multilining || depth <= currentDepth) { // check the next character is a tab if(line[spaces] == '\t') throw OTMLException(doc, "indentation with tabs are not allowed", currentLine); // must indent every 2 spaces if(spaces % 2 != 0) throw OTMLException(doc, "must indent every 2 spaces", currentLine); } return depth; }
void UIManager::importStyleFromOTML(const OTMLNodePtr& styleNode) { std::string tag = styleNode->tag(); std::vector<std::string> split = stdext::split(tag, "<"); if(split.size() != 2) throw OTMLException(styleNode, "not a valid style declaration"); std::string name = split[0]; std::string base = split[1]; bool unique = false; stdext::trim(name); stdext::trim(base); if(name[0] == '#') { name = name.substr(1); unique = true; styleNode->setTag(name); styleNode->writeAt("__unique", true); } OTMLNodePtr oldStyle = m_styles[name]; // Warn about redefined styles /* if(!g_app.isRunning() && (oldStyle && !oldStyle->valueAt("__unique", false))) { auto it = m_styles.find(name); if(it != m_styles.end()) g_logger.warning(stdext::format("style '%s' is being redefined", name)); } */ if(!oldStyle || !oldStyle->valueAt("__unique", false) || unique) { OTMLNodePtr originalStyle = getStyle(base); if(!originalStyle) stdext::throw_exception(stdext::format("base style '%s', is not defined", base)); OTMLNodePtr style = originalStyle->clone(); style->merge(styleNode); style->setTag(name); m_styles[name] = style; } }
void OTMLParser::parseLine(std::string line) { int depth = getLineDepth(line); if(depth == -1) return; // remove line sides spaces boost::trim(line); // skip empty lines if(line.empty()) return; // skip comments if(boost::starts_with(line, "//")) return; // a depth above, change current parent to the previous added node if(depth == currentDepth+1) { currentParent = previousNode; // a depth below, change parent to previous parent } else if(depth < currentDepth) { for(int i=0;i<currentDepth-depth;++i) currentParent = currentParent->parent(); // if it isn't the current depth, it's a syntax error } else if(depth != currentDepth) throw OTMLException(doc, "invalid indentation depth, are you indenting correctly?", currentLine); // sets current depth currentDepth = depth; // alright, new depth is set, the line is not empty and it isn't a comment // then it must be a node, so we parse it parseNode(line); }
OTMLNodePtr OTMLNode::atIndex(int childIndex) { if(childIndex >= size() || childIndex < 0) throw OTMLException(asOTMLNode(), stdext::format("child node with index '%d' not found", childIndex)); return m_children[childIndex]; }
void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode) { // load styles used by all widgets for(const OTMLNodePtr& node : styleNode->children()) { if(node->tag() == "color") setColor(node->value<Color>()); else if(node->tag() == "x") setX(node->value<int>()); else if(node->tag() == "y") setY(node->value<int>()); else if(node->tag() == "pos") setPosition(node->value<Point>()); else if(node->tag() == "width") setWidth(node->value<int>()); else if(node->tag() == "height") setHeight(node->value<int>()); else if(node->tag() == "rect") setRect(node->value<Rect>()); else if(node->tag() == "background") setBackgroundColor(node->value<Color>()); else if(node->tag() == "background-color") setBackgroundColor(node->value<Color>()); else if(node->tag() == "background-offset-x") setBackgroundOffsetX(node->value<int>()); else if(node->tag() == "background-offset-y") setBackgroundOffsetY(node->value<int>()); else if(node->tag() == "background-offset") setBackgroundOffset(node->value<Point>()); else if(node->tag() == "background-width") setBackgroundWidth(node->value<int>()); else if(node->tag() == "background-height") setBackgroundHeight(node->value<int>()); else if(node->tag() == "background-size") setBackgroundSize(node->value<Size>()); else if(node->tag() == "background-rect") setBackgroundRect(node->value<Rect>()); else if(node->tag() == "icon") setIcon(stdext::resolve_path(node->value(), node->source())); else if(node->tag() == "icon-source") setIcon(stdext::resolve_path(node->value(), node->source())); else if(node->tag() == "icon-color") setIconColor(node->value<Color>()); else if(node->tag() == "icon-offset-x") setIconOffsetX(node->value<int>()); else if(node->tag() == "icon-offset-y") setIconOffsetY(node->value<int>()); else if(node->tag() == "icon-offset") setIconOffset(node->value<Point>()); else if(node->tag() == "icon-width") setIconWidth(node->value<int>()); else if(node->tag() == "icon-height") setIconHeight(node->value<int>()); else if(node->tag() == "icon-size") setIconSize(node->value<Size>()); else if(node->tag() == "icon-rect") setIconRect(node->value<Rect>()); else if(node->tag() == "opacity") setOpacity(node->value<float>()); else if(node->tag() == "enabled") setEnabled(node->value<bool>()); else if(node->tag() == "visible") setVisible(node->value<bool>()); else if(node->tag() == "checked") setChecked(node->value<bool>()); else if(node->tag() == "dragable") setChecked(node->value<bool>()); else if(node->tag() == "on") setOn(node->value<bool>()); else if(node->tag() == "focusable") setFocusable(node->value<bool>()); else if(node->tag() == "phantom") setPhantom(node->value<bool>()); else if(node->tag() == "size") setSize(node->value<Size>()); else if(node->tag() == "fixed-size") setFixedSize(node->value<bool>()); else if(node->tag() == "clipping") setClipping(node->value<bool>()); else if(node->tag() == "border") { auto split = stdext::split(node->value(), " "); if(split.size() == 2) { setBorderWidth(stdext::safe_cast<int>(split[0])); setBorderColor(stdext::safe_cast<Color>(split[1])); } else throw OTMLException(node, "border param must have its width followed by its color"); } else if(node->tag() == "border-width") setBorderWidth(node->value<int>()); else if(node->tag() == "border-width-top") setBorderWidthTop(node->value<int>()); else if(node->tag() == "border-width-right") setBorderWidthRight(node->value<int>()); else if(node->tag() == "border-width-bottom") setBorderWidthBottom(node->value<int>()); else if(node->tag() == "border-width-left") setBorderWidthLeft(node->value<int>()); else if(node->tag() == "border-color") setBorderColor(node->value<Color>()); else if(node->tag() == "border-color-top") setBorderColorTop(node->value<Color>()); else if(node->tag() == "border-color-right") setBorderColorRight(node->value<Color>()); else if(node->tag() == "border-color-bottom") setBorderColorBottom(node->value<Color>()); else if(node->tag() == "border-color-left") setBorderColorLeft(node->value<Color>()); else if(node->tag() == "margin-top") setMarginTop(node->value<int>()); else if(node->tag() == "margin-right") setMarginRight(node->value<int>()); else if(node->tag() == "margin-bottom") setMarginBottom(node->value<int>()); else if(node->tag() == "margin-left") setMarginLeft(node->value<int>()); else if(node->tag() == "margin") { std::string marginDesc = node->value(); std::vector<std::string> split; boost::split(split, marginDesc, boost::is_any_of(std::string(" "))); if(split.size() == 4) { setMarginTop(stdext::safe_cast<int>(split[0])); setMarginRight(stdext::safe_cast<int>(split[1])); setMarginBottom(stdext::safe_cast<int>(split[2])); setMarginLeft(stdext::safe_cast<int>(split[3])); } else if(split.size() == 3) { int marginTop = stdext::safe_cast<int>(split[0]); int marginHorizontal = stdext::safe_cast<int>(split[1]); int marginBottom = stdext::safe_cast<int>(split[2]); setMarginTop(marginTop); setMarginRight(marginHorizontal); setMarginBottom(marginBottom); setMarginLeft(marginHorizontal); } else if(split.size() == 2) { int marginVertical = stdext::safe_cast<int>(split[0]); int marginHorizontal = stdext::safe_cast<int>(split[1]); setMarginTop(marginVertical); setMarginRight(marginHorizontal); setMarginBottom(marginVertical); setMarginLeft(marginHorizontal); } else if(split.size() == 1) { int margin = stdext::safe_cast<int>(split[0]); setMarginTop(margin); setMarginRight(margin); setMarginBottom(margin); setMarginLeft(margin); } } else if(node->tag() == "padding-top") setPaddingTop(node->value<int>()); else if(node->tag() == "padding-right") setPaddingRight(node->value<int>()); else if(node->tag() == "padding-bottom") setPaddingBottom(node->value<int>()); else if(node->tag() == "padding-left") setPaddingLeft(node->value<int>()); else if(node->tag() == "padding") { std::string paddingDesc = node->value(); std::vector<std::string> split; boost::split(split, paddingDesc, boost::is_any_of(std::string(" "))); if(split.size() == 4) { setPaddingTop(stdext::safe_cast<int>(split[0])); setPaddingRight(stdext::safe_cast<int>(split[1])); setPaddingBottom(stdext::safe_cast<int>(split[2])); setPaddingLeft(stdext::safe_cast<int>(split[3])); } else if(split.size() == 3) { int paddingTop = stdext::safe_cast<int>(split[0]); int paddingHorizontal = stdext::safe_cast<int>(split[1]); int paddingBottom = stdext::safe_cast<int>(split[2]); setPaddingTop(paddingTop); setPaddingRight(paddingHorizontal); setPaddingBottom(paddingBottom); setPaddingLeft(paddingHorizontal); } else if(split.size() == 2) { int paddingVertical = stdext::safe_cast<int>(split[0]); int paddingHorizontal = stdext::safe_cast<int>(split[1]); setPaddingTop(paddingVertical); setPaddingRight(paddingHorizontal); setPaddingBottom(paddingVertical); setPaddingLeft(paddingHorizontal); } else if(split.size() == 1) { int padding = stdext::safe_cast<int>(split[0]); setPaddingTop(padding); setPaddingRight(padding); setPaddingBottom(padding); setPaddingLeft(padding); } } // layouts else if(node->tag() == "layout") { std::string layoutType; if(node->hasValue()) layoutType = node->value(); else layoutType = node->valueAt<std::string>("type", ""); if(!layoutType.empty()) { UILayoutPtr layout; if(layoutType == "horizontalBox") layout = UIHorizontalLayoutPtr(new UIHorizontalLayout(asUIWidget())); else if(layoutType == "verticalBox") layout = UIVerticalLayoutPtr(new UIVerticalLayout(asUIWidget())); else if(layoutType == "grid") layout = UIGridLayoutPtr(new UIGridLayout(asUIWidget())); else if(layoutType == "anchor") layout = UIAnchorLayoutPtr(new UIAnchorLayout(asUIWidget())); else throw OTMLException(node, "cannot determine layout type"); setLayout(layout); } if(node->hasChildren()) m_layout->applyStyle(node); } // anchors else if(boost::starts_with(node->tag(), "anchors.")) { UIWidgetPtr parent = getParent(); if(!parent) { if(m_firstOnStyle) throw OTMLException(node, "cannot create anchor, there is no parent widget!"); else continue; } UIAnchorLayoutPtr anchorLayout = parent->getLayout()->asUIAnchorLayout(); if(!anchorLayout) throw OTMLException(node, "cannot create anchor, the parent widget doesn't use anchor layout!"); std::string what = node->tag().substr(8); if(what == "fill") { fill(node->value()); } else if(what == "centerIn") { centerIn(node->value()); } else { Fw::AnchorEdge anchoredEdge = Fw::translateAnchorEdge(what); if(node->value() == "none") { removeAnchor(anchoredEdge); } else { std::vector<std::string> split = stdext::split(node->value(), "."); if(split.size() != 2) throw OTMLException(node, "invalid anchor description"); std::string hookedWidgetId = split[0]; Fw::AnchorEdge hookedEdge = Fw::translateAnchorEdge(split[1]); if(anchoredEdge == Fw::AnchorNone) throw OTMLException(node, "invalid anchor edge"); if(hookedEdge == Fw::AnchorNone) throw OTMLException(node, "invalid anchor target edge"); addAnchor(anchoredEdge, hookedWidgetId, hookedEdge); } } // lua functions } else if(boost::starts_with(node->tag(), "@")) { // load once if(m_firstOnStyle) { std::string funcName = node->tag().substr(1); std::string funcOrigin = "@" + node->source() + "[" + node->tag() + "]"; g_lua.loadFunction(node->value(), funcOrigin); luaSetField(funcName); } // lua fields value } else if(boost::starts_with(node->tag(), "&")) { std::string fieldName = node->tag().substr(1); std::string fieldOrigin = "@" + node->source() + "[" + node->tag() + "]"; g_lua.evaluateExpression(node->value(), fieldOrigin); luaSetField(fieldName); } } }