void UIWidget::updateStyle() { if(m_destroyed) return; if(m_loadingStyle && !m_updateStyleScheduled) { UIWidgetPtr self = static_self_cast<UIWidget>(); g_dispatcher.addEvent([self] { self->m_updateStyleScheduled = false; self->updateStyle(); }); m_updateStyleScheduled = true; return; } if(!m_style) return; OTMLNodePtr newStateStyle = OTMLNode::create(); // copy only the changed styles from default style if(m_stateStyle) { for(OTMLNodePtr node : m_stateStyle->children()) { if(OTMLNodePtr otherNode = m_style->get(node->tag())) newStateStyle->addChild(otherNode->clone()); } } // checks for states combination for(const OTMLNodePtr& style : m_style->children()) { if(stdext::starts_with(style->tag(), "$")) { std::string statesStr = style->tag().substr(1); std::vector<std::string> statesSplit = stdext::split(statesStr, " "); bool match = true; for(std::string stateStr : statesSplit) { if(stateStr.length() == 0) continue; bool notstate = (stateStr[0] == '!'); if(notstate) stateStr = stateStr.substr(1); bool stateOn = hasState(Fw::translateState(stateStr)); if((!notstate && !stateOn) || (notstate && stateOn)) match = false; } // merge states styles if(match) { newStateStyle->merge(style); } } } //TODO: prevent setting already set proprieties applyStyle(newStateStyle); m_stateStyle = newStateStyle; }
void Config::mergeNode(const std::string& key, const OTMLNodePtr& node) { OTMLNodePtr clone = node->clone(); node->setTag(key); node->setUnique(true); m_confsDoc->addChild(node); }
std::string UIManager::getStyleClass(const std::string& styleName) { OTMLNodePtr style = getStyle(styleName); if(style && style->get("__class")) return style->valueAt("__class"); return ""; }
ModulePtr ModuleManager::discoverModule(const std::string& moduleFile) { ModulePtr module; try { OTMLDocumentPtr doc = OTMLDocument::parse(moduleFile); OTMLNodePtr moduleNode = doc->at("Module"); std::string name = moduleNode->valueAt("name"); bool push = false; module = getModule(name); if(!module) { module = ModulePtr(new Module(name)); push = true; } module->discover(moduleNode); // not loaded modules are always in back if(push) m_modules.push_back(module); } catch(stdext::exception& e) { g_logger.error(stdext::format("Unable to discover module from file '%s': %s", moduleFile, e.what())); } return module; }
void OTMLNode::merge(const OTMLNodePtr& node) { for(const OTMLNodePtr& child : node->m_children) addChild(child->clone()); setTag(node->tag()); setSource(node->source()); }
std::string Config::getValue(const std::string& key) { OTMLNodePtr child = m_confsDoc->get(key); if(child) return child->value(); else return ""; }
void ParticleEffectType::load(const OTMLNodePtr& node) { m_node = node->clone(); for(const OTMLNodePtr& childNode : node->children()) { if(childNode->tag() == "name") m_name = childNode->value(); else if(childNode->tag() == "description") m_description = childNode->value(); } }
std::vector<std::string> Config::getList(const std::string& key) { std::vector<std::string> list; OTMLNodePtr child = m_confsDoc->get(key); if(child) { for(const OTMLNodePtr& subchild : child->children()) list.push_back(subchild->value()); } return list; }
UIWidgetPtr UIManager::createWidgetFromOTML(const OTMLNodePtr& widgetNode, const UIWidgetPtr& parent) { OTMLNodePtr originalStyleNode = getStyle(widgetNode->tag()); if(!originalStyleNode) stdext::throw_exception(stdext::format("'%s' is not a defined style", widgetNode->tag())); OTMLNodePtr styleNode = originalStyleNode->clone(); styleNode->merge(widgetNode); std::string widgetType = styleNode->valueAt("__class"); // call widget creation from lua UIWidgetPtr widget = g_lua.callGlobalField<UIWidgetPtr>(widgetType, "create"); if(parent) parent->addChild(widget); if(widget) { widget->callLuaField("onCreate"); widget->setStyleFromNode(styleNode); for(const OTMLNodePtr& childNode : styleNode->children()) { if(!childNode->isUnique()) { createWidgetFromOTML(childNode, widget); styleNode->removeChild(childNode); } } } else stdext::throw_exception(stdext::format("unable to create widget of type '%s'", widgetType)); widget->callLuaField("onSetup"); return widget; }
void OTMLNode::copy(const OTMLNodePtr& node) { setTag(node->tag()); setValue(node->rawValue()); setUnique(node->isUnique()); setNull(node->isNull()); setSource(node->source()); clear(); for(const OTMLNodePtr& child : node->m_children) addChild(child->clone()); }
void UIWidget::setStyle(const std::string& styleName) { OTMLNodePtr styleNode = g_ui.getStyle(styleName); if(!styleNode) { g_logger.traceError(stdext::format("unable to retrieve style '%s': not a defined style", styleName)); return; } styleNode = styleNode->clone(); applyStyle(styleNode); m_style = styleNode; updateStyle(); }
void UIWidget::setStyle(const std::string& styleName) { OTMLNodePtr styleNode = g_ui.getStyle(styleName); if(!styleNode) { logTraceError("unable to retrive style '", styleName, "': not a defined style"); return; } styleNode = styleNode->clone(); applyStyle(styleNode); m_style = styleNode; updateStyle(); }
void Config::setList(const std::string& key, const std::vector<std::string>& list) { remove(key); if(list.size() == 0) return; OTMLNodePtr child = OTMLNode::create(key, true); for(const std::string& value : list) child->writeIn(value); m_confsDoc->addChild(child); }
OTMLNodePtr UIManager::getStyle(const std::string& styleName) { auto it = m_styles.find(styleName); if(it != m_styles.end()) return m_styles[styleName]; // styles starting with UI are automatically defined if(stdext::starts_with(styleName, "UI")) { OTMLNodePtr node = OTMLNode::create(styleName); node->writeAt("__class", styleName); m_styles[styleName] = node; return node; } return nullptr; }
bool ParticleAffector::load(const OTMLNodePtr& node) { float minDelay = 0, maxDelay = 0; float minDuration = -1, maxDuration = -1; for(const OTMLNodePtr& childNode : node->children()) { if(childNode->tag() == "delay") { minDelay = childNode->value<float>(); maxDelay = childNode->value<float>(); } else if(childNode->tag() == "min-delay") minDelay = childNode->value<float>(); else if(childNode->tag() == "max-delay") maxDelay = childNode->value<float>(); if(childNode->tag() == "duration") { minDuration = childNode->value<float>(); maxDuration = childNode->value<float>(); } else if(childNode->tag() == "min-duration") minDuration = childNode->value<float>(); else if(childNode->tag() == "max-duration") maxDuration = childNode->value<float>(); } m_delay = Fw::randomRange(minDelay, maxDelay); m_duration = Fw::randomRange(minDuration, maxDuration); return true; }
void Module::discover(const OTMLNodePtr& moduleNode) { const static std::string none = "none"; m_description = moduleNode->valueAt("description", none); m_author = moduleNode->valueAt("author", none); m_website = moduleNode->valueAt("website", none); m_version = moduleNode->valueAt("version", none); m_autoLoad = moduleNode->valueAt<bool>("autoload", false); m_reloadable = moduleNode->valueAt<bool>("reloadable", true); m_autoLoadPriority = moduleNode->valueAt<int>("autoload-priority", 9999); if(OTMLNodePtr node = moduleNode->get("dependencies")) { for(const OTMLNodePtr& tmp : node->children()) m_dependencies.push_back(tmp->value()); } // set onLoad callback if(OTMLNodePtr node = moduleNode->get("@onLoad")) { g_lua.loadFunction(node->value(), "@" + node->source() + "[" + node->tag() + "]"); g_lua.useValue(); m_loadCallback = g_lua.polymorphicPop<std::function<void()>>(); } // set onUnload callback if(OTMLNodePtr node = moduleNode->get("@onUnload")) { g_lua.loadFunction(node->value(), "@" + node->source() + "[" + node->tag() + "]"); g_lua.useValue(); m_unloadCallback = g_lua.polymorphicPop<std::function<void()>>(); } if(OTMLNodePtr node = moduleNode->get("load-later")) { for(const OTMLNodePtr& tmp : node->children()) m_loadLaterModules.push_back(tmp->value()); } }
void UIProgressRect::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode) { UIWidget::onStyleApply(styleName, styleNode); for(const OTMLNodePtr& node : styleNode->children()) { if(node->tag() == "percent") setPercent(node->value<float>()); } }
void UIHorizontalLayout::applyStyle(const OTMLNodePtr& styleNode) { UIBoxLayout::applyStyle(styleNode); for(const OTMLNodePtr& node : styleNode->children()) { if(node->tag() == "align-right") setAlignRight(node->value<bool>()); } }
void BitmapFont::load(const OTMLNodePtr& fontNode) { OTMLNodePtr textureNode = fontNode->at("texture"); std::string textureFile = stdext::resolve_path(textureNode->value(), textureNode->source()); Size glyphSize = fontNode->valueAt<Size>("glyph-size"); m_glyphHeight = fontNode->valueAt<int>("height"); m_yOffset = fontNode->valueAt("y-offset", 0); m_firstGlyph = fontNode->valueAt("first-glyph", 32); m_glyphSpacing = fontNode->valueAt("spacing", Size(0,0)); int spaceWidth = fontNode->valueAt("space-width", glyphSize.width()); // load font texture m_texture = g_textures.getTexture(textureFile); if(OTMLNodePtr node = fontNode->get("fixed-glyph-width")) { for(int glyph = m_firstGlyph; glyph < 256; ++glyph) m_glyphsSize[glyph] = Size(node->value<int>(), m_glyphHeight); } else { calculateGlyphsWidthsAutomatically(Image::load(textureFile), glyphSize); } // 32 and 160 are spaces ( ) m_glyphsSize[32].setWidth(spaceWidth); m_glyphsSize[160].setWidth(spaceWidth); // use 127 as spacer [Width: 1], Important for the current NPC highlighting system m_glyphsSize[127].setWidth(1); // new line actually has a size that will be useful in multiline algorithm m_glyphsSize[(uchar)'\n'] = Size(1, m_glyphHeight); // read custom widths /* if(OTMLNodePtr node = fontNode->get("glyph-widths")) { for(const OTMLNodePtr& child : node->children()) m_glyphsSize[stdext::safe_cast<int>(child->tag())].setWidth(child->value<int>()); } */ // calculate glyphs texture coords int numHorizontalGlyphs = m_texture->getSize().width() / glyphSize.width(); for(int glyph = m_firstGlyph; glyph < 256; ++glyph) { m_glyphsTextureCoords[glyph].setRect(((glyph - m_firstGlyph) % numHorizontalGlyphs) * glyphSize.width(), ((glyph - m_firstGlyph) / numHorizontalGlyphs) * glyphSize.height(), m_glyphsSize[glyph].width(), m_glyphHeight); } }
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; } }
ModulePtr ModuleManager::discoverModule(const std::string& moduleFile) { ModulePtr module; try { OTMLDocumentPtr doc = OTMLDocument::parse(moduleFile); OTMLNodePtr moduleNode = doc->at("Module"); std::string name = moduleNode->valueAt("name"); if(getModule(name)) Fw::throwException("module '", name, "' already exists, cannot have duplicate module names"); module = ModulePtr(new Module(name)); module->discover(moduleNode); m_modules.push_back(module); } catch(Exception& e) { logError("Unable to discover module from file '", moduleFile, "': ", e.what()); } return module; }
void UIWidget::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode) { // first set id if(const OTMLNodePtr& node = styleNode->get("id")) setId(node->value()); parseBaseStyle(styleNode); parseImageStyle(styleNode); parseTextStyle(styleNode); }
void UIWidget::applyStyle(const OTMLNodePtr& styleNode) { if(m_destroyed) return; if(styleNode->size() == 0) return; m_loadingStyle = true; try { // translate ! style tags for(const OTMLNodePtr& node : styleNode->children()) { if(node->tag()[0] == '!') { std::string tag = node->tag().substr(1); std::string code = stdext::format("tostring(%s)", node->value()); std::string origin = "@" + node->source() + ": [" + node->tag() + "]"; g_lua.evaluateExpression(code, origin); std::string value = g_lua.popString(); node->setTag(tag); node->setValue(value); } } onStyleApply(styleNode->tag(), styleNode); callLuaField("onStyleApply", styleNode->tag(), styleNode); if(m_firstOnStyle) { UIWidgetPtr parent = getParent(); if(isFocusable() && isExplicitlyVisible() && isExplicitlyEnabled() && parent && ((!parent->getFocusedChild() && parent->getAutoFocusPolicy() == Fw::AutoFocusFirst) || parent->getAutoFocusPolicy() == Fw::AutoFocusLast)) { focus(); } } m_firstOnStyle = false; } catch(stdext::exception& e) { g_logger.traceError(stdext::format("failed to apply style to widget '%s': %s", m_id, e.what())); } m_loadingStyle = false; }
void UIBoxLayout::applyStyle(const OTMLNodePtr& styleNode) { UILayout::applyStyle(styleNode); for(const OTMLNodePtr& node : styleNode->children()) { if(node->tag() == "spacing") setSpacing(node->value<int>()); else if(node->tag() == "fit-children") setFitChildren(node->value<bool>()); } }
// otml nodes void push_otml_subnode_luavalue(const OTMLNodePtr& node) { if(node->hasValue()) { union { bool b; double d; long l; }; std::string value = node->rawValue(); if(stdext::cast(value, b)) g_lua.pushBoolean(b); else if(stdext::cast(value, l)) g_lua.pushInteger(l); else if(stdext::cast(value, d)) g_lua.pushNumber(d); else g_lua.pushString(value); } else if(node->hasChildren()) { g_lua.newTable(); bool pushedChild = false; int currentIndex = 1; for(const OTMLNodePtr& cnode : node->children()) { push_otml_subnode_luavalue(cnode); if(!g_lua.isNil()) { if(cnode->isUnique()) { g_lua.pushString(cnode->tag()); g_lua.insert(-2); g_lua.rawSet(); } else g_lua.rawSeti(currentIndex++); pushedChild = true; } else g_lua.pop(); } if(!pushedChild) { g_lua.pop(); g_lua.pushNil(); } } else g_lua.pushNil(); }
void UIMinimap::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode) { UIWidget::onStyleApply(styleName, styleNode); for(const OTMLNodePtr& node : styleNode->children()) { if(node->tag() == "zoom") setZoom(node->value<int>()); else if(node->tag() == "max-zoom") setMaxZoom(node->value<int>()); else if(node->tag() == "min-zoom") setMinZoom(node->value<int>()); } }
void UIWidget::applyStyle(const OTMLNodePtr& styleNode) { if(m_destroyed) return; if(styleNode->size() == 0) return; m_loadingStyle = true; try { // translate ! style tags for(const OTMLNodePtr& node : styleNode->children()) { if(node->tag()[0] == '!') { std::string tag = node->tag().substr(1); std::string code = Fw::formatString("tostring(%s)", node->value().c_str()); std::string origin = "@" + node->source() + "[" + node->tag() + "]"; g_lua.evaluateExpression(code, origin); std::string value = g_lua.popString(); node->setTag(tag); node->setValue(value); } } onStyleApply(styleNode->tag(), styleNode); callLuaField("onStyleApply", styleNode->tag(), styleNode); if(m_firstOnStyle) { callLuaField("onSetup"); // always focus new child if(isFocusable() && isExplicitlyVisible() && isExplicitlyEnabled()) focus(); } m_firstOnStyle = false; } catch(Exception& e) { logError("Failed to apply style to widget '", m_id, "' style: ", e.what()); } m_loadingStyle = false; }
void UIWidget::applyStyle(const OTMLNodePtr& styleNode) { if(styleNode->size() == 0) return; m_loadingStyle = true; try { onStyleApply(styleNode->tag(), styleNode); callLuaField("onStyleApply", styleNode->tag(), styleNode); if(m_firstOnStyle) { callLuaField("onSetup"); // always focus new child if(isFocusable() && isExplicitlyVisible() && isExplicitlyEnabled()) focus(); } m_firstOnStyle = false; } catch(Exception& e) { logError("Failed to apply style to widget '", m_id, "' style: ", e.what()); } m_loadingStyle = false; }
void UIWidget::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode) { if(m_destroyed) return; // first set id if(const OTMLNodePtr& node = styleNode->get("id")) setId(node->value()); parseBaseStyle(styleNode); parseImageStyle(styleNode); parseTextStyle(styleNode); g_app.repaint(); }
int push_luavalue(const OTMLNodePtr& node) { if(node) { g_lua.newTable(); int currentIndex = 1; for(const OTMLNodePtr& cnode : node->children()) { push_otml_subnode_luavalue(cnode); if(cnode->isUnique() && !cnode->tag().empty()) { g_lua.setField(cnode->tag()); } else g_lua.rawSeti(currentIndex++); } } else g_lua.pushNil(); return 1; }