make otml simpler and easier to use, improve error handling/exceptions

This commit is contained in:
Eduardo Bart 2011-08-19 15:53:23 -03:00
parent f9e7d52ac0
commit 033f14780d
32 changed files with 646 additions and 622 deletions

View File

@ -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

View File

@ -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);
for(auto it : m_confsMap) {
OTMLNodePtr node = OTMLNode::create(it.first, it.second);
doc->addChild(node);
}
return doc->save(m_fileName);
}
return false;
}

View File

@ -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()
{
try {
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;
}
if(!dep)
throw std::runtime_error(fw::mkstr("could not find module dependency '", depName ,"'"));
if(!dep->isLoaded()) {
if(!dep->load()) {
logError("ERROR: failed to load module '",m_name,"': a dependency has failed to load");
return false;
}
}
if(!dep->isLoaded() && !dep->load())
throw std::runtime_error(fw::mkstr("dependency '", depName, "' has failed to load"));
}
if(m_loadCallback) {
m_loaded = m_loadCallback();
if(!m_loaded) {
logError("ERROR: failed to load module '",m_name, "': onLoad returned false");
return false;
}
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;
}
}
void Module::unload()

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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

View File

@ -3,6 +3,5 @@
#include "otmldocument.h"
#include "otmlnode.h"
#include "otmlnodeext.h"
#endif

View File

@ -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());
}

View File

@ -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();

View File

@ -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;
};

View File

@ -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 count = 0;
for(const OTMLNodePtr& child : m_children) {
if(!child->isNull())
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 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);
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) {
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_childNodes.erase(it);
m_childNodes.insert(it, newChild);
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);
}

View File

@ -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, typename U>
T OTMLNode::readAt(const U& childIdentifier, const T& def) {
OTMLNodePtr child = get(childIdentifier);
if(!child)
template<typename T>
T OTMLNode::valueAtIndex(int childIndex, const T& def) {
if(OTMLNodePtr node = getIndex(childIndex))
return node->value<T>();
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;
}
OTMLNodePtr child = OTMLNode::create(childTag);
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();
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);
}
}
#endif

View File

@ -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->setSource(doc->source() + ":" + fw::unsafe_cast<std::string>(nodeLine));
// ~ is considered the null value
if(value == "~")
node->setNull(true);
else
node->setValue(value);
node->setSource(doc->source() + ":" + fw::safe_cast<std::string>(currentLine));
currentParent->addChild(node);
previousNode = node;
}

View File

@ -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()

View File

@ -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())

View File

@ -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()

View File

@ -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));
}

View File

@ -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);

View File

@ -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()

View File

@ -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) { }

View File

@ -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));
}
}

View File

@ -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);

View File

@ -12,11 +12,16 @@ SpriteManager::SpriteManager()
bool SpriteManager::load(const std::string &filename)
{
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()