make otml simpler and easier to use, improve error handling/exceptions
This commit is contained in:
		
							parent
							
								
									f9e7d52ac0
								
							
						
					
					
						commit
						033f14780d
					
				| 
						 | 
				
			
			@ -110,15 +110,16 @@ SET(SOURCES
 | 
			
		|||
    # framework otml
 | 
			
		||||
    src/framework/otml/otmldocument.cpp
 | 
			
		||||
    src/framework/otml/otmlemitter.cpp
 | 
			
		||||
    src/framework/otml/otmlexception.cpp
 | 
			
		||||
    src/framework/otml/otmlnode.cpp
 | 
			
		||||
    src/framework/otml/otmlparser.cpp
 | 
			
		||||
    src/framework/otml/otmlexception.cpp
 | 
			
		||||
 | 
			
		||||
    # framework luascript
 | 
			
		||||
    src/framework/luascript/luainterface.cpp
 | 
			
		||||
    src/framework/luascript/luaobject.cpp
 | 
			
		||||
    src/framework/luascript/luaexception.cpp
 | 
			
		||||
    src/framework/luascript/luafunctions.cpp
 | 
			
		||||
    src/framework/luascript/luavaluecasts.cpp
 | 
			
		||||
 | 
			
		||||
    # framework ui
 | 
			
		||||
    src/framework/ui/uimanager.cpp
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,27 +9,23 @@ bool Configs::load(const std::string& fileName)
 | 
			
		|||
{
 | 
			
		||||
    m_fileName = fileName;
 | 
			
		||||
 | 
			
		||||
    if(!g_resources.fileExists(fileName))
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        OTMLDocumentPtr doc = OTMLDocument::parse(fileName);
 | 
			
		||||
        for(const OTMLNodePtr& child : doc->childNodes())
 | 
			
		||||
        for(const OTMLNodePtr& child : doc->children())
 | 
			
		||||
            m_confsMap[child->tag()] = child->value();
 | 
			
		||||
        return true;
 | 
			
		||||
    } catch(std::exception& e) {
 | 
			
		||||
        logError("ERROR: could not load configurations: ", e.what());
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Configs::save()
 | 
			
		||||
{
 | 
			
		||||
    if(!m_fileName.empty()) {
 | 
			
		||||
        OTMLDocumentPtr doc = OTMLDocument::create();
 | 
			
		||||
        doc->write(m_confsMap);
 | 
			
		||||
        return doc->save(m_fileName);
 | 
			
		||||
    OTMLDocumentPtr doc = OTMLDocument::create();
 | 
			
		||||
    for(auto it : m_confsMap) {
 | 
			
		||||
        OTMLNodePtr node = OTMLNode::create(it.first, it.second);
 | 
			
		||||
        doc->addChild(node);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
    return doc->save(m_fileName);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,61 +6,57 @@
 | 
			
		|||
 | 
			
		||||
void Module::discover(const OTMLNodePtr& moduleNode)
 | 
			
		||||
{
 | 
			
		||||
    m_description = moduleNode->readAt<std::string>("description");
 | 
			
		||||
    m_author = moduleNode->readAt<std::string>("author");
 | 
			
		||||
    m_website = moduleNode->readAt<std::string>("website");
 | 
			
		||||
    m_version = moduleNode->readAt<std::string>("version");
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    if(OTMLNodePtr node = moduleNode->get("dependencies")) {
 | 
			
		||||
        for(const OTMLNodePtr& tmp : node->childNodes())
 | 
			
		||||
        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->read<std::string>(), "@" + node->source() + "[" + node->tag() + "]");
 | 
			
		||||
        g_lua.loadFunction(node->value<std::string>(), "@" + node->source() + "[" + node->tag() + "]");
 | 
			
		||||
        g_lua.useValue();
 | 
			
		||||
        m_loadCallback = g_lua.polymorphicPop<BooleanCallback>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // set onUnload callback
 | 
			
		||||
    if(OTMLNodePtr node = moduleNode->get("onUnload")) {
 | 
			
		||||
        g_lua.loadFunction(node->read<std::string>(), "@" + node->source() + "[" + node->tag() + "]");
 | 
			
		||||
        g_lua.loadFunction(node->value<std::string>(), "@" + node->source() + "[" + node->tag() + "]");
 | 
			
		||||
        g_lua.useValue();
 | 
			
		||||
        m_unloadCallback = g_lua.polymorphicPop<SimpleCallback>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // load if autoLoad is set
 | 
			
		||||
    m_autoLoad = moduleNode->readAt<bool>("autoLoad", false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Module::load()
 | 
			
		||||
{
 | 
			
		||||
    for(const std::string& depName : m_dependencies) {
 | 
			
		||||
        ModulePtr dep = g_modules.getModule(depName);
 | 
			
		||||
        if(!dep) {
 | 
			
		||||
            logError("ERROR: failed to load module '",m_name,"': could not find module dependency '",depName,"'");
 | 
			
		||||
            return false;
 | 
			
		||||
    try {
 | 
			
		||||
        for(const std::string& depName : m_dependencies) {
 | 
			
		||||
            ModulePtr dep = g_modules.getModule(depName);
 | 
			
		||||
            if(!dep)
 | 
			
		||||
                throw std::runtime_error(fw::mkstr("could not find module dependency '", depName ,"'"));
 | 
			
		||||
 | 
			
		||||
            if(!dep->isLoaded() && !dep->load())
 | 
			
		||||
                throw std::runtime_error(fw::mkstr("dependency '", depName, "' has failed to load"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(!dep->isLoaded()) {
 | 
			
		||||
            if(!dep->load()) {
 | 
			
		||||
                logError("ERROR: failed to load module '",m_name,"': a dependency has failed to load");
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        if(m_loadCallback) {
 | 
			
		||||
            m_loaded = m_loadCallback();
 | 
			
		||||
            if(!m_loaded)
 | 
			
		||||
                throw std::runtime_error("module onLoad event returned false");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        logInfo("Loaded module '", m_name, "'");
 | 
			
		||||
        return true;
 | 
			
		||||
    } catch(std::exception& e) {
 | 
			
		||||
        logError("ERROR: failed to load module '", m_name, "': ", e.what());
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(m_loadCallback) {
 | 
			
		||||
        m_loaded = m_loadCallback();
 | 
			
		||||
        if(!m_loaded) {
 | 
			
		||||
            logError("ERROR: failed to load module '",m_name, "': onLoad returned false");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    logInfo("Loaded module '", m_name, "'");
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Module::unload()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ bool ModuleManager::discoverModule(const std::string& file)
 | 
			
		|||
        OTMLDocumentPtr doc = OTMLDocument::parse(file);
 | 
			
		||||
        OTMLNodePtr moduleNode = doc->at("Module");
 | 
			
		||||
 | 
			
		||||
        std::string name = moduleNode->readAt<std::string>("name");
 | 
			
		||||
        std::string name = moduleNode->valueAt("name");
 | 
			
		||||
        if(getModule(name))
 | 
			
		||||
            throw OTMLException(moduleNode, "a module with the same name is already discovered, did you duplicate module names?");
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ bool ModuleManager::discoverModule(const std::string& file)
 | 
			
		|||
        module->discover(moduleNode);
 | 
			
		||||
        m_modules.push_back(module);
 | 
			
		||||
    } catch(std::exception& e) {
 | 
			
		||||
        logError("ERROR: failed to load module from '", file, "':\n", e.what());
 | 
			
		||||
        logError("ERROR: failed to load module from '", file, "': ", e.what());
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,14 +30,14 @@ void ResourceManager::init(const char* argv0)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    if(!found)
 | 
			
		||||
        throw std::runtime_error("could not find modules directory");
 | 
			
		||||
        logFatal("FATAL ERROR: could not find modules directory");
 | 
			
		||||
 | 
			
		||||
    // setup write directory
 | 
			
		||||
    std::string dir = g_platform.getAppUserDir();
 | 
			
		||||
    if(g_resources.setWriteDir(dir))
 | 
			
		||||
        g_resources.addToSearchPath(dir);
 | 
			
		||||
    else
 | 
			
		||||
        throw std::runtime_error("could not setup write directory");
 | 
			
		||||
        logError("ERROR: could not setup write directory");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ResourceManager::terminate()
 | 
			
		||||
| 
						 | 
				
			
			@ -156,12 +156,11 @@ std::string ResourceManager::resolvePath(const std::string& path)
 | 
			
		|||
{
 | 
			
		||||
    std::string fullPath;
 | 
			
		||||
    if(boost::starts_with(path, "/"))
 | 
			
		||||
        fullPath = path.substr(1);
 | 
			
		||||
        fullPath = path;
 | 
			
		||||
    else {
 | 
			
		||||
        std::string scriptPath = g_lua.currentSourcePath();
 | 
			
		||||
        if(!scriptPath.empty()) {
 | 
			
		||||
        std::string scriptPath = "/" + g_lua.currentSourcePath();
 | 
			
		||||
        if(!scriptPath.empty())
 | 
			
		||||
            fullPath += scriptPath + "/";
 | 
			
		||||
        }
 | 
			
		||||
        fullPath += path;
 | 
			
		||||
    }
 | 
			
		||||
    return fullPath;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,17 +61,17 @@ BorderImagePtr BorderImage::loadFromOTML(const OTMLNodePtr& borderImageNode)
 | 
			
		|||
 | 
			
		||||
    // load basic border confs
 | 
			
		||||
    size = texture->getSize();
 | 
			
		||||
    size = borderImageNode->readAt("size", size);
 | 
			
		||||
    offset = borderImageNode->readAt("offset", offset);
 | 
			
		||||
    border = borderImageNode->readAt("border", 0);
 | 
			
		||||
    size = borderImageNode->valueAt("size", size);
 | 
			
		||||
    offset = borderImageNode->valueAt("offset", offset);
 | 
			
		||||
    border = borderImageNode->valueAt("border", 0);
 | 
			
		||||
    subRect = Rect(offset, size);
 | 
			
		||||
 | 
			
		||||
    // load border margins
 | 
			
		||||
    top = bottom = left = right = border;
 | 
			
		||||
    top = borderImageNode->readAt("border.top", top);
 | 
			
		||||
    bottom = borderImageNode->readAt("border.bottom", bottom);
 | 
			
		||||
    left = borderImageNode->readAt("border.left", left);
 | 
			
		||||
    right = borderImageNode->readAt("border.right", right);
 | 
			
		||||
    top = borderImageNode->valueAt("border.top", top);
 | 
			
		||||
    bottom = borderImageNode->valueAt("border.bottom", bottom);
 | 
			
		||||
    left = borderImageNode->valueAt("border.left", left);
 | 
			
		||||
    right = borderImageNode->valueAt("border.right", right);
 | 
			
		||||
 | 
			
		||||
    // calculates border coords
 | 
			
		||||
    leftBorder = Rect(subRect.left(), subRect.top() + top, left, subRect.height() - top - bottom);
 | 
			
		||||
| 
						 | 
				
			
			@ -86,15 +86,15 @@ BorderImagePtr BorderImage::loadFromOTML(const OTMLNodePtr& borderImageNode)
 | 
			
		|||
 | 
			
		||||
    // load individual border conf if supplied
 | 
			
		||||
    /*
 | 
			
		||||
    leftBorder = borderImageNode->readAt("left border", leftBorder);
 | 
			
		||||
    rightBorder = borderImageNode->readAt("right border", rightBorder);
 | 
			
		||||
    topBorder = borderImageNode->readAt("top border", topBorder);
 | 
			
		||||
    bottomBorder = borderImageNode->readAt("bottom border", bottomBorder);
 | 
			
		||||
    topLeftCorner = borderImageNode->readAt("top left corner", topLeftCorner);
 | 
			
		||||
    topRightCorner = borderImageNode->readAt("top right corner", topRightCorner);
 | 
			
		||||
    bottomLeftCorner = borderImageNode->readAt("bottom left corner", bottomLeftCorner);
 | 
			
		||||
    bottomRightCorner = borderImageNode->readAt("bottom right corner", bottomRightCorner);
 | 
			
		||||
    center = borderImageNode->readAt("center", center);
 | 
			
		||||
    leftBorder = borderImageNode->valueAt("left border", leftBorder);
 | 
			
		||||
    rightBorder = borderImageNode->valueAt("right border", rightBorder);
 | 
			
		||||
    topBorder = borderImageNode->valueAt("top border", topBorder);
 | 
			
		||||
    bottomBorder = borderImageNode->valueAt("bottom border", bottomBorder);
 | 
			
		||||
    topLeftCorner = borderImageNode->valueAt("top left corner", topLeftCorner);
 | 
			
		||||
    topRightCorner = borderImageNode->valueAt("top right corner", topRightCorner);
 | 
			
		||||
    bottomLeftCorner = borderImageNode->valueAt("bottom left corner", bottomLeftCorner);
 | 
			
		||||
    bottomRightCorner = borderImageNode->valueAt("bottom right corner", bottomRightCorner);
 | 
			
		||||
    center = borderImageNode->valueAt("center", center);
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    return BorderImagePtr(new BorderImage(texture,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,6 @@ class Texture;
 | 
			
		|||
class Font;
 | 
			
		||||
class Image;
 | 
			
		||||
class BorderImage;
 | 
			
		||||
class TextArea;
 | 
			
		||||
class FrameBuffer;
 | 
			
		||||
 | 
			
		||||
typedef std::weak_ptr<Texture> TextureWeakPtr;
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +15,6 @@ typedef std::shared_ptr<Texture> TexturePtr;
 | 
			
		|||
typedef std::shared_ptr<Font> FontPtr;
 | 
			
		||||
typedef std::shared_ptr<Image> ImagePtr;
 | 
			
		||||
typedef std::shared_ptr<BorderImage> BorderImagePtr;
 | 
			
		||||
typedef std::shared_ptr<TextArea> TextAreaPtr;
 | 
			
		||||
typedef std::shared_ptr<FrameBuffer> FrameBufferPtr;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,25 +6,25 @@
 | 
			
		|||
 | 
			
		||||
void Font::load(const OTMLNodePtr& fontNode)
 | 
			
		||||
{
 | 
			
		||||
    std::string textureName = fontNode->readAt<std::string>("texture");
 | 
			
		||||
    Size glyphSize = fontNode->readAt<Size>("glyph size");
 | 
			
		||||
    m_glyphHeight = fontNode->readAt<int>("height");
 | 
			
		||||
    m_topMargin = fontNode->readAt("top margin", 0);
 | 
			
		||||
    m_firstGlyph = fontNode->readAt("first glyph", 32);
 | 
			
		||||
    m_glyphSpacing = fontNode->readAt("spacing", Size(0,0));
 | 
			
		||||
    std::string textureName = fontNode->valueAt("texture");
 | 
			
		||||
    Size glyphSize = fontNode->valueAt<Size>("glyph size");
 | 
			
		||||
    m_glyphHeight = fontNode->valueAt<int>("height");
 | 
			
		||||
    m_topMargin = fontNode->valueAt("top margin", 0);
 | 
			
		||||
    m_firstGlyph = fontNode->valueAt("first glyph", 32);
 | 
			
		||||
    m_glyphSpacing = fontNode->valueAt("spacing", Size(0,0));
 | 
			
		||||
 | 
			
		||||
    // load font texture
 | 
			
		||||
    m_texture = g_textures.getTexture(textureName);
 | 
			
		||||
    if(!m_texture)
 | 
			
		||||
        throw OTMLException(fontNode, "failed to load texture for font");
 | 
			
		||||
        throw std::runtime_error("failed to load texture for font");
 | 
			
		||||
 | 
			
		||||
    // auto calculate widths
 | 
			
		||||
    calculateGlyphsWidthsAutomatically(glyphSize);
 | 
			
		||||
 | 
			
		||||
    // read custom widths
 | 
			
		||||
    if(OTMLNodePtr node = fontNode->get("glyph widths")) {
 | 
			
		||||
        for(const OTMLNodePtr& child : node->childNodes())
 | 
			
		||||
            m_glyphsSize[fw::safe_cast<int>(child->tag())].setWidth(child->read<int>());
 | 
			
		||||
        for(const OTMLNodePtr& child : node->children())
 | 
			
		||||
            m_glyphsSize[fw::safe_cast<int>(child->tag())].setWidth(child->value<int>());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // calculate glyphs texture coords
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,9 +20,9 @@ bool FontManager::importFont(std::string fontFile)
 | 
			
		|||
        OTMLDocumentPtr doc = OTMLDocument::parse(fontFile);
 | 
			
		||||
        OTMLNodePtr fontNode = doc->at("Font");
 | 
			
		||||
 | 
			
		||||
        std::string name = fontNode->readAt<std::string>("name");
 | 
			
		||||
        std::string name = fontNode->valueAt("name");
 | 
			
		||||
        if(fontExists(name))
 | 
			
		||||
            throw OTMLException(fontNode, "a font with the same name is already imported, did you duplicate font names?");
 | 
			
		||||
            throw std::runtime_error("a font with the same name is already imported, did you duplicate font names?");
 | 
			
		||||
 | 
			
		||||
        FontPtr font(new Font(name));
 | 
			
		||||
        font->load(fontNode);
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ bool FontManager::importFont(std::string fontFile)
 | 
			
		|||
 | 
			
		||||
        return true;
 | 
			
		||||
    } catch(std::exception& e) {
 | 
			
		||||
        logError("ERROR: could not load font '", fontFile, "': ", e.what());
 | 
			
		||||
        logError("ERROR: could not load font from '", fontFile, "': ", e.what());
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,9 +17,9 @@ Image::Image(TexturePtr texture, Rect textureCoords)
 | 
			
		|||
ImagePtr Image::loadFromOTML(const OTMLNodePtr& imageNode)
 | 
			
		||||
{
 | 
			
		||||
    // load configs from otml node
 | 
			
		||||
    std::string source = imageNode->hasValue() ? imageNode->read<std::string>() : imageNode->readAt<std::string>("source");
 | 
			
		||||
    bool smooth = imageNode->readAt("smooth", false);
 | 
			
		||||
    Rect textureCoords = imageNode->readAt("coords", Rect());
 | 
			
		||||
    std::string source = imageNode->hasValue() ? imageNode->value() : imageNode->valueAt("source");
 | 
			
		||||
    bool smooth = imageNode->valueAt("smooth", false);
 | 
			
		||||
    Rect textureCoords = imageNode->valueAt("coords", Rect());
 | 
			
		||||
 | 
			
		||||
    // load texture
 | 
			
		||||
    TexturePtr texture = g_textures.getTexture(source);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ TexturePtr TextureManager::getTexture(const std::string& textureFile)
 | 
			
		|||
        try {
 | 
			
		||||
            // currently only png textures are supported
 | 
			
		||||
            if(!boost::ends_with(textureFile, ".png"))
 | 
			
		||||
                throw std::logic_error("texture file format no supported");
 | 
			
		||||
                throw std::runtime_error("texture file format no supported");
 | 
			
		||||
 | 
			
		||||
            // load texture file data
 | 
			
		||||
            std::stringstream fin;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,7 @@ namespace luabinder
 | 
			
		|||
    /// C++ function caller that can push results to lua
 | 
			
		||||
    template<typename Ret, typename F, typename... Args>
 | 
			
		||||
    typename std::enable_if<!std::is_void<Ret>::value, int>::type
 | 
			
		||||
    call_fun_and_push_result(const F& f, LuaInterface* lua, Args... args) {
 | 
			
		||||
    call_fun_and_push_result(const F& f, LuaInterface* lua, const Args&... args) {
 | 
			
		||||
        Ret ret = f(args...);
 | 
			
		||||
        lua->polymorphicPush(ret);
 | 
			
		||||
        return 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ namespace luabinder
 | 
			
		|||
    /// C++ void function caller
 | 
			
		||||
    template<typename Ret, typename F, typename... Args>
 | 
			
		||||
    typename std::enable_if<std::is_void<Ret>::value, int>::type
 | 
			
		||||
    call_fun_and_push_result(const F& f, LuaInterface* lua, Args... args) {
 | 
			
		||||
    call_fun_and_push_result(const F& f, LuaInterface* lua, const Args&... args) {
 | 
			
		||||
        f(args...);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -57,14 +57,14 @@ namespace luabinder
 | 
			
		|||
    template<int N, typename Ret>
 | 
			
		||||
    struct expand_fun_arguments {
 | 
			
		||||
        template<typename Tuple, typename F, typename... Args>
 | 
			
		||||
        static int call(const Tuple& tuple, const F& f, LuaInterface* lua, Args... args) {
 | 
			
		||||
            return expand_fun_arguments<N-1,Ret>::call(tuple, f, lua, std::cref(std::get<N-1>(tuple)), args...);
 | 
			
		||||
        static int call(const Tuple& tuple, const F& f, LuaInterface* lua, const Args&... args) {
 | 
			
		||||
            return expand_fun_arguments<N-1,Ret>::call(tuple, f, lua, std::get<N-1>(tuple), args...);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    template<typename Ret>
 | 
			
		||||
    struct expand_fun_arguments<0,Ret> {
 | 
			
		||||
        template<typename Tuple, typename F, typename... Args>
 | 
			
		||||
        static int call(const Tuple& tuple, const F& f, LuaInterface* lua, Args... args) {
 | 
			
		||||
        static int call(const Tuple& tuple, const F& f, LuaInterface* lua, const Args&... args) {
 | 
			
		||||
            return call_fun_and_push_result<Ret>(f, lua, args...);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			@ -178,7 +178,7 @@ namespace luabinder
 | 
			
		|||
    template<typename Ret, typename Obj, typename... Args>
 | 
			
		||||
    LuaCppFunction bind_mem_fun(Ret (Obj::*f)(Args...)) {
 | 
			
		||||
        auto mf = std::mem_fn(f);
 | 
			
		||||
        typedef typename std::tuple<Obj*, typename remove_const_ref<Args>::type...> Tuple;
 | 
			
		||||
        typedef typename std::tuple<std::shared_ptr<Obj>, typename remove_const_ref<Args>::type...> Tuple;
 | 
			
		||||
        return bind_fun_specializer<typename remove_const_ref<Ret>::type,
 | 
			
		||||
                                    decltype(mf),
 | 
			
		||||
                                    Tuple>(mf);
 | 
			
		||||
| 
						 | 
				
			
			@ -186,7 +186,7 @@ namespace luabinder
 | 
			
		|||
    template<typename Ret, typename Obj, typename... Args>
 | 
			
		||||
    LuaCppFunction bind_mem_fun(Ret (Obj::*f)(Args...) const) {
 | 
			
		||||
        auto mf = std::mem_fn(f);
 | 
			
		||||
        typedef typename std::tuple<Obj*, typename remove_const_ref<Args>::type...> Tuple;
 | 
			
		||||
        typedef typename std::tuple<std::shared_ptr<Obj>, typename remove_const_ref<Args>::type...> Tuple;
 | 
			
		||||
        return bind_fun_specializer<typename remove_const_ref<Ret>::type,
 | 
			
		||||
                                    decltype(mf),
 | 
			
		||||
                                    Tuple>(mf);
 | 
			
		||||
| 
						 | 
				
			
			@ -197,7 +197,7 @@ namespace luabinder
 | 
			
		|||
    LuaCppFunction bind_mem_fun(int (Obj::*f)(LuaInterface*)) {
 | 
			
		||||
        auto mf = std::mem_fn(f);
 | 
			
		||||
        return [=](LuaInterface* lua) {
 | 
			
		||||
            auto obj = lua->castValue<Obj*>(1);
 | 
			
		||||
            auto obj = lua->castValue<std::shared_ptr<Obj>>(1);
 | 
			
		||||
            lua->remove(1);
 | 
			
		||||
            return mf(obj, lua);
 | 
			
		||||
        };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,202 @@
 | 
			
		|||
#include "luavaluecasts.h"
 | 
			
		||||
#include "luainterface.h"
 | 
			
		||||
#include <framework/otml/otmlnode.h>
 | 
			
		||||
 | 
			
		||||
// bool
 | 
			
		||||
void push_luavalue(bool b)
 | 
			
		||||
{
 | 
			
		||||
    g_lua.pushBoolean(b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool luavalue_cast(int index, bool& b)
 | 
			
		||||
{
 | 
			
		||||
    b = g_lua.toBoolean(index);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// int
 | 
			
		||||
void push_luavalue(int i)
 | 
			
		||||
{
 | 
			
		||||
    g_lua.pushInteger(i);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool luavalue_cast(int index, int& i)
 | 
			
		||||
{
 | 
			
		||||
    i = g_lua.toInteger(index);
 | 
			
		||||
    if(i == 0 && !g_lua.isNumber(index))
 | 
			
		||||
        return false;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// double
 | 
			
		||||
void push_luavalue(double d)
 | 
			
		||||
{
 | 
			
		||||
    g_lua.pushNumber(d);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool luavalue_cast(int index, double& d)
 | 
			
		||||
{
 | 
			
		||||
    d = g_lua.toNumber(index);
 | 
			
		||||
    if(d == 0 && !g_lua.isNumber(index))
 | 
			
		||||
        return false;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// string
 | 
			
		||||
void push_luavalue(const char* cstr)
 | 
			
		||||
{
 | 
			
		||||
    g_lua.pushCString(cstr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void push_luavalue(const std::string& str)
 | 
			
		||||
{
 | 
			
		||||
    g_lua.pushString(str);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool luavalue_cast(int index, std::string& str)
 | 
			
		||||
{
 | 
			
		||||
    str = g_lua.toString(index);
 | 
			
		||||
    if(str.empty() && !g_lua.isString(index))
 | 
			
		||||
        return false;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// lua cpp function
 | 
			
		||||
void push_luavalue(const LuaCppFunction& func)
 | 
			
		||||
{
 | 
			
		||||
    g_lua.pushCppFunction(func);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// color
 | 
			
		||||
void push_luavalue(const Color& color)
 | 
			
		||||
{
 | 
			
		||||
    g_lua.newTable();
 | 
			
		||||
    g_lua.pushInteger(color.r());
 | 
			
		||||
    g_lua.setField("r");
 | 
			
		||||
    g_lua.pushInteger(color.g());
 | 
			
		||||
    g_lua.setField("g");
 | 
			
		||||
    g_lua.pushInteger(color.b());
 | 
			
		||||
    g_lua.setField("b");
 | 
			
		||||
    g_lua.pushInteger(color.a());
 | 
			
		||||
    g_lua.setField("a");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool luavalue_cast(int index, Color& color)
 | 
			
		||||
{
 | 
			
		||||
    if(g_lua.isTable(index)) {
 | 
			
		||||
        g_lua.getField("r", index);
 | 
			
		||||
        color.setRed(g_lua.popInteger());
 | 
			
		||||
        g_lua.getField("g", index);
 | 
			
		||||
        color.setGreen(g_lua.popInteger());
 | 
			
		||||
        g_lua.getField("b", index);
 | 
			
		||||
        color.setBlue(g_lua.popInteger());
 | 
			
		||||
        g_lua.getField("a", index);
 | 
			
		||||
        color.setAlpha(g_lua.popInteger());
 | 
			
		||||
        return true;
 | 
			
		||||
    } else if(g_lua.isString()) {
 | 
			
		||||
        return fw::cast(g_lua.toString(index), color);
 | 
			
		||||
    } else if(g_lua.isNil()) {
 | 
			
		||||
        color = Color::white;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// rect
 | 
			
		||||
void push_luavalue(const Rect& rect)
 | 
			
		||||
{
 | 
			
		||||
    g_lua.newTable();
 | 
			
		||||
    g_lua.pushInteger(rect.x());
 | 
			
		||||
    g_lua.setField("x");
 | 
			
		||||
    g_lua.pushInteger(rect.y());
 | 
			
		||||
    g_lua.setField("y");
 | 
			
		||||
    g_lua.pushInteger(rect.width());
 | 
			
		||||
    g_lua.setField("width");
 | 
			
		||||
    g_lua.pushInteger(rect.height());
 | 
			
		||||
    g_lua.setField("height");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool luavalue_cast(int index, Rect& rect)
 | 
			
		||||
{
 | 
			
		||||
    if(g_lua.isTable(index)) {
 | 
			
		||||
        g_lua.getField("x", index);
 | 
			
		||||
        rect.setX(g_lua.popInteger());
 | 
			
		||||
        g_lua.getField("y", index);
 | 
			
		||||
        rect.setY(g_lua.popInteger());
 | 
			
		||||
        g_lua.getField("width", index);
 | 
			
		||||
        rect.setWidth(g_lua.popInteger());
 | 
			
		||||
        g_lua.getField("height", index);
 | 
			
		||||
        rect.setHeight(g_lua.popInteger());
 | 
			
		||||
    } else if(g_lua.isString()) {
 | 
			
		||||
        return fw::cast(g_lua.toString(index), rect);
 | 
			
		||||
    } else if(g_lua.isNil()) {
 | 
			
		||||
        rect = Rect();
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// point
 | 
			
		||||
void push_luavalue(const Point& point)
 | 
			
		||||
{
 | 
			
		||||
    g_lua.newTable();
 | 
			
		||||
    g_lua.pushInteger(point.x);
 | 
			
		||||
    g_lua.setField("x");
 | 
			
		||||
    g_lua.pushInteger(point.y);
 | 
			
		||||
    g_lua.setField("y");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool luavalue_cast(int index, Point& point)
 | 
			
		||||
{
 | 
			
		||||
    if(g_lua.isTable(index)) {
 | 
			
		||||
        g_lua.getField("x", index);
 | 
			
		||||
        point.x = g_lua.popInteger();
 | 
			
		||||
        g_lua.getField("y", index);
 | 
			
		||||
        point.y = g_lua.popInteger();
 | 
			
		||||
        return true;
 | 
			
		||||
    } else if(g_lua.isString()) {
 | 
			
		||||
        return fw::cast(g_lua.toString(index), point);
 | 
			
		||||
    } else if(g_lua.isNil()) {
 | 
			
		||||
        point = Point();
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// otml nodes
 | 
			
		||||
void push_luavalue(const OTMLNodePtr& node)
 | 
			
		||||
{
 | 
			
		||||
    if(node->hasValue()) {
 | 
			
		||||
        g_lua.pushString(node->value());
 | 
			
		||||
    } else if(node->hasChildren()) {
 | 
			
		||||
        g_lua.newTable();
 | 
			
		||||
        bool pushedChild = false;
 | 
			
		||||
        for(const OTMLNodePtr& cnode : node->children()) {
 | 
			
		||||
            if(cnode->isUnique()) {
 | 
			
		||||
                push_luavalue(cnode);
 | 
			
		||||
                if(!g_lua.isNil()) {
 | 
			
		||||
                    g_lua.setField(cnode->tag());
 | 
			
		||||
                    pushedChild = true;
 | 
			
		||||
                } else
 | 
			
		||||
                    g_lua.pop();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if(!pushedChild) {
 | 
			
		||||
            g_lua.pop();
 | 
			
		||||
            g_lua.pushNil();
 | 
			
		||||
        }
 | 
			
		||||
    } else
 | 
			
		||||
        g_lua.pushNil();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// object ptr
 | 
			
		||||
bool luavalue_cast(int index, LuaObjectPtr& obj) {
 | 
			
		||||
    if(g_lua.isUserdata(index)) {
 | 
			
		||||
        obj = g_lua.toObject(index);
 | 
			
		||||
        return true;
 | 
			
		||||
    } else if(g_lua.isNil(index)) {
 | 
			
		||||
        obj = nullptr;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2,137 +2,123 @@
 | 
			
		|||
#define LUAVALUECASTS_H
 | 
			
		||||
 | 
			
		||||
// this file is and must be included only from luainterface.h
 | 
			
		||||
#include "luainterface.h"
 | 
			
		||||
#include "luaexception.h"
 | 
			
		||||
 | 
			
		||||
/// Pushes bool
 | 
			
		||||
inline void push_luavalue(bool v) {
 | 
			
		||||
    g_lua.pushBoolean(v);
 | 
			
		||||
}
 | 
			
		||||
#include "declarations.h"
 | 
			
		||||
#include <framework/otml/declarations.h>
 | 
			
		||||
 | 
			
		||||
/// Pushes int
 | 
			
		||||
inline void push_luavalue(int v) {
 | 
			
		||||
    g_lua.pushInteger(v);
 | 
			
		||||
}
 | 
			
		||||
// bool
 | 
			
		||||
void push_luavalue(bool b);
 | 
			
		||||
bool luavalue_cast(int index, bool& b);
 | 
			
		||||
 | 
			
		||||
/// Pushes double
 | 
			
		||||
inline void push_luavalue(double v) {
 | 
			
		||||
    g_lua.pushNumber(v);
 | 
			
		||||
}
 | 
			
		||||
// int
 | 
			
		||||
void push_luavalue(int i);
 | 
			
		||||
bool luavalue_cast(int index, int& i);
 | 
			
		||||
 | 
			
		||||
/// Pushes std::string
 | 
			
		||||
inline void push_luavalue(const std::string& v) {
 | 
			
		||||
    g_lua.pushString(v);
 | 
			
		||||
}
 | 
			
		||||
// double
 | 
			
		||||
void push_luavalue(double d);
 | 
			
		||||
bool luavalue_cast(int index, double& d);
 | 
			
		||||
 | 
			
		||||
/// Pushes const char*
 | 
			
		||||
inline void push_luavalue(const char* v) {
 | 
			
		||||
    g_lua.pushCString(v);
 | 
			
		||||
}
 | 
			
		||||
// string
 | 
			
		||||
void push_luavalue(const char* cstr);
 | 
			
		||||
void push_luavalue(const std::string& str);
 | 
			
		||||
bool luavalue_cast(int index, std::string& str);
 | 
			
		||||
 | 
			
		||||
/// Pushes LuaCppFunction
 | 
			
		||||
inline void push_luavalue(const LuaCppFunction& v) {
 | 
			
		||||
    g_lua.pushCppFunction(v);
 | 
			
		||||
}
 | 
			
		||||
// lua cpp function
 | 
			
		||||
void push_luavalue(const LuaCppFunction& func);
 | 
			
		||||
 | 
			
		||||
/// Pushes LuaObjectPtr
 | 
			
		||||
// color
 | 
			
		||||
void push_luavalue(const Color& color);
 | 
			
		||||
bool luavalue_cast(int index, Color& color);
 | 
			
		||||
 | 
			
		||||
// rect
 | 
			
		||||
void push_luavalue(const Rect& rect);
 | 
			
		||||
bool luavalue_cast(int index, Rect& rect);
 | 
			
		||||
 | 
			
		||||
// point
 | 
			
		||||
void push_luavalue(const Point& point);
 | 
			
		||||
bool luavalue_cast(int index, Point& point);
 | 
			
		||||
 | 
			
		||||
// size
 | 
			
		||||
void push_luavalue(const Size& size);
 | 
			
		||||
bool luavalue_cast(int index, Size& size);
 | 
			
		||||
 | 
			
		||||
// otml nodes
 | 
			
		||||
void push_luavalue(const OTMLNodePtr& node);
 | 
			
		||||
 | 
			
		||||
// enum
 | 
			
		||||
template<class T>
 | 
			
		||||
typename std::enable_if<std::is_enum<T>::value, bool>::type
 | 
			
		||||
luavalue_cast(int index, T& myenum);
 | 
			
		||||
 | 
			
		||||
// LuaObject pointers
 | 
			
		||||
template<class T>
 | 
			
		||||
typename std::enable_if<std::is_base_of<LuaObject, typename T::element_type>::value, void>::type
 | 
			
		||||
push_luavalue(const T& v) {
 | 
			
		||||
    if(v)
 | 
			
		||||
        return g_lua.pushObject(v);
 | 
			
		||||
push_luavalue(const T& obj);
 | 
			
		||||
 | 
			
		||||
bool luavalue_cast(int index, LuaObjectPtr& obj);
 | 
			
		||||
 | 
			
		||||
template<class T>
 | 
			
		||||
typename std::enable_if<std::is_base_of<LuaObject, T>::value, bool>::type
 | 
			
		||||
luavalue_cast(int index, std::shared_ptr<T>& ptr);
 | 
			
		||||
 | 
			
		||||
// std::function
 | 
			
		||||
template<typename Ret, typename... Args>
 | 
			
		||||
void push_luavalue(const std::function<Ret(Args...)>& func);
 | 
			
		||||
 | 
			
		||||
template<typename... Args>
 | 
			
		||||
bool luavalue_cast(int index, std::function<void(Args...)>& func);
 | 
			
		||||
 | 
			
		||||
template<typename Ret, typename... Args>
 | 
			
		||||
typename std::enable_if<!std::is_void<Ret>::value, bool>::type
 | 
			
		||||
luavalue_cast(int index, std::function<Ret(Args...)>& func);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// start definitions
 | 
			
		||||
 | 
			
		||||
#include "luaexception.h"
 | 
			
		||||
#include "luainterface.h"
 | 
			
		||||
 | 
			
		||||
template<class T>
 | 
			
		||||
typename std::enable_if<std::is_enum<T>::value, bool>::type
 | 
			
		||||
luavalue_cast(int index, T& myenum) {
 | 
			
		||||
    return luavalue_cast(index, (int&)myenum);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<class T>
 | 
			
		||||
typename std::enable_if<std::is_base_of<LuaObject, typename T::element_type>::value, void>::type
 | 
			
		||||
push_luavalue(const T& obj) {
 | 
			
		||||
    if(obj)
 | 
			
		||||
        return g_lua.pushObject(obj);
 | 
			
		||||
    return g_lua.pushNil();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Push std::function types
 | 
			
		||||
template<class T>
 | 
			
		||||
typename std::enable_if<std::is_base_of<LuaObject, T>::value, bool>::type
 | 
			
		||||
luavalue_cast(int index, std::shared_ptr<T>& ptr) {
 | 
			
		||||
    LuaObjectPtr obj;
 | 
			
		||||
    if(!luavalue_cast(index, obj))
 | 
			
		||||
        return false;
 | 
			
		||||
    ptr = std::dynamic_pointer_cast<T>(obj);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename Ret, typename... Args>
 | 
			
		||||
void push_luavalue(const std::function<Ret(Args...)>& v) {
 | 
			
		||||
    if(v) {
 | 
			
		||||
        LuaCppFunction f = luabinder::bind_fun(v);
 | 
			
		||||
void push_luavalue(const std::function<Ret(Args...)>& func) {
 | 
			
		||||
    if(func) {
 | 
			
		||||
        LuaCppFunction f = luabinder::bind_fun(func);
 | 
			
		||||
        g_lua.pushCppFunction(f);
 | 
			
		||||
    } else
 | 
			
		||||
        g_lua.pushNil();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Casts lua value to bool
 | 
			
		||||
inline bool luavalue_cast(int index, bool& o) {
 | 
			
		||||
    o = g_lua.toBoolean(index);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Casts lua value to int
 | 
			
		||||
inline bool luavalue_cast(int index, int& o) {
 | 
			
		||||
    o = g_lua.toInteger(index);
 | 
			
		||||
    if(o == 0 && !g_lua.isNumber(index))
 | 
			
		||||
        return false;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Casts lua value to double
 | 
			
		||||
inline bool luavalue_cast(int index, double& o) {
 | 
			
		||||
    o = g_lua.toNumber(index);
 | 
			
		||||
    if(o == 0 && !g_lua.isNumber(index))
 | 
			
		||||
        return false;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Casts lua value to std::string
 | 
			
		||||
inline bool luavalue_cast(int index, std::string& o) {
 | 
			
		||||
    o = g_lua.toString(index);
 | 
			
		||||
    if(o.empty() && !g_lua.isString(index))
 | 
			
		||||
        return false;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Casts lua value to LuaObjectPtr
 | 
			
		||||
inline bool luavalue_cast(int index, LuaObjectPtr& o) {
 | 
			
		||||
    if(g_lua.isUserdata(index)) {
 | 
			
		||||
        o = g_lua.toObject(index);
 | 
			
		||||
        return true;
 | 
			
		||||
    } else if(g_lua.isNil(index)) {
 | 
			
		||||
        o = nullptr;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Casts lua value to enum
 | 
			
		||||
template<class T>
 | 
			
		||||
typename std::enable_if<std::is_enum<T>::value, bool>::type
 | 
			
		||||
luavalue_cast(int index, T& o) {
 | 
			
		||||
    return luavalue_cast(index, (int&)o);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Cast lua userdata to a class pointer
 | 
			
		||||
template<class T>
 | 
			
		||||
typename std::enable_if<std::is_base_of<LuaObject, T>::value, bool>::type
 | 
			
		||||
luavalue_cast(int index, T*& o) {
 | 
			
		||||
    LuaObjectPtr obj;
 | 
			
		||||
    if(!luavalue_cast(index, obj))
 | 
			
		||||
        return false;
 | 
			
		||||
    o = std::dynamic_pointer_cast<T>(obj).get();
 | 
			
		||||
    return !!o;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Cast lua userdata to a class shared pointer
 | 
			
		||||
template<class T>
 | 
			
		||||
bool luavalue_cast(int index, std::shared_ptr<T>& o) {
 | 
			
		||||
    LuaObjectPtr obj;
 | 
			
		||||
    if(!luavalue_cast(index, obj))
 | 
			
		||||
        return false;
 | 
			
		||||
    o = std::dynamic_pointer_cast<T>(obj);
 | 
			
		||||
    return !!o;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Cast a lua function to a std::function
 | 
			
		||||
template<typename... Args>
 | 
			
		||||
bool luavalue_cast(int index, std::function<void(Args...)>& o) {
 | 
			
		||||
bool luavalue_cast(int index, std::function<void(Args...)>& func) {
 | 
			
		||||
    if(g_lua.isFunction(index)) {
 | 
			
		||||
        g_lua.pushValue(index);
 | 
			
		||||
        // weak references are used here, this means that the script must hold another reference
 | 
			
		||||
        // to this function, otherwise it will expire
 | 
			
		||||
        int funcWeakRef = g_lua.weakRef();
 | 
			
		||||
        o = [=](Args... args...) {
 | 
			
		||||
        func = [=](Args... args...) {
 | 
			
		||||
            // note that we must catch exceptions, because this lambda can be called from anywhere
 | 
			
		||||
            // and most of them won't catch exceptions (e.g. dispatcher)
 | 
			
		||||
            g_lua.getWeakRef(funcWeakRef);
 | 
			
		||||
| 
						 | 
				
			
			@ -150,22 +136,21 @@ bool luavalue_cast(int index, std::function<void(Args...)>& o) {
 | 
			
		|||
        };
 | 
			
		||||
        return true;
 | 
			
		||||
    } else if(g_lua.isNil(index)) {
 | 
			
		||||
        o = std::function<void(Args...)>();
 | 
			
		||||
        func = std::function<void(Args...)>();
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Cast a lua function to a std::function that can return
 | 
			
		||||
template<typename Ret, typename... Args>
 | 
			
		||||
typename std::enable_if<!std::is_void<Ret>::value, bool>::type
 | 
			
		||||
luavalue_cast(int index, std::function<Ret(Args...)>& o) {
 | 
			
		||||
luavalue_cast(int index, std::function<Ret(Args...)>& func) {
 | 
			
		||||
    if(g_lua.isFunction(index)) {
 | 
			
		||||
        g_lua.pushValue(index);
 | 
			
		||||
        // weak references are used here, this means that the script must hold another reference
 | 
			
		||||
        // to this function, otherwise it will expire
 | 
			
		||||
        int funcWeakRef = g_lua.weakRef();
 | 
			
		||||
        o = [=](Args... args...) -> Ret {
 | 
			
		||||
        func = [=](Args... args...) -> Ret {
 | 
			
		||||
            // note that we must catch exceptions, because this lambda can be called from anywhere
 | 
			
		||||
            // and most of them won't catch exceptions (e.g. dispatcher)
 | 
			
		||||
            try {
 | 
			
		||||
| 
						 | 
				
			
			@ -186,40 +171,10 @@ luavalue_cast(int index, std::function<Ret(Args...)>& o) {
 | 
			
		|||
        };
 | 
			
		||||
        return true;
 | 
			
		||||
    } else if(g_lua.isNil(index)) {
 | 
			
		||||
        o = std::function<Ret(Args...)>();
 | 
			
		||||
        func = std::function<Ret(Args...)>();
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// additional casts
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
inline void push_luavalue(const Color& v) {
 | 
			
		||||
    g_lua.newTable();
 | 
			
		||||
    g_lua.pushInteger(v.r());
 | 
			
		||||
    g_lua.setField("r");
 | 
			
		||||
    g_lua.pushInteger(v.g());
 | 
			
		||||
    g_lua.setField("g");
 | 
			
		||||
    g_lua.pushInteger(v.b());
 | 
			
		||||
    g_lua.setField("b");
 | 
			
		||||
    g_lua.pushInteger(v.a());
 | 
			
		||||
    g_lua.setField("a");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline bool luavalue_cast(int index, Color& o) {
 | 
			
		||||
    if(!g_lua.isTable(index))
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    g_lua.getField("r", index);
 | 
			
		||||
    o.setRed(g_lua.popInteger());
 | 
			
		||||
    g_lua.getField("g", index);
 | 
			
		||||
    o.setGreen(g_lua.popInteger());
 | 
			
		||||
    g_lua.getField("b", index);
 | 
			
		||||
    o.setBlue(g_lua.popInteger());
 | 
			
		||||
    g_lua.getField("a", index);
 | 
			
		||||
    o.setAlpha(g_lua.popInteger());
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,5 @@
 | 
			
		|||
 | 
			
		||||
#include "otmldocument.h"
 | 
			
		||||
#include "otmlnode.h"
 | 
			
		||||
#include "otmlnodeext.h"
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ OTMLDocumentPtr OTMLDocument::parse(const std::string& fileName)
 | 
			
		|||
{
 | 
			
		||||
    std::stringstream fin;
 | 
			
		||||
    g_resources.loadFile(fileName, fin);
 | 
			
		||||
    return parse(fin, fileName);
 | 
			
		||||
    return parse(fin, g_resources.resolvePath(fileName));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
OTMLDocumentPtr OTMLDocument::parse(std::istream& in, const std::string& source)
 | 
			
		||||
| 
						 | 
				
			
			@ -34,8 +34,7 @@ std::string OTMLDocument::emit()
 | 
			
		|||
 | 
			
		||||
bool OTMLDocument::save(const std::string& fileName)
 | 
			
		||||
{
 | 
			
		||||
    setSource(fileName);
 | 
			
		||||
 | 
			
		||||
    m_source = fileName;
 | 
			
		||||
    return g_resources.saveFile(fileName, emit());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,13 +16,15 @@ std::string OTMLEmitter::emitNode(const OTMLNodePtr& node, int currentDepth)
 | 
			
		|||
            ss << node->tag();
 | 
			
		||||
 | 
			
		||||
            // add ':' to if the node is unique or has value
 | 
			
		||||
            if(node->hasValue() || node->isUnique())
 | 
			
		||||
            if(node->hasValue() || node->isUnique() || node->isNull())
 | 
			
		||||
                ss << ":";
 | 
			
		||||
        } else
 | 
			
		||||
            ss << "-";
 | 
			
		||||
 | 
			
		||||
        // emit node value
 | 
			
		||||
        if(node->hasValue()) {
 | 
			
		||||
        if(node->isNull())
 | 
			
		||||
            ss << " ~";
 | 
			
		||||
        else if(node->hasValue()) {
 | 
			
		||||
            ss << " ";
 | 
			
		||||
 | 
			
		||||
            std::string value = node->value();
 | 
			
		||||
| 
						 | 
				
			
			@ -61,7 +63,7 @@ std::string OTMLEmitter::emitNode(const OTMLNodePtr& node, int currentDepth)
 | 
			
		|||
    for(int i=0;i<node->size();++i) {
 | 
			
		||||
        if(currentDepth >= 0 || i != 0)
 | 
			
		||||
            ss << "\n";
 | 
			
		||||
        ss << emitNode(node->at(i), currentDepth+1);
 | 
			
		||||
        ss << emitNode(node->atIndex(i), currentDepth+1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ss.str();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,9 +14,6 @@ public:
 | 
			
		|||
    virtual const char* what() const throw() { return m_what.c_str(); }
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    OTMLException() { }
 | 
			
		||||
    void generateErrorMessage(const OTMLDocumentPtr& doc, const std::string& error, int line);
 | 
			
		||||
    void generateErrorMessage(const OTMLNodePtr& node, const std::string& error);
 | 
			
		||||
    std::string m_what;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,157 +2,86 @@
 | 
			
		|||
#include "otmlemitter.h"
 | 
			
		||||
#include "otmldocument.h"
 | 
			
		||||
 | 
			
		||||
OTMLNode::OTMLNode()
 | 
			
		||||
OTMLNodePtr OTMLNode::create(std::string tag, bool unique)
 | 
			
		||||
{
 | 
			
		||||
    m_unique = false;
 | 
			
		||||
    OTMLNodePtr node(new OTMLNode);
 | 
			
		||||
    node->setTag(tag);
 | 
			
		||||
    node->setUnique(unique);
 | 
			
		||||
    return node;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string OTMLNode::tag() const
 | 
			
		||||
OTMLNodePtr OTMLNode::create(std::string tag, std::string value)
 | 
			
		||||
{
 | 
			
		||||
    return m_tag;
 | 
			
		||||
    OTMLNodePtr node(new OTMLNode);
 | 
			
		||||
    node->setTag(tag);
 | 
			
		||||
    node->setValue(value);
 | 
			
		||||
    node->setUnique(true);
 | 
			
		||||
    return node;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string OTMLNode::value() const
 | 
			
		||||
bool OTMLNode::hasChildren() const
 | 
			
		||||
{
 | 
			
		||||
    // ~ is an alias for no value
 | 
			
		||||
    if(m_value == "~")
 | 
			
		||||
        return fw::empty_string;
 | 
			
		||||
    return m_value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int OTMLNode::size() const
 | 
			
		||||
{
 | 
			
		||||
    return m_childNodes.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
OTMLNodePtr OTMLNode::parent() const
 | 
			
		||||
{
 | 
			
		||||
    return m_parent.lock();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const OTMLNodeList& OTMLNode::childNodes() const
 | 
			
		||||
{
 | 
			
		||||
    return m_childNodes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string OTMLNode::source() const
 | 
			
		||||
{
 | 
			
		||||
    return m_source;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool OTMLNode::hasTag() const
 | 
			
		||||
{
 | 
			
		||||
    return !m_tag.empty();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool OTMLNode::hasValue() const
 | 
			
		||||
{
 | 
			
		||||
    return (!m_value.empty() && m_value != "~");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool OTMLNode::hasChildNodes() const
 | 
			
		||||
{
 | 
			
		||||
    return size() > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool OTMLNode::hasChild(const std::string& childTag) const
 | 
			
		||||
{
 | 
			
		||||
    return !!get(childTag);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool OTMLNode::hasChild(int index) const
 | 
			
		||||
{
 | 
			
		||||
    return !!get(index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool OTMLNode::isUnique() const
 | 
			
		||||
{
 | 
			
		||||
    return m_unique;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OTMLNode::setTag(std::string tag)
 | 
			
		||||
{
 | 
			
		||||
    m_tag = tag;
 | 
			
		||||
 | 
			
		||||
    // valued nodes that has tags are always unique
 | 
			
		||||
    if(!m_value.empty() && hasTag())
 | 
			
		||||
        setUnique();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OTMLNode::setValue(const std::string& value)
 | 
			
		||||
{
 | 
			
		||||
    m_value = value;
 | 
			
		||||
 | 
			
		||||
    // valued nodes that has tags are always unique
 | 
			
		||||
    if(!m_value.empty() && hasTag())
 | 
			
		||||
        setUnique();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OTMLNode::setParent(const OTMLNodePtr& parent)
 | 
			
		||||
{
 | 
			
		||||
    m_parent = parent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OTMLNode::setUnique(bool unique)
 | 
			
		||||
{
 | 
			
		||||
    m_unique = unique;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OTMLNode::setSource(const std::string& source)
 | 
			
		||||
{
 | 
			
		||||
    m_source = source;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
OTMLNodePtr OTMLNode::at(const std::string& childTag)
 | 
			
		||||
{
 | 
			
		||||
    for(const OTMLNodePtr& child : m_childNodes) {
 | 
			
		||||
        if(child->tag() == childTag)
 | 
			
		||||
            return child;
 | 
			
		||||
    int count = 0;
 | 
			
		||||
    for(const OTMLNodePtr& child : m_children) {
 | 
			
		||||
        if(!child->isNull())
 | 
			
		||||
            count++;
 | 
			
		||||
    }
 | 
			
		||||
    throw OTMLException(shared_from_this(), fw::mkstr("child node with tag '", childTag, "' not found"));
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
OTMLNodePtr OTMLNode::at(int childIndex)
 | 
			
		||||
{
 | 
			
		||||
    if(childIndex < size() && childIndex >= 0)
 | 
			
		||||
        return m_childNodes[childIndex];
 | 
			
		||||
    throw OTMLException(shared_from_this(), fw::mkstr("child node at index '", childIndex, "' not found"));
 | 
			
		||||
    return nullptr;
 | 
			
		||||
    return count > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
OTMLNodePtr OTMLNode::get(const std::string& childTag) const
 | 
			
		||||
{
 | 
			
		||||
    for(const OTMLNodePtr& child : m_childNodes) {
 | 
			
		||||
        if(child->tag() == childTag)
 | 
			
		||||
    for(const OTMLNodePtr& child : m_children) {
 | 
			
		||||
        if(child->tag() == childTag && !child->isNull())
 | 
			
		||||
            return child;
 | 
			
		||||
    }
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
OTMLNodePtr OTMLNode::get(int childIndex) const
 | 
			
		||||
OTMLNodePtr OTMLNode::getIndex(int childIndex) const
 | 
			
		||||
{
 | 
			
		||||
    if(childIndex < size() && childIndex >= 0)
 | 
			
		||||
        return m_childNodes[childIndex];
 | 
			
		||||
        return m_children[childIndex];
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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(shared_from_this(), fw::mkstr("child node with tag '", childTag, "' not found"));
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
OTMLNodePtr OTMLNode::atIndex(int childIndex)
 | 
			
		||||
{
 | 
			
		||||
    if(childIndex >= size() || childIndex < 0)
 | 
			
		||||
        throw OTMLException(shared_from_this(), fw::mkstr("child node with index '", childIndex, "' not found"));
 | 
			
		||||
    return m_children[childIndex];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OTMLNode::addChild(const OTMLNodePtr& newChild)
 | 
			
		||||
{
 | 
			
		||||
    // replace is needed when the tag is marked as unique
 | 
			
		||||
    if(newChild->hasTag()) {
 | 
			
		||||
        for(OTMLNodePtr node : m_childNodes) {
 | 
			
		||||
        for(const OTMLNodePtr& node : m_children) {
 | 
			
		||||
            if(node->tag() == newChild->tag() && (node->isUnique() || newChild->isUnique())) {
 | 
			
		||||
                newChild->setUnique();
 | 
			
		||||
                newChild->setUnique(true);
 | 
			
		||||
                replaceChild(node, newChild);
 | 
			
		||||
 | 
			
		||||
                // remove any other child with the same tag
 | 
			
		||||
                auto it = m_childNodes.begin();
 | 
			
		||||
                while(it != m_childNodes.end()) {
 | 
			
		||||
                auto it = m_children.begin();
 | 
			
		||||
                while(it != m_children.end()) {
 | 
			
		||||
                    OTMLNodePtr node = (*it);
 | 
			
		||||
                    if(node != newChild && node->tag() == newChild->tag()) {
 | 
			
		||||
                        node->setParent(nullptr);
 | 
			
		||||
                        it = m_childNodes.erase(it);
 | 
			
		||||
                        it = m_children.erase(it);
 | 
			
		||||
                    } else
 | 
			
		||||
                        ++it;
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -161,60 +90,67 @@ void OTMLNode::addChild(const OTMLNodePtr& newChild)
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_childNodes.push_back(newChild);
 | 
			
		||||
    m_children.push_back(newChild);
 | 
			
		||||
    newChild->setParent(shared_from_this());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool OTMLNode::removeChild(const OTMLNodePtr& oldChild)
 | 
			
		||||
{
 | 
			
		||||
    for(auto it = m_childNodes.begin(); it != m_childNodes.end(); ++it) {
 | 
			
		||||
        if((*it) == oldChild) {
 | 
			
		||||
            m_childNodes.erase(it);
 | 
			
		||||
            oldChild->setParent(nullptr);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    auto it = std::find(m_children.begin(), m_children.end(), oldChild);
 | 
			
		||||
    if(it != m_children.end()) {
 | 
			
		||||
        m_children.erase(it);
 | 
			
		||||
        oldChild->setParent(nullptr);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool OTMLNode::replaceChild(const OTMLNodePtr& oldChild, const OTMLNodePtr& newChild)
 | 
			
		||||
{
 | 
			
		||||
    for(auto it = m_childNodes.begin(); it != m_childNodes.end(); ++it) {
 | 
			
		||||
        if((*it) == oldChild) {
 | 
			
		||||
            oldChild->setParent(nullptr);
 | 
			
		||||
            newChild->setParent(shared_from_this());
 | 
			
		||||
            it = m_childNodes.erase(it);
 | 
			
		||||
            m_childNodes.insert(it, newChild);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    auto it = std::find(m_children.begin(), m_children.end(), oldChild);
 | 
			
		||||
    if(it != m_children.end()) {
 | 
			
		||||
        oldChild->setParent(nullptr);
 | 
			
		||||
        newChild->setParent(shared_from_this());
 | 
			
		||||
        it = m_children.erase(it);
 | 
			
		||||
        m_children.insert(it, newChild);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OTMLNode::clear()
 | 
			
		||||
{
 | 
			
		||||
    m_childNodes.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OTMLNode::merge(const OTMLNodePtr& node)
 | 
			
		||||
{
 | 
			
		||||
    for(const OTMLNodePtr& child : node->childNodes()) {
 | 
			
		||||
        OTMLNodePtr newNode(new OTMLNode);
 | 
			
		||||
        newNode->setUnique(child->isUnique());
 | 
			
		||||
        newNode->setTag(child->tag());
 | 
			
		||||
        newNode->setValue(child->value());
 | 
			
		||||
        addChild(newNode);
 | 
			
		||||
        newNode->merge(child);
 | 
			
		||||
    }
 | 
			
		||||
    for(const OTMLNodePtr& child : node->m_children)
 | 
			
		||||
        addChild(child->clone());
 | 
			
		||||
    setTag(node->tag());
 | 
			
		||||
    setSource(node->source());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OTMLNode::clear()
 | 
			
		||||
{
 | 
			
		||||
    for(const OTMLNodePtr& child : m_children)
 | 
			
		||||
        child->setParent(nullptr);
 | 
			
		||||
    m_children.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
OTMLNodeList OTMLNode::children() const
 | 
			
		||||
{
 | 
			
		||||
    OTMLNodeList children;
 | 
			
		||||
    for(const OTMLNodePtr& child : m_children)
 | 
			
		||||
        if(!child->isNull())
 | 
			
		||||
            children.push_back(child);
 | 
			
		||||
    return children;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
OTMLNodePtr OTMLNode::clone() const
 | 
			
		||||
{
 | 
			
		||||
    OTMLNodePtr myClone(new OTMLNode);
 | 
			
		||||
    myClone->setTag(tag());
 | 
			
		||||
    myClone->setValue(value());
 | 
			
		||||
    myClone->setUnique(isUnique());
 | 
			
		||||
    for(OTMLNodePtr child : childNodes())
 | 
			
		||||
    myClone->setTag(m_tag);
 | 
			
		||||
    myClone->setValue(m_value);
 | 
			
		||||
    myClone->setUnique(m_unique);
 | 
			
		||||
    myClone->setNull(m_null);
 | 
			
		||||
    myClone->setSource(m_source);
 | 
			
		||||
    for(const OTMLNodePtr& child : m_children)
 | 
			
		||||
        myClone->addChild(child->clone());
 | 
			
		||||
    return myClone;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -223,3 +159,4 @@ std::string OTMLNode::emit()
 | 
			
		|||
{
 | 
			
		||||
    return OTMLEmitter::emitNode(shared_from_this(), 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,214 +2,138 @@
 | 
			
		|||
#define OTMLNODE_H
 | 
			
		||||
 | 
			
		||||
#include "declarations.h"
 | 
			
		||||
#include "otmlexception.h"
 | 
			
		||||
 | 
			
		||||
class OTMLNode : public std::enable_shared_from_this<OTMLNode>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    OTMLNode();
 | 
			
		||||
    virtual ~OTMLNode() { }
 | 
			
		||||
 | 
			
		||||
    std::string value() const;
 | 
			
		||||
    std::string tag() const;
 | 
			
		||||
    int size() const;
 | 
			
		||||
    OTMLNodePtr parent() const;
 | 
			
		||||
    const OTMLNodeList& childNodes() const;
 | 
			
		||||
    std::string source() const;
 | 
			
		||||
    static OTMLNodePtr create(std::string tag = fw::empty_string, bool unique = false);
 | 
			
		||||
    static OTMLNodePtr create(std::string tag, std::string value);
 | 
			
		||||
 | 
			
		||||
    bool hasTag() const;
 | 
			
		||||
    bool hasValue() const;
 | 
			
		||||
    bool hasChildNodes() const;
 | 
			
		||||
    bool hasChild(const std::string& childTag) const;
 | 
			
		||||
    bool hasChild(int index) const;
 | 
			
		||||
    bool isUnique() const;
 | 
			
		||||
    std::string tag() const { return m_tag; }
 | 
			
		||||
    int size() const { return m_children.size(); }
 | 
			
		||||
    OTMLNodePtr parent() const { return m_parent.lock(); }
 | 
			
		||||
    std::string source() const { return m_source; }
 | 
			
		||||
 | 
			
		||||
    void setTag(std::string tag);
 | 
			
		||||
    void setValue(const std::string& value);
 | 
			
		||||
    void setParent(const OTMLNodePtr& parent);
 | 
			
		||||
    void setUnique(bool unique = true);
 | 
			
		||||
    void setSource(const std::string& source);
 | 
			
		||||
    bool isUnique() const { return m_unique; }
 | 
			
		||||
    bool isNull() const { return m_null; }
 | 
			
		||||
 | 
			
		||||
    /// Same as get but if the child node doesn't exist throws an OTMLException
 | 
			
		||||
    OTMLNodePtr at(const std::string& childTag);
 | 
			
		||||
    OTMLNodePtr at(int childIndex);
 | 
			
		||||
    bool hasTag() const { return !m_tag.empty(); }
 | 
			
		||||
    bool hasValue() const { return !m_value.empty(); }
 | 
			
		||||
    bool hasChildren() const;
 | 
			
		||||
    bool hasChildAt(const std::string& childTag) { return !!get(childTag); }
 | 
			
		||||
    bool hasChildAtIndex(int childIndex) { return !!getIndex(childIndex); }
 | 
			
		||||
 | 
			
		||||
    void setTag(std::string tag) { m_tag = tag; }
 | 
			
		||||
    void setValue(const std::string& value) { m_value = value; }
 | 
			
		||||
    void setNull(bool null) { m_null = null; }
 | 
			
		||||
    void setUnique(bool unique) { m_unique = unique; }
 | 
			
		||||
    void setParent(const OTMLNodePtr& parent) { m_parent = parent; }
 | 
			
		||||
    void setSource(const std::string& source) { m_source = source; }
 | 
			
		||||
 | 
			
		||||
    /// Get a child node, if doesn't exists returns nullptr
 | 
			
		||||
    OTMLNodePtr get(const std::string& childTag) const;
 | 
			
		||||
    OTMLNodePtr get(int childIndex) const;
 | 
			
		||||
    OTMLNodePtr getIndex(int childIndex) const;
 | 
			
		||||
 | 
			
		||||
    OTMLNodePtr at(const std::string& childTag);
 | 
			
		||||
    OTMLNodePtr atIndex(int childIndex);
 | 
			
		||||
 | 
			
		||||
    void addChild(const OTMLNodePtr& newChild);
 | 
			
		||||
    bool removeChild(const OTMLNodePtr& oldChild);
 | 
			
		||||
    bool replaceChild(const OTMLNodePtr& oldChild, const OTMLNodePtr& newChild);
 | 
			
		||||
 | 
			
		||||
    /// Remove all children
 | 
			
		||||
    void merge(const OTMLNodePtr& node);
 | 
			
		||||
    void clear();
 | 
			
		||||
 | 
			
		||||
    /// Recursively copy children from another node to this node
 | 
			
		||||
    void merge(const OTMLNodePtr& node);
 | 
			
		||||
 | 
			
		||||
    /// Recursively clone this node into a new one
 | 
			
		||||
    OTMLNodeList children() const;
 | 
			
		||||
    OTMLNodePtr clone() const;
 | 
			
		||||
 | 
			
		||||
    /// Emits this node to a std::string
 | 
			
		||||
    virtual std::string emit();
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    T read();
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    T read(const T& def);
 | 
			
		||||
 | 
			
		||||
    template<typename T, typename U>
 | 
			
		||||
    T readAt(const U& childIdentifier);
 | 
			
		||||
 | 
			
		||||
    template<typename T, typename U>
 | 
			
		||||
    T readAt(const U& childIdentifier, const T& def);
 | 
			
		||||
    template<typename T = std::string>
 | 
			
		||||
    T value();
 | 
			
		||||
    template<typename T = std::string>
 | 
			
		||||
    T valueAt(const std::string& childTag);
 | 
			
		||||
    template<typename T = std::string>
 | 
			
		||||
    T valueAtIndex(int childIndex);
 | 
			
		||||
    template<typename T = std::string>
 | 
			
		||||
    T valueAt(const std::string& childTag, const T& def);
 | 
			
		||||
    template<typename T = std::string>
 | 
			
		||||
    T valueAtIndex(int childIndex, const T& def);
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    void write(const T& v);
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    void writeAt(const std::string& childTag, const T& v);
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    void writeIn(const T& v);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    virtual std::string emit();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    OTMLNode() : m_unique(false), m_null(false) { }
 | 
			
		||||
 | 
			
		||||
    OTMLNodeList m_children;
 | 
			
		||||
    OTMLNodeWeakPtr m_parent;
 | 
			
		||||
    std::string m_tag;
 | 
			
		||||
    std::string m_value;
 | 
			
		||||
    std::string m_source;
 | 
			
		||||
    bool m_unique;
 | 
			
		||||
    OTMLNodeList m_childNodes;
 | 
			
		||||
    OTMLNodeWeakPtr m_parent;
 | 
			
		||||
    bool m_null;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// templates for reading values
 | 
			
		||||
#include "otmlexception.h"
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
T OTMLNode::read() {
 | 
			
		||||
    T v;
 | 
			
		||||
    if(!from_otmlnode(shared_from_this(), v))
 | 
			
		||||
        throw OTMLException(shared_from_this(),
 | 
			
		||||
                            fw::mkstr("failed to cast node value to type '", fw::demangle_type<T>(), "'"));
 | 
			
		||||
    return v;
 | 
			
		||||
T OTMLNode::value() {
 | 
			
		||||
    T ret;
 | 
			
		||||
    if(!fw::cast(m_value, ret))
 | 
			
		||||
        throw OTMLException(shared_from_this(), fw::mkstr("failed to cast node value to type '", fw::demangle_type<T>(), "'"));
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
T OTMLNode::read(const T& def) {
 | 
			
		||||
    if(hasValue())
 | 
			
		||||
        return read<T>();
 | 
			
		||||
T OTMLNode::valueAt(const std::string& childTag) {
 | 
			
		||||
    OTMLNodePtr node = at(childTag);
 | 
			
		||||
    return node->value<T>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
T OTMLNode::valueAtIndex(int childIndex) {
 | 
			
		||||
    OTMLNodePtr node = atIndex(childIndex);
 | 
			
		||||
    return node->value<T>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
T OTMLNode::valueAt(const std::string& childTag, const T& def) {
 | 
			
		||||
    if(OTMLNodePtr node = get(childTag))
 | 
			
		||||
        if(!node->isNull())
 | 
			
		||||
            return node->value<T>();
 | 
			
		||||
    return def;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T, typename U>
 | 
			
		||||
T OTMLNode::readAt(const U& childIdentifier) {
 | 
			
		||||
    OTMLNodePtr child = at(childIdentifier);
 | 
			
		||||
    return child->read<T>();
 | 
			
		||||
template<typename T>
 | 
			
		||||
T OTMLNode::valueAtIndex(int childIndex, const T& def) {
 | 
			
		||||
    if(OTMLNodePtr node = getIndex(childIndex))
 | 
			
		||||
        return node->value<T>();
 | 
			
		||||
    return def;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T, typename U>
 | 
			
		||||
T OTMLNode::readAt(const U& childIdentifier, const T& def) {
 | 
			
		||||
    OTMLNodePtr child = get(childIdentifier);
 | 
			
		||||
    if(!child)
 | 
			
		||||
        return def;
 | 
			
		||||
    return child->read<T>(def);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// templates for writing values
 | 
			
		||||
template<typename T>
 | 
			
		||||
void OTMLNode::write(const T& v) {
 | 
			
		||||
    to_otmlnode(shared_from_this(), v);
 | 
			
		||||
    m_value = fw::safe_cast<std::string>(v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
void OTMLNode::writeAt(const std::string& childTag, const T& v) {
 | 
			
		||||
    OTMLNodePtr child = get(childTag);
 | 
			
		||||
    bool created = false;
 | 
			
		||||
    if(!child) {
 | 
			
		||||
        child = OTMLNodePtr(new OTMLNode);
 | 
			
		||||
        child->setTag(childTag);
 | 
			
		||||
        child->setUnique();
 | 
			
		||||
        created = true;
 | 
			
		||||
    }
 | 
			
		||||
    child->write<T>(v);
 | 
			
		||||
    if(created)
 | 
			
		||||
        addChild(child);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
void OTMLNode::writeIn(const T& v) {
 | 
			
		||||
    OTMLNodePtr child = OTMLNodePtr(new OTMLNode);
 | 
			
		||||
    OTMLNodePtr child = OTMLNode::create(childTag);
 | 
			
		||||
    child->write<T>(v);
 | 
			
		||||
    addChild(child);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// templates for casting a node to another type
 | 
			
		||||
template<typename T>
 | 
			
		||||
bool from_otmlnode(OTMLNodePtr node, T& v) {
 | 
			
		||||
    return fw::cast(node->value(), v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
bool from_otmlnode(OTMLNodePtr node, std::vector<T>& v) {
 | 
			
		||||
    v.resize(node->size());
 | 
			
		||||
    for(unsigned i=0;i<node->size();++i)
 | 
			
		||||
        v[i] = node->readAt<T>(i);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
bool from_otmlnode(OTMLNodePtr node, std::list<T>& v) {
 | 
			
		||||
    for(unsigned i=0;i<node->size();++i)
 | 
			
		||||
        v.push_back(node->readAt<T>(i));
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename K, typename T>
 | 
			
		||||
bool from_otmlnode(OTMLNodePtr node, std::map<K, T>& m) {
 | 
			
		||||
    for(int i=0;i<node->size();++i) {
 | 
			
		||||
        K k;
 | 
			
		||||
        if(!fw::cast(node->at(i)->tag(), k))
 | 
			
		||||
            return false;
 | 
			
		||||
        m[k] = node->at(i)->read<T>();
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// templates for casting a type to a node
 | 
			
		||||
template<typename T>
 | 
			
		||||
void to_otmlnode(OTMLNodePtr node, const T& v) {
 | 
			
		||||
    node->setValue(fw::unsafe_cast<std::string>(v));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
void to_otmlnode(OTMLNodePtr node, const std::vector<T>& v) {
 | 
			
		||||
    for(unsigned i=0;i<v.size();++i) {
 | 
			
		||||
        OTMLNodePtr newNode(new OTMLNode);
 | 
			
		||||
        newNode->write(v[i]);
 | 
			
		||||
        node->addChild(newNode);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
void to_otmlnode(OTMLNodePtr node, const std::list<T>& v) {
 | 
			
		||||
    for(unsigned i=0;i<v.size();++i) {
 | 
			
		||||
        OTMLNodePtr newNode(new OTMLNode);
 | 
			
		||||
        newNode->write(v[i]);
 | 
			
		||||
        node->addChild(newNode);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename K, typename T>
 | 
			
		||||
void to_otmlnode(OTMLNodePtr node, const std::map<K, T>& m) {
 | 
			
		||||
    for(auto it = m.begin(); it != m.end(); ++it) {
 | 
			
		||||
        std::string k = fw::unsafe_cast<std::string>(it->first);
 | 
			
		||||
        OTMLNodePtr newNode(new OTMLNode);
 | 
			
		||||
        newNode->setTag(k);
 | 
			
		||||
        newNode->setUnique();
 | 
			
		||||
        newNode->write(it->second);
 | 
			
		||||
        node->addChild(newNode);
 | 
			
		||||
    }
 | 
			
		||||
void OTMLNode::writeIn(const T& v) {
 | 
			
		||||
    OTMLNodePtr child = OTMLNode::create();
 | 
			
		||||
    child->write<T>(v);
 | 
			
		||||
    addChild(child);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
#include "otmlparser.h"
 | 
			
		||||
#include "otmldocument.h"
 | 
			
		||||
#include "otmlexception.h"
 | 
			
		||||
 | 
			
		||||
OTMLParser::OTMLParser(OTMLDocumentPtr doc, std::istream& in) :
 | 
			
		||||
    currentDepth(0), currentLine(0),
 | 
			
		||||
| 
						 | 
				
			
			@ -52,6 +53,9 @@ void OTMLParser::parseLine(std::string line)
 | 
			
		|||
{
 | 
			
		||||
    int depth = getLineDepth(line);
 | 
			
		||||
 | 
			
		||||
    if(depth == -1)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    // remove line sides spaces
 | 
			
		||||
    boost::trim(line);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -87,6 +91,7 @@ void OTMLParser::parseNode(const std::string& data)
 | 
			
		|||
    std::string tag;
 | 
			
		||||
    std::string value;
 | 
			
		||||
    std::size_t dotsPos = data.find_first_of(':');
 | 
			
		||||
    int nodeLine = currentLine;
 | 
			
		||||
 | 
			
		||||
    // node that has no tag and may have a value
 | 
			
		||||
    if(!data.empty() && data[0] == '-') {
 | 
			
		||||
| 
						 | 
				
			
			@ -150,11 +155,18 @@ void OTMLParser::parseNode(const std::string& data)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // create the node
 | 
			
		||||
    OTMLNodePtr node(new OTMLNode);
 | 
			
		||||
    OTMLNodePtr node = OTMLNode::create(tag);
 | 
			
		||||
 | 
			
		||||
    node->setUnique(dotsPos != std::string::npos);
 | 
			
		||||
    node->setTag(tag);
 | 
			
		||||
    node->setValue(value);
 | 
			
		||||
    node->setSource(doc->source() + ":" + fw::safe_cast<std::string>(currentLine));
 | 
			
		||||
    node->setSource(doc->source() + ":" + fw::unsafe_cast<std::string>(nodeLine));
 | 
			
		||||
 | 
			
		||||
    // ~ is considered the null value
 | 
			
		||||
    if(value == "~")
 | 
			
		||||
        node->setNull(true);
 | 
			
		||||
    else
 | 
			
		||||
        node->setValue(value);
 | 
			
		||||
 | 
			
		||||
    currentParent->addChild(node);
 | 
			
		||||
    previousNode = node;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,10 +37,10 @@ void UIButton::loadStyleFromOTML(const OTMLNodePtr& styleNode)
 | 
			
		|||
    if(OTMLNodePtr node = styleNode->get("state.down"))
 | 
			
		||||
        loadStateStyle(m_statesStyle[ButtonDown], node);
 | 
			
		||||
 | 
			
		||||
    m_text = styleNode->readAt("text", fw::empty_string);
 | 
			
		||||
    m_text = styleNode->valueAt("text", fw::empty_string);
 | 
			
		||||
 | 
			
		||||
    if(OTMLNodePtr node = styleNode->get("onClick")) {
 | 
			
		||||
        g_lua.loadFunction(node->read<std::string>(), "@" + node->source() + "[" + node->tag() + "]");
 | 
			
		||||
        g_lua.loadFunction(node->value<std::string>(), "@" + node->source() + "[" + node->tag() + "]");
 | 
			
		||||
        luaSetField("onClick");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -51,9 +51,9 @@ void UIButton::loadStateStyle(ButtonStateStyle& stateStyle, const OTMLNodePtr& s
 | 
			
		|||
        stateStyle.image = BorderImage::loadFromOTML(node);
 | 
			
		||||
    if(OTMLNodePtr node = stateStyleNode->get("image"))
 | 
			
		||||
        stateStyle.image = Image::loadFromOTML(node);
 | 
			
		||||
    stateStyle.textTranslate = stateStyleNode->readAt("text-translate", Point());
 | 
			
		||||
    stateStyle.color = stateStyleNode->readAt("font-color", m_fontColor);
 | 
			
		||||
    stateStyle.color = stateStyleNode->readAt("color", m_color);
 | 
			
		||||
    stateStyle.textTranslate = stateStyleNode->valueAt("text-translate", Point());
 | 
			
		||||
    stateStyle.color = stateStyleNode->valueAt("font-color", m_fontColor);
 | 
			
		||||
    stateStyle.color = stateStyleNode->valueAt("color", m_color);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UIButton::render()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,10 +18,10 @@ void UILabel::loadStyleFromOTML(const OTMLNodePtr& styleNode)
 | 
			
		|||
{
 | 
			
		||||
    UIWidget::loadStyleFromOTML(styleNode);
 | 
			
		||||
 | 
			
		||||
    m_text = styleNode->readAt("text", m_text);
 | 
			
		||||
    m_text = styleNode->valueAt("text", m_text);
 | 
			
		||||
 | 
			
		||||
    if(styleNode->hasChild("align"))
 | 
			
		||||
        m_align = fw::translateAlignment(styleNode->readAt<std::string>("align"));
 | 
			
		||||
    if(styleNode->hasChildAt("align"))
 | 
			
		||||
        m_align = fw::translateAlignment(styleNode->valueAt("align"));
 | 
			
		||||
 | 
			
		||||
    // auto resize if no size supplied
 | 
			
		||||
    if(!m_text.empty() && !getGeometry().isValid())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,7 +25,7 @@ void UILineEdit::loadStyleFromOTML(const OTMLNodePtr& styleNode)
 | 
			
		|||
{
 | 
			
		||||
    UIWidget::loadStyleFromOTML(styleNode);
 | 
			
		||||
 | 
			
		||||
    setText(styleNode->readAt("text", getText()));
 | 
			
		||||
    setText(styleNode->valueAt("text", getText()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UILineEdit::render()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -93,7 +93,7 @@ bool UIManager::importStyles(const std::string& file)
 | 
			
		|||
    try {
 | 
			
		||||
        OTMLDocumentPtr doc = OTMLDocument::parse(file);
 | 
			
		||||
 | 
			
		||||
        for(const OTMLNodePtr& styleNode : doc->childNodes())
 | 
			
		||||
        for(const OTMLNodePtr& styleNode : doc->children())
 | 
			
		||||
            importStyleFromOTML(styleNode);
 | 
			
		||||
        return true;
 | 
			
		||||
    } catch(std::exception& e) {
 | 
			
		||||
| 
						 | 
				
			
			@ -129,14 +129,14 @@ void UIManager::importStyleFromOTML(const OTMLNodePtr& styleNode)
 | 
			
		|||
OTMLNodePtr UIManager::getStyle(const std::string& styleName)
 | 
			
		||||
{
 | 
			
		||||
    if(boost::starts_with(styleName, "UI")) {
 | 
			
		||||
        OTMLNodePtr node(new OTMLNode());
 | 
			
		||||
        OTMLNodePtr node = OTMLNode::create();
 | 
			
		||||
        node->writeAt("__widgetType", styleName);
 | 
			
		||||
        return node;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto it = m_styles.find(styleName);
 | 
			
		||||
    if(it == m_styles.end())
 | 
			
		||||
        throw std::logic_error(fw::mkstr("style '", styleName, "' is not a defined style"));
 | 
			
		||||
        throw std::runtime_error(fw::mkstr("style '", styleName, "' is not a defined style"));
 | 
			
		||||
    return m_styles[styleName];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +145,7 @@ UIWidgetPtr UIManager::loadUI(const std::string& file)
 | 
			
		|||
    try {
 | 
			
		||||
        OTMLDocumentPtr doc = OTMLDocument::parse(file);
 | 
			
		||||
        UIWidgetPtr widget;
 | 
			
		||||
        for(const OTMLNodePtr& node : doc->childNodes()) {
 | 
			
		||||
        for(const OTMLNodePtr& node : doc->children()) {
 | 
			
		||||
            std::string tag = node->tag();
 | 
			
		||||
 | 
			
		||||
            // import styles in these files too
 | 
			
		||||
| 
						 | 
				
			
			@ -153,7 +153,7 @@ UIWidgetPtr UIManager::loadUI(const std::string& file)
 | 
			
		|||
                importStyleFromOTML(node);
 | 
			
		||||
            else {
 | 
			
		||||
                if(widget)
 | 
			
		||||
                    throw OTMLException(node, "cannot have multiple main widgets in .otui files");
 | 
			
		||||
                    throw std::runtime_error("cannot have multiple main widgets in .otui files");
 | 
			
		||||
                widget = loadWidgetFromOTML(node);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +172,7 @@ UIWidgetPtr UIManager::loadWidgetFromOTML(const OTMLNodePtr& widgetNode)
 | 
			
		|||
    OTMLNodePtr styleNode = getStyle(widgetNode->tag())->clone();
 | 
			
		||||
    styleNode->merge(widgetNode);
 | 
			
		||||
 | 
			
		||||
    std::string widgetType = styleNode->readAt<std::string>("__widgetType");
 | 
			
		||||
    std::string widgetType = styleNode->valueAt("__widgetType");
 | 
			
		||||
 | 
			
		||||
    UIWidgetPtr widget;
 | 
			
		||||
    if(widgetType == "UIWidget")
 | 
			
		||||
| 
						 | 
				
			
			@ -191,7 +191,7 @@ UIWidgetPtr UIManager::loadWidgetFromOTML(const OTMLNodePtr& widgetNode)
 | 
			
		|||
    widget->loadStyleFromOTML(styleNode);
 | 
			
		||||
    widget->updateGeometry();
 | 
			
		||||
 | 
			
		||||
    for(const OTMLNodePtr& childNode : widgetNode->childNodes()) {
 | 
			
		||||
    for(const OTMLNodePtr& childNode : widgetNode->children()) {
 | 
			
		||||
        if(!childNode->isUnique())
 | 
			
		||||
            widget->addChild(loadWidgetFromOTML(childNode));
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -103,7 +103,7 @@ void UIWidget::loadStyleFromOTML(const OTMLNodePtr& styleNode)
 | 
			
		|||
    assert(!m_destroyed);
 | 
			
		||||
 | 
			
		||||
    // load styles used by all widgets
 | 
			
		||||
    for(const OTMLNodePtr& node : styleNode->childNodes()) {
 | 
			
		||||
    for(const OTMLNodePtr& node : styleNode->children()) {
 | 
			
		||||
        // id
 | 
			
		||||
        if(node->tag() == "id") {
 | 
			
		||||
            setId(node->value());
 | 
			
		||||
| 
						 | 
				
			
			@ -121,48 +121,48 @@ void UIWidget::loadStyleFromOTML(const OTMLNodePtr& styleNode)
 | 
			
		|||
        }
 | 
			
		||||
        // font color
 | 
			
		||||
        else if(node->tag() == "font-color") {
 | 
			
		||||
            setFontColor(node->read<Color>());
 | 
			
		||||
            setFontColor(node->value<Color>());
 | 
			
		||||
        }
 | 
			
		||||
        // color
 | 
			
		||||
        else if(node->tag() == "color") {
 | 
			
		||||
            setColor(node->read<Color>());
 | 
			
		||||
            setColor(node->value<Color>());
 | 
			
		||||
        }
 | 
			
		||||
        // opacity
 | 
			
		||||
        else if(node->tag() == "opacity") {
 | 
			
		||||
            setOpacity(node->read<int>());
 | 
			
		||||
            setOpacity(node->value<int>());
 | 
			
		||||
        }
 | 
			
		||||
        // size
 | 
			
		||||
        else if(node->tag() == "size") {
 | 
			
		||||
            resize(node->read<Size>());
 | 
			
		||||
            resize(node->value<Size>());
 | 
			
		||||
        }
 | 
			
		||||
        else if(node->tag() == "width") {
 | 
			
		||||
            setWidth(node->read<int>());
 | 
			
		||||
            setWidth(node->value<int>());
 | 
			
		||||
        }
 | 
			
		||||
        else if(node->tag() == "height") {
 | 
			
		||||
            setHeight(node->read<int>());
 | 
			
		||||
            setHeight(node->value<int>());
 | 
			
		||||
        }
 | 
			
		||||
        // position
 | 
			
		||||
        else if(node->tag() == "position") {
 | 
			
		||||
            move(node->read<Point>());
 | 
			
		||||
            move(node->value<Point>());
 | 
			
		||||
        }
 | 
			
		||||
        else if(node->tag() == "x") {
 | 
			
		||||
            setX(node->read<int>());
 | 
			
		||||
            setX(node->value<int>());
 | 
			
		||||
        }
 | 
			
		||||
        else if(node->tag() == "y") {
 | 
			
		||||
            setY(node->read<int>());
 | 
			
		||||
            setY(node->value<int>());
 | 
			
		||||
        }
 | 
			
		||||
        // margins
 | 
			
		||||
        else if(node->tag() == "margin.left") {
 | 
			
		||||
            setMarginLeft(node->read<int>());
 | 
			
		||||
            setMarginLeft(node->value<int>());
 | 
			
		||||
        }
 | 
			
		||||
        else if(node->tag() == "margin.right") {
 | 
			
		||||
            setMarginRight(node->read<int>());
 | 
			
		||||
            setMarginRight(node->value<int>());
 | 
			
		||||
        }
 | 
			
		||||
        else if(node->tag() == "margin.top") {
 | 
			
		||||
            setMarginTop(node->read<int>());
 | 
			
		||||
            setMarginTop(node->value<int>());
 | 
			
		||||
        }
 | 
			
		||||
        else if(node->tag() == "margin.bottom") {
 | 
			
		||||
            setMarginBottom(node->read<int>());
 | 
			
		||||
            setMarginBottom(node->value<int>());
 | 
			
		||||
        }
 | 
			
		||||
        // anchors
 | 
			
		||||
        else if(boost::starts_with(node->tag(), "anchors.")) {
 | 
			
		||||
| 
						 | 
				
			
			@ -193,7 +193,7 @@ void UIWidget::loadStyleFromOTML(const OTMLNodePtr& styleNode)
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if(node->tag() == "onLoad") {
 | 
			
		||||
            g_lua.loadFunction(node->read<std::string>(), "@" + node->source() + "[" + node->tag() + "]");
 | 
			
		||||
            g_lua.loadFunction(node->value<std::string>(), "@" + node->source() + "[" + node->tag() + "]");
 | 
			
		||||
            luaSetField("onLoad");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -437,8 +437,12 @@ UIWidgetPtr UIWidget::recursiveGetChildById(const std::string& childId)
 | 
			
		|||
        for(const UIWidgetPtr& child : m_children) {
 | 
			
		||||
            if(child->getId() == childId)
 | 
			
		||||
                return child;
 | 
			
		||||
            else
 | 
			
		||||
                return child->recursiveGetChildById(childId);
 | 
			
		||||
        }
 | 
			
		||||
        for(const UIWidgetPtr& child : m_children) {
 | 
			
		||||
            if(UIWidgetPtr subChild = child->recursiveGetChildById(childId)) {
 | 
			
		||||
                if(subChild->getId() == childId)
 | 
			
		||||
                    return subChild;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return nullptr;
 | 
			
		||||
| 
						 | 
				
			
			@ -522,6 +526,9 @@ void UIWidget::addChild(const UIWidgetPtr& childToAdd)
 | 
			
		|||
{
 | 
			
		||||
    assert(!m_destroyed);
 | 
			
		||||
 | 
			
		||||
    if(!childToAdd)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    assert(!hasChild(childToAdd));
 | 
			
		||||
    m_children.push_back(childToAdd);
 | 
			
		||||
    childToAdd->setParent(asUIWidget());
 | 
			
		||||
| 
						 | 
				
			
			@ -538,6 +545,9 @@ void UIWidget::removeChild(const UIWidgetPtr& childToRemove)
 | 
			
		|||
{
 | 
			
		||||
    assert(!m_destroyed);
 | 
			
		||||
 | 
			
		||||
    if(!childToRemove)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    // defocus if needed
 | 
			
		||||
    if(m_focusedChild == childToRemove)
 | 
			
		||||
        focusChild(nullptr, ActiveFocusReason);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,9 +23,9 @@ void UIWindow::loadStyleFromOTML(const OTMLNodePtr& styleNode)
 | 
			
		|||
    if(OTMLNodePtr headNode = styleNode->get("head")) {
 | 
			
		||||
        if(OTMLNodePtr node = headNode->get("border-image"))
 | 
			
		||||
            m_headImage = BorderImage::loadFromOTML(node);
 | 
			
		||||
        m_headHeight = headNode->readAt("height", m_headImage->getDefaultSize().height());
 | 
			
		||||
        m_headMargin = headNode->readAt("margin", 0);
 | 
			
		||||
        m_titleAlign = fw::translateAlignment(headNode->readAt("text align", std::string("center")));
 | 
			
		||||
        m_headHeight = headNode->valueAt("height", m_headImage->getDefaultSize().height());
 | 
			
		||||
        m_headMargin = headNode->valueAt("margin", 0);
 | 
			
		||||
        m_titleAlign = fw::translateAlignment(headNode->valueAt("text align", std::string("center")));
 | 
			
		||||
    } else {
 | 
			
		||||
        m_headHeight = 0;
 | 
			
		||||
        m_headMargin = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -37,7 +37,7 @@ void UIWindow::loadStyleFromOTML(const OTMLNodePtr& styleNode)
 | 
			
		|||
            m_bodyImage = BorderImage::loadFromOTML(node);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_title = styleNode->readAt("title", fw::empty_string);
 | 
			
		||||
    m_title = styleNode->valueAt("title", fw::empty_string);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UIWindow::render()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ typedef uint32 RGBA;
 | 
			
		|||
class Color
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Color() : color(0) { }
 | 
			
		||||
    Color() : color(0xFFFFFFFF) { }
 | 
			
		||||
    Color(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) : color(((a & 0xff)<<24) | ((b & 0xff)<<16) | ((g & 0xff)<<8) | (r & 0xff)) { }
 | 
			
		||||
    Color(const Color& other) : color(other.color) { }
 | 
			
		||||
    Color(RGBA rgba) : color(rgba) { }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,11 +4,11 @@
 | 
			
		|||
 | 
			
		||||
DatManager g_dat;
 | 
			
		||||
 | 
			
		||||
bool DatManager::load(const std::string& filename)
 | 
			
		||||
bool DatManager::load(const std::string& file)
 | 
			
		||||
{
 | 
			
		||||
    try {
 | 
			
		||||
        std::stringstream fin;
 | 
			
		||||
        g_resources.loadFile(filename, fin);
 | 
			
		||||
        g_resources.loadFile(file, fin);
 | 
			
		||||
 | 
			
		||||
        m_signature = fw::getu32(fin);
 | 
			
		||||
        int numItems = fw::getu16(fin);
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ bool DatManager::load(const std::string& filename)
 | 
			
		|||
 | 
			
		||||
        return true;
 | 
			
		||||
    } catch(std::exception& e) {
 | 
			
		||||
        logError(e.what());
 | 
			
		||||
        logError("ERROR: failed to load dat from '", file, "': ", e.what());
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -87,11 +87,9 @@ void DatManager::parseThingAttributes(std::stringstream& fin, ThingAttributes& t
 | 
			
		|||
 | 
			
		||||
void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes& thingAttributes, uint8 opt)
 | 
			
		||||
{
 | 
			
		||||
    uint8 read_byte;
 | 
			
		||||
    uint16 read_short;
 | 
			
		||||
    switch(opt) {
 | 
			
		||||
        case 0x00: // Ground tile
 | 
			
		||||
            fin.read((char*)&thingAttributes.speed, 2);
 | 
			
		||||
            thingAttributes.speed = fw::getu16(fin);
 | 
			
		||||
            thingAttributes.group = THING_GROUP_GROUND;
 | 
			
		||||
            break;
 | 
			
		||||
        case 0x01: // All OnTop
 | 
			
		||||
| 
						 | 
				
			
			@ -120,16 +118,16 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes
 | 
			
		|||
        case 0x08: // Writtable
 | 
			
		||||
            thingAttributes.group = THING_GROUP_WRITEABLE;
 | 
			
		||||
            thingAttributes.readable = true;
 | 
			
		||||
            fin.read((char*)&thingAttributes.subParam07, 2);
 | 
			
		||||
            thingAttributes.subParam08 = fw::getu16(fin);
 | 
			
		||||
            break;
 | 
			
		||||
        case 0x09: // Writtable once
 | 
			
		||||
            // Writtable objects that can't be edited by players
 | 
			
		||||
            thingAttributes.readable = true;
 | 
			
		||||
            fin.read((char*)&thingAttributes.subParam08, 2);
 | 
			
		||||
            thingAttributes.subParam08 = fw::getu16(fin);
 | 
			
		||||
            break;
 | 
			
		||||
        case 0x0A: // Fluid containers
 | 
			
		||||
            fin.read((char*)&read_byte, 1);
 | 
			
		||||
            thingAttributes.group = THING_GROUP_FLUID;
 | 
			
		||||
            fw::getu8(fin);
 | 
			
		||||
            break;
 | 
			
		||||
        case 0x0B: // Splashes
 | 
			
		||||
            thingAttributes.group = THING_GROUP_SPLASH;
 | 
			
		||||
| 
						 | 
				
			
			@ -162,8 +160,8 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes
 | 
			
		|||
            thingAttributes.rotable = true;
 | 
			
		||||
            break;
 | 
			
		||||
        case 0x15: // Light info
 | 
			
		||||
            fin.read((char*)&thingAttributes.lightLevel, 2);
 | 
			
		||||
            fin.read((char*)&thingAttributes.lightColor, 2);
 | 
			
		||||
            thingAttributes.lightLevel = fw::getu16(fin);
 | 
			
		||||
            thingAttributes.lightColor = fw::getu16(fin);
 | 
			
		||||
            break;
 | 
			
		||||
        case 0x16:
 | 
			
		||||
            break;
 | 
			
		||||
| 
						 | 
				
			
			@ -171,17 +169,12 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes
 | 
			
		|||
            break;
 | 
			
		||||
        case 0x18: // Thing must be drawed with offset
 | 
			
		||||
            thingAttributes.hasHeight = true;
 | 
			
		||||
            fin.read((char*)&thingAttributes.xOffset, 1);
 | 
			
		||||
            fin.read((char*)&thingAttributes.yOffset, 1);
 | 
			
		||||
 | 
			
		||||
            fin.read((char*)&read_short, 2);
 | 
			
		||||
            thingAttributes.xOffset = fw::getu8(fin);
 | 
			
		||||
            thingAttributes.yOffset = fw::getu8(fin);
 | 
			
		||||
            fw::getu16(fin);
 | 
			
		||||
            break;
 | 
			
		||||
        case 0x19: // pixels characters height
 | 
			
		||||
 | 
			
		||||
            //fin.read((char*)&thingAttributes.xOffset, 1);
 | 
			
		||||
            //fin.read((char*)&thingAttributes.yOffset, 1);
 | 
			
		||||
            fin.read((char*)&read_short, 2);
 | 
			
		||||
            //logDebug((int)thingAttributes.xOffset, " ", (int)thingAttributes.yOffset);
 | 
			
		||||
            fw::getu16(fin);
 | 
			
		||||
            break;
 | 
			
		||||
        case 0x1A:
 | 
			
		||||
            //thingAttributes.hasHeight = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -189,12 +182,11 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes
 | 
			
		|||
        case 0x1B:
 | 
			
		||||
            break;
 | 
			
		||||
        case 0x1C: // Minimap color
 | 
			
		||||
            fin.read((char*)&thingAttributes.miniMapColor, 2);
 | 
			
		||||
            thingAttributes.miniMapColor = fw::getu16(fin);
 | 
			
		||||
            thingAttributes.hasMiniMapColor = true;
 | 
			
		||||
            break;
 | 
			
		||||
        case 0x1D: // Unknown
 | 
			
		||||
            fin.read((char*)&read_short, 2);
 | 
			
		||||
            if(read_short == 1112)
 | 
			
		||||
            if(fw::getu16(fin) == 1112)
 | 
			
		||||
                thingAttributes.readable = true;
 | 
			
		||||
            break;
 | 
			
		||||
        case 0x1E:
 | 
			
		||||
| 
						 | 
				
			
			@ -205,6 +197,6 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes
 | 
			
		|||
        case 0x20:
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            throw std::logic_error(fw::mkstr("ERROR: unknown .dat byte code: 0x", std::hex, (int)opt));
 | 
			
		||||
            throw std::runtime_error(fw::mkstr("unknown .dat byte code: 0x", std::hex, (int)opt));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@
 | 
			
		|||
class DatManager
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    bool load(const std::string& filename);
 | 
			
		||||
    bool load(const std::string& file);
 | 
			
		||||
    void unload();
 | 
			
		||||
 | 
			
		||||
    void parseThingAttributes(std::stringstream& fin, ThingAttributes& thingAttributes);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,11 +12,16 @@ SpriteManager::SpriteManager()
 | 
			
		|||
 | 
			
		||||
bool SpriteManager::load(const std::string &filename)
 | 
			
		||||
{
 | 
			
		||||
    g_resources.loadFile(filename, m_fin);
 | 
			
		||||
    m_signature = fw::getu32(m_fin);
 | 
			
		||||
    m_spritesCount = fw::getu16(m_fin);
 | 
			
		||||
    m_sprites.resize(m_spritesCount);
 | 
			
		||||
    return true;
 | 
			
		||||
    try {
 | 
			
		||||
        g_resources.loadFile(filename, m_fin);
 | 
			
		||||
        m_signature = fw::getu32(m_fin);
 | 
			
		||||
        m_spritesCount = fw::getu16(m_fin);
 | 
			
		||||
        m_sprites.resize(m_spritesCount);
 | 
			
		||||
        return true;
 | 
			
		||||
    } catch(std::exception& e) {
 | 
			
		||||
        logError(e.what());
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SpriteManager::unload()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue