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