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