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

master
Eduardo Bart 13 years ago
parent f9e7d52ac0
commit 033f14780d

@ -110,15 +110,16 @@ SET(SOURCES
# framework otml # framework otml
src/framework/otml/otmldocument.cpp src/framework/otml/otmldocument.cpp
src/framework/otml/otmlemitter.cpp src/framework/otml/otmlemitter.cpp
src/framework/otml/otmlexception.cpp
src/framework/otml/otmlnode.cpp src/framework/otml/otmlnode.cpp
src/framework/otml/otmlparser.cpp src/framework/otml/otmlparser.cpp
src/framework/otml/otmlexception.cpp
# framework luascript # framework luascript
src/framework/luascript/luainterface.cpp src/framework/luascript/luainterface.cpp
src/framework/luascript/luaobject.cpp src/framework/luascript/luaobject.cpp
src/framework/luascript/luaexception.cpp src/framework/luascript/luaexception.cpp
src/framework/luascript/luafunctions.cpp src/framework/luascript/luafunctions.cpp
src/framework/luascript/luavaluecasts.cpp
# framework ui # framework ui
src/framework/ui/uimanager.cpp src/framework/ui/uimanager.cpp

@ -9,27 +9,23 @@ bool Configs::load(const std::string& fileName)
{ {
m_fileName = fileName; m_fileName = fileName;
if(!g_resources.fileExists(fileName))
return false;
try { try {
OTMLDocumentPtr doc = OTMLDocument::parse(fileName); OTMLDocumentPtr doc = OTMLDocument::parse(fileName);
for(const OTMLNodePtr& child : doc->childNodes()) for(const OTMLNodePtr& child : doc->children())
m_confsMap[child->tag()] = child->value(); m_confsMap[child->tag()] = child->value();
return true;
} catch(std::exception& e) { } catch(std::exception& e) {
logError("ERROR: could not load configurations: ", e.what()); logError("ERROR: could not load configurations: ", e.what());
return false; return false;
} }
return true;
} }
bool Configs::save() bool Configs::save()
{ {
if(!m_fileName.empty()) { OTMLDocumentPtr doc = OTMLDocument::create();
OTMLDocumentPtr doc = OTMLDocument::create(); for(auto it : m_confsMap) {
doc->write(m_confsMap); OTMLNodePtr node = OTMLNode::create(it.first, it.second);
return doc->save(m_fileName); doc->addChild(node);
} }
return false; return doc->save(m_fileName);
} }

@ -6,61 +6,57 @@
void Module::discover(const OTMLNodePtr& moduleNode) void Module::discover(const OTMLNodePtr& moduleNode)
{ {
m_description = moduleNode->readAt<std::string>("description"); const static std::string none = "none";
m_author = moduleNode->readAt<std::string>("author"); m_description = moduleNode->valueAt("description", none);
m_website = moduleNode->readAt<std::string>("website"); m_author = moduleNode->valueAt("author", none);
m_version = moduleNode->readAt<std::string>("version"); m_website = moduleNode->valueAt("website", none);
m_version = moduleNode->valueAt("version", none);
m_autoLoad = moduleNode->valueAt<bool>("autoLoad", false);
if(OTMLNodePtr node = moduleNode->get("dependencies")) { if(OTMLNodePtr node = moduleNode->get("dependencies")) {
for(const OTMLNodePtr& tmp : node->childNodes()) for(const OTMLNodePtr& tmp : node->children())
m_dependencies.push_back(tmp->value()); m_dependencies.push_back(tmp->value());
} }
// set onLoad callback // set onLoad callback
if(OTMLNodePtr node = moduleNode->get("onLoad")) { if(OTMLNodePtr node = moduleNode->get("onLoad")) {
g_lua.loadFunction(node->read<std::string>(), "@" + node->source() + "[" + node->tag() + "]"); g_lua.loadFunction(node->value<std::string>(), "@" + node->source() + "[" + node->tag() + "]");
g_lua.useValue(); g_lua.useValue();
m_loadCallback = g_lua.polymorphicPop<BooleanCallback>(); m_loadCallback = g_lua.polymorphicPop<BooleanCallback>();
} }
// set onUnload callback // set onUnload callback
if(OTMLNodePtr node = moduleNode->get("onUnload")) { if(OTMLNodePtr node = moduleNode->get("onUnload")) {
g_lua.loadFunction(node->read<std::string>(), "@" + node->source() + "[" + node->tag() + "]"); g_lua.loadFunction(node->value<std::string>(), "@" + node->source() + "[" + node->tag() + "]");
g_lua.useValue(); g_lua.useValue();
m_unloadCallback = g_lua.polymorphicPop<SimpleCallback>(); m_unloadCallback = g_lua.polymorphicPop<SimpleCallback>();
} }
// load if autoLoad is set
m_autoLoad = moduleNode->readAt<bool>("autoLoad", false);
} }
bool Module::load() bool Module::load()
{ {
for(const std::string& depName : m_dependencies) { try {
ModulePtr dep = g_modules.getModule(depName); for(const std::string& depName : m_dependencies) {
if(!dep) { ModulePtr dep = g_modules.getModule(depName);
logError("ERROR: failed to load module '",m_name,"': could not find module dependency '",depName,"'"); if(!dep)
return false; throw std::runtime_error(fw::mkstr("could not find module dependency '", depName ,"'"));
}
if(!dep->isLoaded()) { if(!dep->isLoaded() && !dep->load())
if(!dep->load()) { throw std::runtime_error(fw::mkstr("dependency '", depName, "' has failed to load"));
logError("ERROR: failed to load module '",m_name,"': a dependency has failed to load");
return false;
}
} }
}
if(m_loadCallback) { if(m_loadCallback) {
m_loaded = m_loadCallback(); m_loaded = m_loadCallback();
if(!m_loaded) { if(!m_loaded)
logError("ERROR: failed to load module '",m_name, "': onLoad returned false"); throw std::runtime_error("module onLoad event returned false");
return false;
} }
}
logInfo("Loaded module '", m_name, "'"); logInfo("Loaded module '", m_name, "'");
return true; return true;
} catch(std::exception& e) {
logError("ERROR: failed to load module '", m_name, "': ", e.what());
return false;
}
} }
void Module::unload() void Module::unload()

@ -30,7 +30,7 @@ bool ModuleManager::discoverModule(const std::string& file)
OTMLDocumentPtr doc = OTMLDocument::parse(file); OTMLDocumentPtr doc = OTMLDocument::parse(file);
OTMLNodePtr moduleNode = doc->at("Module"); OTMLNodePtr moduleNode = doc->at("Module");
std::string name = moduleNode->readAt<std::string>("name"); std::string name = moduleNode->valueAt("name");
if(getModule(name)) if(getModule(name))
throw OTMLException(moduleNode, "a module with the same name is already discovered, did you duplicate module names?"); throw OTMLException(moduleNode, "a module with the same name is already discovered, did you duplicate module names?");
@ -38,7 +38,7 @@ bool ModuleManager::discoverModule(const std::string& file)
module->discover(moduleNode); module->discover(moduleNode);
m_modules.push_back(module); m_modules.push_back(module);
} catch(std::exception& e) { } catch(std::exception& e) {
logError("ERROR: failed to load module from '", file, "':\n", e.what()); logError("ERROR: failed to load module from '", file, "': ", e.what());
return false; return false;
} }
return true; return true;

@ -30,14 +30,14 @@ void ResourceManager::init(const char* argv0)
} }
if(!found) if(!found)
throw std::runtime_error("could not find modules directory"); logFatal("FATAL ERROR: could not find modules directory");
// setup write directory // setup write directory
std::string dir = g_platform.getAppUserDir(); std::string dir = g_platform.getAppUserDir();
if(g_resources.setWriteDir(dir)) if(g_resources.setWriteDir(dir))
g_resources.addToSearchPath(dir); g_resources.addToSearchPath(dir);
else else
throw std::runtime_error("could not setup write directory"); logError("ERROR: could not setup write directory");
} }
void ResourceManager::terminate() void ResourceManager::terminate()
@ -156,12 +156,11 @@ std::string ResourceManager::resolvePath(const std::string& path)
{ {
std::string fullPath; std::string fullPath;
if(boost::starts_with(path, "/")) if(boost::starts_with(path, "/"))
fullPath = path.substr(1); fullPath = path;
else { else {
std::string scriptPath = g_lua.currentSourcePath(); std::string scriptPath = "/" + g_lua.currentSourcePath();
if(!scriptPath.empty()) { if(!scriptPath.empty())
fullPath += scriptPath + "/"; fullPath += scriptPath + "/";
}
fullPath += path; fullPath += path;
} }
return fullPath; return fullPath;

@ -61,17 +61,17 @@ BorderImagePtr BorderImage::loadFromOTML(const OTMLNodePtr& borderImageNode)
// load basic border confs // load basic border confs
size = texture->getSize(); size = texture->getSize();
size = borderImageNode->readAt("size", size); size = borderImageNode->valueAt("size", size);
offset = borderImageNode->readAt("offset", offset); offset = borderImageNode->valueAt("offset", offset);
border = borderImageNode->readAt("border", 0); border = borderImageNode->valueAt("border", 0);
subRect = Rect(offset, size); subRect = Rect(offset, size);
// load border margins // load border margins
top = bottom = left = right = border; top = bottom = left = right = border;
top = borderImageNode->readAt("border.top", top); top = borderImageNode->valueAt("border.top", top);
bottom = borderImageNode->readAt("border.bottom", bottom); bottom = borderImageNode->valueAt("border.bottom", bottom);
left = borderImageNode->readAt("border.left", left); left = borderImageNode->valueAt("border.left", left);
right = borderImageNode->readAt("border.right", right); right = borderImageNode->valueAt("border.right", right);
// calculates border coords // calculates border coords
leftBorder = Rect(subRect.left(), subRect.top() + top, left, subRect.height() - top - bottom); leftBorder = Rect(subRect.left(), subRect.top() + top, left, subRect.height() - top - bottom);
@ -86,15 +86,15 @@ BorderImagePtr BorderImage::loadFromOTML(const OTMLNodePtr& borderImageNode)
// load individual border conf if supplied // load individual border conf if supplied
/* /*
leftBorder = borderImageNode->readAt("left border", leftBorder); leftBorder = borderImageNode->valueAt("left border", leftBorder);
rightBorder = borderImageNode->readAt("right border", rightBorder); rightBorder = borderImageNode->valueAt("right border", rightBorder);
topBorder = borderImageNode->readAt("top border", topBorder); topBorder = borderImageNode->valueAt("top border", topBorder);
bottomBorder = borderImageNode->readAt("bottom border", bottomBorder); bottomBorder = borderImageNode->valueAt("bottom border", bottomBorder);
topLeftCorner = borderImageNode->readAt("top left corner", topLeftCorner); topLeftCorner = borderImageNode->valueAt("top left corner", topLeftCorner);
topRightCorner = borderImageNode->readAt("top right corner", topRightCorner); topRightCorner = borderImageNode->valueAt("top right corner", topRightCorner);
bottomLeftCorner = borderImageNode->readAt("bottom left corner", bottomLeftCorner); bottomLeftCorner = borderImageNode->valueAt("bottom left corner", bottomLeftCorner);
bottomRightCorner = borderImageNode->readAt("bottom right corner", bottomRightCorner); bottomRightCorner = borderImageNode->valueAt("bottom right corner", bottomRightCorner);
center = borderImageNode->readAt("center", center); center = borderImageNode->valueAt("center", center);
*/ */
return BorderImagePtr(new BorderImage(texture, return BorderImagePtr(new BorderImage(texture,

@ -7,7 +7,6 @@ class Texture;
class Font; class Font;
class Image; class Image;
class BorderImage; class BorderImage;
class TextArea;
class FrameBuffer; class FrameBuffer;
typedef std::weak_ptr<Texture> TextureWeakPtr; typedef std::weak_ptr<Texture> TextureWeakPtr;
@ -16,7 +15,6 @@ typedef std::shared_ptr<Texture> TexturePtr;
typedef std::shared_ptr<Font> FontPtr; typedef std::shared_ptr<Font> FontPtr;
typedef std::shared_ptr<Image> ImagePtr; typedef std::shared_ptr<Image> ImagePtr;
typedef std::shared_ptr<BorderImage> BorderImagePtr; typedef std::shared_ptr<BorderImage> BorderImagePtr;
typedef std::shared_ptr<TextArea> TextAreaPtr;
typedef std::shared_ptr<FrameBuffer> FrameBufferPtr; typedef std::shared_ptr<FrameBuffer> FrameBufferPtr;
#endif #endif

@ -6,25 +6,25 @@
void Font::load(const OTMLNodePtr& fontNode) void Font::load(const OTMLNodePtr& fontNode)
{ {
std::string textureName = fontNode->readAt<std::string>("texture"); std::string textureName = fontNode->valueAt("texture");
Size glyphSize = fontNode->readAt<Size>("glyph size"); Size glyphSize = fontNode->valueAt<Size>("glyph size");
m_glyphHeight = fontNode->readAt<int>("height"); m_glyphHeight = fontNode->valueAt<int>("height");
m_topMargin = fontNode->readAt("top margin", 0); m_topMargin = fontNode->valueAt("top margin", 0);
m_firstGlyph = fontNode->readAt("first glyph", 32); m_firstGlyph = fontNode->valueAt("first glyph", 32);
m_glyphSpacing = fontNode->readAt("spacing", Size(0,0)); m_glyphSpacing = fontNode->valueAt("spacing", Size(0,0));
// load font texture // load font texture
m_texture = g_textures.getTexture(textureName); m_texture = g_textures.getTexture(textureName);
if(!m_texture) if(!m_texture)
throw OTMLException(fontNode, "failed to load texture for font"); throw std::runtime_error("failed to load texture for font");
// auto calculate widths // auto calculate widths
calculateGlyphsWidthsAutomatically(glyphSize); calculateGlyphsWidthsAutomatically(glyphSize);
// read custom widths // read custom widths
if(OTMLNodePtr node = fontNode->get("glyph widths")) { if(OTMLNodePtr node = fontNode->get("glyph widths")) {
for(const OTMLNodePtr& child : node->childNodes()) for(const OTMLNodePtr& child : node->children())
m_glyphsSize[fw::safe_cast<int>(child->tag())].setWidth(child->read<int>()); m_glyphsSize[fw::safe_cast<int>(child->tag())].setWidth(child->value<int>());
} }
// calculate glyphs texture coords // calculate glyphs texture coords

@ -20,9 +20,9 @@ bool FontManager::importFont(std::string fontFile)
OTMLDocumentPtr doc = OTMLDocument::parse(fontFile); OTMLDocumentPtr doc = OTMLDocument::parse(fontFile);
OTMLNodePtr fontNode = doc->at("Font"); OTMLNodePtr fontNode = doc->at("Font");
std::string name = fontNode->readAt<std::string>("name"); std::string name = fontNode->valueAt("name");
if(fontExists(name)) if(fontExists(name))
throw OTMLException(fontNode, "a font with the same name is already imported, did you duplicate font names?"); throw std::runtime_error("a font with the same name is already imported, did you duplicate font names?");
FontPtr font(new Font(name)); FontPtr font(new Font(name));
font->load(fontNode); font->load(fontNode);
@ -34,7 +34,7 @@ bool FontManager::importFont(std::string fontFile)
return true; return true;
} catch(std::exception& e) { } catch(std::exception& e) {
logError("ERROR: could not load font '", fontFile, "': ", e.what()); logError("ERROR: could not load font from '", fontFile, "': ", e.what());
return false; return false;
} }
} }

@ -17,9 +17,9 @@ Image::Image(TexturePtr texture, Rect textureCoords)
ImagePtr Image::loadFromOTML(const OTMLNodePtr& imageNode) ImagePtr Image::loadFromOTML(const OTMLNodePtr& imageNode)
{ {
// load configs from otml node // load configs from otml node
std::string source = imageNode->hasValue() ? imageNode->read<std::string>() : imageNode->readAt<std::string>("source"); std::string source = imageNode->hasValue() ? imageNode->value() : imageNode->valueAt("source");
bool smooth = imageNode->readAt("smooth", false); bool smooth = imageNode->valueAt("smooth", false);
Rect textureCoords = imageNode->readAt("coords", Rect()); Rect textureCoords = imageNode->valueAt("coords", Rect());
// load texture // load texture
TexturePtr texture = g_textures.getTexture(source); TexturePtr texture = g_textures.getTexture(source);

@ -24,7 +24,7 @@ TexturePtr TextureManager::getTexture(const std::string& textureFile)
try { try {
// currently only png textures are supported // currently only png textures are supported
if(!boost::ends_with(textureFile, ".png")) if(!boost::ends_with(textureFile, ".png"))
throw std::logic_error("texture file format no supported"); throw std::runtime_error("texture file format no supported");
// load texture file data // load texture file data
std::stringstream fin; std::stringstream fin;

@ -39,7 +39,7 @@ namespace luabinder
/// C++ function caller that can push results to lua /// C++ function caller that can push results to lua
template<typename Ret, typename F, typename... Args> template<typename Ret, typename F, typename... Args>
typename std::enable_if<!std::is_void<Ret>::value, int>::type typename std::enable_if<!std::is_void<Ret>::value, int>::type
call_fun_and_push_result(const F& f, LuaInterface* lua, Args... args) { call_fun_and_push_result(const F& f, LuaInterface* lua, const Args&... args) {
Ret ret = f(args...); Ret ret = f(args...);
lua->polymorphicPush(ret); lua->polymorphicPush(ret);
return 1; return 1;
@ -48,7 +48,7 @@ namespace luabinder
/// C++ void function caller /// C++ void function caller
template<typename Ret, typename F, typename... Args> template<typename Ret, typename F, typename... Args>
typename std::enable_if<std::is_void<Ret>::value, int>::type typename std::enable_if<std::is_void<Ret>::value, int>::type
call_fun_and_push_result(const F& f, LuaInterface* lua, Args... args) { call_fun_and_push_result(const F& f, LuaInterface* lua, const Args&... args) {
f(args...); f(args...);
return 0; return 0;
} }
@ -57,14 +57,14 @@ namespace luabinder
template<int N, typename Ret> template<int N, typename Ret>
struct expand_fun_arguments { struct expand_fun_arguments {
template<typename Tuple, typename F, typename... Args> template<typename Tuple, typename F, typename... Args>
static int call(const Tuple& tuple, const F& f, LuaInterface* lua, Args... args) { static int call(const Tuple& tuple, const F& f, LuaInterface* lua, const Args&... args) {
return expand_fun_arguments<N-1,Ret>::call(tuple, f, lua, std::cref(std::get<N-1>(tuple)), args...); return expand_fun_arguments<N-1,Ret>::call(tuple, f, lua, std::get<N-1>(tuple), args...);
} }
}; };
template<typename Ret> template<typename Ret>
struct expand_fun_arguments<0,Ret> { struct expand_fun_arguments<0,Ret> {
template<typename Tuple, typename F, typename... Args> template<typename Tuple, typename F, typename... Args>
static int call(const Tuple& tuple, const F& f, LuaInterface* lua, Args... args) { static int call(const Tuple& tuple, const F& f, LuaInterface* lua, const Args&... args) {
return call_fun_and_push_result<Ret>(f, lua, args...); return call_fun_and_push_result<Ret>(f, lua, args...);
} }
}; };
@ -178,7 +178,7 @@ namespace luabinder
template<typename Ret, typename Obj, typename... Args> template<typename Ret, typename Obj, typename... Args>
LuaCppFunction bind_mem_fun(Ret (Obj::*f)(Args...)) { LuaCppFunction bind_mem_fun(Ret (Obj::*f)(Args...)) {
auto mf = std::mem_fn(f); auto mf = std::mem_fn(f);
typedef typename std::tuple<Obj*, typename remove_const_ref<Args>::type...> Tuple; typedef typename std::tuple<std::shared_ptr<Obj>, typename remove_const_ref<Args>::type...> Tuple;
return bind_fun_specializer<typename remove_const_ref<Ret>::type, return bind_fun_specializer<typename remove_const_ref<Ret>::type,
decltype(mf), decltype(mf),
Tuple>(mf); Tuple>(mf);
@ -186,7 +186,7 @@ namespace luabinder
template<typename Ret, typename Obj, typename... Args> template<typename Ret, typename Obj, typename... Args>
LuaCppFunction bind_mem_fun(Ret (Obj::*f)(Args...) const) { LuaCppFunction bind_mem_fun(Ret (Obj::*f)(Args...) const) {
auto mf = std::mem_fn(f); auto mf = std::mem_fn(f);
typedef typename std::tuple<Obj*, typename remove_const_ref<Args>::type...> Tuple; typedef typename std::tuple<std::shared_ptr<Obj>, typename remove_const_ref<Args>::type...> Tuple;
return bind_fun_specializer<typename remove_const_ref<Ret>::type, return bind_fun_specializer<typename remove_const_ref<Ret>::type,
decltype(mf), decltype(mf),
Tuple>(mf); Tuple>(mf);
@ -197,7 +197,7 @@ namespace luabinder
LuaCppFunction bind_mem_fun(int (Obj::*f)(LuaInterface*)) { LuaCppFunction bind_mem_fun(int (Obj::*f)(LuaInterface*)) {
auto mf = std::mem_fn(f); auto mf = std::mem_fn(f);
return [=](LuaInterface* lua) { return [=](LuaInterface* lua) {
auto obj = lua->castValue<Obj*>(1); auto obj = lua->castValue<std::shared_ptr<Obj>>(1);
lua->remove(1); lua->remove(1);
return mf(obj, lua); return mf(obj, lua);
}; };

@ -0,0 +1,202 @@
#include "luavaluecasts.h"
#include "luainterface.h"
#include <framework/otml/otmlnode.h>
// bool
void push_luavalue(bool b)
{
g_lua.pushBoolean(b);
}
bool luavalue_cast(int index, bool& b)
{
b = g_lua.toBoolean(index);
return true;
}
// int
void push_luavalue(int i)
{
g_lua.pushInteger(i);
}
bool luavalue_cast(int index, int& i)
{
i = g_lua.toInteger(index);
if(i == 0 && !g_lua.isNumber(index))
return false;
return true;
}
// double
void push_luavalue(double d)
{
g_lua.pushNumber(d);
}
bool luavalue_cast(int index, double& d)
{
d = g_lua.toNumber(index);
if(d == 0 && !g_lua.isNumber(index))
return false;
return true;
}
// string
void push_luavalue(const char* cstr)
{
g_lua.pushCString(cstr);
}
void push_luavalue(const std::string& str)
{
g_lua.pushString(str);
}
bool luavalue_cast(int index, std::string& str)
{
str = g_lua.toString(index);
if(str.empty() && !g_lua.isString(index))
return false;
return true;
}
// lua cpp function
void push_luavalue(const LuaCppFunction& func)
{
g_lua.pushCppFunction(func);
}
// color
void push_luavalue(const Color& color)
{
g_lua.newTable();
g_lua.pushInteger(color.r());
g_lua.setField("r");
g_lua.pushInteger(color.g());
g_lua.setField("g");
g_lua.pushInteger(color.b());
g_lua.setField("b");
g_lua.pushInteger(color.a());
g_lua.setField("a");
}
bool luavalue_cast(int index, Color& color)
{
if(g_lua.isTable(index)) {
g_lua.getField("r", index);
color.setRed(g_lua.popInteger());
g_lua.getField("g", index);
color.setGreen(g_lua.popInteger());
g_lua.getField("b", index);
color.setBlue(g_lua.popInteger());
g_lua.getField("a", index);
color.setAlpha(g_lua.popInteger());
return true;
} else if(g_lua.isString()) {
return fw::cast(g_lua.toString(index), color);
} else if(g_lua.isNil()) {
color = Color::white;
return true;
}
return false;
}
// rect
void push_luavalue(const Rect& rect)
{
g_lua.newTable();
g_lua.pushInteger(rect.x());
g_lua.setField("x");
g_lua.pushInteger(rect.y());
g_lua.setField("y");
g_lua.pushInteger(rect.width());
g_lua.setField("width");
g_lua.pushInteger(rect.height());
g_lua.setField("height");
}
bool luavalue_cast(int index, Rect& rect)
{
if(g_lua.isTable(index)) {
g_lua.getField("x", index);
rect.setX(g_lua.popInteger());
g_lua.getField("y", index);
rect.setY(g_lua.popInteger());
g_lua.getField("width", index);
rect.setWidth(g_lua.popInteger());
g_lua.getField("height", index);
rect.setHeight(g_lua.popInteger());
} else if(g_lua.isString()) {
return fw::cast(g_lua.toString(index), rect);
} else if(g_lua.isNil()) {
rect = Rect();
return true;
}
return true;
}
// point
void push_luavalue(const Point& point)
{
g_lua.newTable();
g_lua.pushInteger(point.x);
g_lua.setField("x");
g_lua.pushInteger(point.y);
g_lua.setField("y");
}
bool luavalue_cast(int index, Point& point)
{
if(g_lua.isTable(index)) {
g_lua.getField("x", index);
point.x = g_lua.popInteger();
g_lua.getField("y", index);
point.y = g_lua.popInteger();
return true;
} else if(g_lua.isString()) {
return fw::cast(g_lua.toString(index), point);
} else if(g_lua.isNil()) {
point = Point();
return true;
}
return true;
}
// otml nodes
void push_luavalue(const OTMLNodePtr& node)
{
if(node->hasValue()) {
g_lua.pushString(node->value());
} else if(node->hasChildren()) {
g_lua.newTable();
bool pushedChild = false;
for(const OTMLNodePtr& cnode : node->children()) {
if(cnode->isUnique()) {
push_luavalue(cnode);
if(!g_lua.isNil()) {
g_lua.setField(cnode->tag());
pushedChild = true;
} else
g_lua.pop();
}
}
if(!pushedChild) {
g_lua.pop();
g_lua.pushNil();
}
} else
g_lua.pushNil();
}
// object ptr
bool luavalue_cast(int index, LuaObjectPtr& obj) {
if(g_lua.isUserdata(index)) {
obj = g_lua.toObject(index);
return true;
} else if(g_lua.isNil(index)) {
obj = nullptr;
return true;
}
return false;
}

@ -2,137 +2,123 @@
#define LUAVALUECASTS_H #define LUAVALUECASTS_H
// this file is and must be included only from luainterface.h // this file is and must be included only from luainterface.h
#include "luainterface.h"
#include "luaexception.h"
/// Pushes bool #include "declarations.h"
inline void push_luavalue(bool v) { #include <framework/otml/declarations.h>
g_lua.pushBoolean(v);
}
/// Pushes int // bool
inline void push_luavalue(int v) { void push_luavalue(bool b);
g_lua.pushInteger(v); bool luavalue_cast(int index, bool& b);
}
/// Pushes double // int
inline void push_luavalue(double v) { void push_luavalue(int i);
g_lua.pushNumber(v); bool luavalue_cast(int index, int& i);
}
/// Pushes std::string // double
inline void push_luavalue(const std::string& v) { void push_luavalue(double d);
g_lua.pushString(v); bool luavalue_cast(int index, double& d);
}
/// Pushes const char* // string
inline void push_luavalue(const char* v) { void push_luavalue(const char* cstr);
g_lua.pushCString(v); void push_luavalue(const std::string& str);
} bool luavalue_cast(int index, std::string& str);
/// Pushes LuaCppFunction // lua cpp function
inline void push_luavalue(const LuaCppFunction& v) { void push_luavalue(const LuaCppFunction& func);
g_lua.pushCppFunction(v);
} // color
void push_luavalue(const Color& color);
bool luavalue_cast(int index, Color& color);
/// Pushes LuaObjectPtr // rect
void push_luavalue(const Rect& rect);
bool luavalue_cast(int index, Rect& rect);
// point
void push_luavalue(const Point& point);
bool luavalue_cast(int index, Point& point);
// size
void push_luavalue(const Size& size);
bool luavalue_cast(int index, Size& size);
// otml nodes
void push_luavalue(const OTMLNodePtr& node);
// enum
template<class T>
typename std::enable_if<std::is_enum<T>::value, bool>::type
luavalue_cast(int index, T& myenum);
// LuaObject pointers
template<class T> template<class T>
typename std::enable_if<std::is_base_of<LuaObject, typename T::element_type>::value, void>::type typename std::enable_if<std::is_base_of<LuaObject, typename T::element_type>::value, void>::type
push_luavalue(const T& v) { push_luavalue(const T& obj);
if(v)
return g_lua.pushObject(v);
return g_lua.pushNil();
}
/// Push std::function types 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> template<typename Ret, typename... Args>
void push_luavalue(const std::function<Ret(Args...)>& v) { void push_luavalue(const std::function<Ret(Args...)>& func);
if(v) {
LuaCppFunction f = luabinder::bind_fun(v);
g_lua.pushCppFunction(f);
} else
g_lua.pushNil();
}
/// Casts lua value to bool template<typename... Args>
inline bool luavalue_cast(int index, bool& o) { bool luavalue_cast(int index, std::function<void(Args...)>& func);
o = g_lua.toBoolean(index);
return true;
}
/// Casts lua value to int template<typename Ret, typename... Args>
inline bool luavalue_cast(int index, int& o) { typename std::enable_if<!std::is_void<Ret>::value, bool>::type
o = g_lua.toInteger(index); luavalue_cast(int index, std::function<Ret(Args...)>& func);
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 // start definitions
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 #include "luaexception.h"
inline bool luavalue_cast(int index, LuaObjectPtr& o) { #include "luainterface.h"
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> template<class T>
typename std::enable_if<std::is_enum<T>::value, bool>::type typename std::enable_if<std::is_enum<T>::value, bool>::type
luavalue_cast(int index, T& o) { luavalue_cast(int index, T& myenum) {
return luavalue_cast(index, (int&)o); return luavalue_cast(index, (int&)myenum);
} }
/// Cast lua userdata to a class pointer
template<class T> template<class T>
typename std::enable_if<std::is_base_of<LuaObject, T>::value, bool>::type typename std::enable_if<std::is_base_of<LuaObject, typename T::element_type>::value, void>::type
luavalue_cast(int index, T*& o) { push_luavalue(const T& obj) {
LuaObjectPtr obj; if(obj)
if(!luavalue_cast(index, obj)) return g_lua.pushObject(obj);
return false; return g_lua.pushNil();
o = std::dynamic_pointer_cast<T>(obj).get();
return !!o;
} }
/// Cast lua userdata to a class shared pointer
template<class T> template<class T>
bool luavalue_cast(int index, std::shared_ptr<T>& o) { typename std::enable_if<std::is_base_of<LuaObject, T>::value, bool>::type
luavalue_cast(int index, std::shared_ptr<T>& ptr) {
LuaObjectPtr obj; LuaObjectPtr obj;
if(!luavalue_cast(index, obj)) if(!luavalue_cast(index, obj))
return false; return false;
o = std::dynamic_pointer_cast<T>(obj); ptr = std::dynamic_pointer_cast<T>(obj);
return !!o; return true;
}
template<typename Ret, typename... Args>
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();
} }
/// Cast a lua function to a std::function
template<typename... Args> template<typename... Args>
bool luavalue_cast(int index, std::function<void(Args...)>& o) { bool luavalue_cast(int index, std::function<void(Args...)>& func) {
if(g_lua.isFunction(index)) { if(g_lua.isFunction(index)) {
g_lua.pushValue(index); g_lua.pushValue(index);
// weak references are used here, this means that the script must hold another reference // weak references are used here, this means that the script must hold another reference
// to this function, otherwise it will expire // to this function, otherwise it will expire
int funcWeakRef = g_lua.weakRef(); int funcWeakRef = g_lua.weakRef();
o = [=](Args... args...) { func = [=](Args... args...) {
// note that we must catch exceptions, because this lambda can be called from anywhere // note that we must catch exceptions, because this lambda can be called from anywhere
// and most of them won't catch exceptions (e.g. dispatcher) // and most of them won't catch exceptions (e.g. dispatcher)
g_lua.getWeakRef(funcWeakRef); g_lua.getWeakRef(funcWeakRef);
@ -150,22 +136,21 @@ bool luavalue_cast(int index, std::function<void(Args...)>& o) {
}; };
return true; return true;
} else if(g_lua.isNil(index)) { } else if(g_lua.isNil(index)) {
o = std::function<void(Args...)>(); func = std::function<void(Args...)>();
return true; return true;
} }
return false; return false;
} }
/// Cast a lua function to a std::function that can return
template<typename Ret, typename... Args> template<typename Ret, typename... Args>
typename std::enable_if<!std::is_void<Ret>::value, bool>::type typename std::enable_if<!std::is_void<Ret>::value, bool>::type
luavalue_cast(int index, std::function<Ret(Args...)>& o) { luavalue_cast(int index, std::function<Ret(Args...)>& func) {
if(g_lua.isFunction(index)) { if(g_lua.isFunction(index)) {
g_lua.pushValue(index); g_lua.pushValue(index);
// weak references are used here, this means that the script must hold another reference // weak references are used here, this means that the script must hold another reference
// to this function, otherwise it will expire // to this function, otherwise it will expire
int funcWeakRef = g_lua.weakRef(); int funcWeakRef = g_lua.weakRef();
o = [=](Args... args...) -> Ret { func = [=](Args... args...) -> Ret {
// note that we must catch exceptions, because this lambda can be called from anywhere // note that we must catch exceptions, because this lambda can be called from anywhere
// and most of them won't catch exceptions (e.g. dispatcher) // and most of them won't catch exceptions (e.g. dispatcher)
try { try {
@ -186,40 +171,10 @@ luavalue_cast(int index, std::function<Ret(Args...)>& o) {
}; };
return true; return true;
} else if(g_lua.isNil(index)) { } else if(g_lua.isNil(index)) {
o = std::function<Ret(Args...)>(); func = std::function<Ret(Args...)>();
return true; return true;
} }
return false; return false;
} }
// additional casts
inline void push_luavalue(const Color& v) {
g_lua.newTable();
g_lua.pushInteger(v.r());
g_lua.setField("r");
g_lua.pushInteger(v.g());
g_lua.setField("g");
g_lua.pushInteger(v.b());
g_lua.setField("b");
g_lua.pushInteger(v.a());
g_lua.setField("a");
}
inline bool luavalue_cast(int index, Color& o) {
if(!g_lua.isTable(index))
return false;
g_lua.getField("r", index);
o.setRed(g_lua.popInteger());
g_lua.getField("g", index);
o.setGreen(g_lua.popInteger());
g_lua.getField("b", index);
o.setBlue(g_lua.popInteger());
g_lua.getField("a", index);
o.setAlpha(g_lua.popInteger());
return true;
}
#endif #endif

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

@ -15,7 +15,7 @@ OTMLDocumentPtr OTMLDocument::parse(const std::string& fileName)
{ {
std::stringstream fin; std::stringstream fin;
g_resources.loadFile(fileName, fin); g_resources.loadFile(fileName, fin);
return parse(fin, fileName); return parse(fin, g_resources.resolvePath(fileName));
} }
OTMLDocumentPtr OTMLDocument::parse(std::istream& in, const std::string& source) OTMLDocumentPtr OTMLDocument::parse(std::istream& in, const std::string& source)
@ -34,8 +34,7 @@ std::string OTMLDocument::emit()
bool OTMLDocument::save(const std::string& fileName) bool OTMLDocument::save(const std::string& fileName)
{ {
setSource(fileName); m_source = fileName;
return g_resources.saveFile(fileName, emit()); return g_resources.saveFile(fileName, emit());
} }

@ -16,13 +16,15 @@ std::string OTMLEmitter::emitNode(const OTMLNodePtr& node, int currentDepth)
ss << node->tag(); ss << node->tag();
// add ':' to if the node is unique or has value // add ':' to if the node is unique or has value
if(node->hasValue() || node->isUnique()) if(node->hasValue() || node->isUnique() || node->isNull())
ss << ":"; ss << ":";
} else } else
ss << "-"; ss << "-";
// emit node value // emit node value
if(node->hasValue()) { if(node->isNull())
ss << " ~";
else if(node->hasValue()) {
ss << " "; ss << " ";
std::string value = node->value(); std::string value = node->value();
@ -61,7 +63,7 @@ std::string OTMLEmitter::emitNode(const OTMLNodePtr& node, int currentDepth)
for(int i=0;i<node->size();++i) { for(int i=0;i<node->size();++i) {
if(currentDepth >= 0 || i != 0) if(currentDepth >= 0 || i != 0)
ss << "\n"; ss << "\n";
ss << emitNode(node->at(i), currentDepth+1); ss << emitNode(node->atIndex(i), currentDepth+1);
} }
return ss.str(); return ss.str();

@ -14,9 +14,6 @@ public:
virtual const char* what() const throw() { return m_what.c_str(); } virtual const char* what() const throw() { return m_what.c_str(); }
protected: protected:
OTMLException() { }
void generateErrorMessage(const OTMLDocumentPtr& doc, const std::string& error, int line);
void generateErrorMessage(const OTMLNodePtr& node, const std::string& error);
std::string m_what; std::string m_what;
}; };

@ -2,157 +2,86 @@
#include "otmlemitter.h" #include "otmlemitter.h"
#include "otmldocument.h" #include "otmldocument.h"
OTMLNode::OTMLNode() OTMLNodePtr OTMLNode::create(std::string tag, bool unique)
{ {
m_unique = false; OTMLNodePtr node(new OTMLNode);
node->setTag(tag);
node->setUnique(unique);
return node;
} }
std::string OTMLNode::tag() const OTMLNodePtr OTMLNode::create(std::string tag, std::string value)
{ {
return m_tag; OTMLNodePtr node(new OTMLNode);
node->setTag(tag);
node->setValue(value);
node->setUnique(true);
return node;
} }
std::string OTMLNode::value() const bool OTMLNode::hasChildren() const
{ {
// ~ is an alias for no value int count = 0;
if(m_value == "~") for(const OTMLNodePtr& child : m_children) {
return fw::empty_string; if(!child->isNull())
return m_value; count++;
} }
return count > 0;
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) OTMLNodePtr OTMLNode::get(const std::string& childTag) const
{ {
for(const OTMLNodePtr& child : m_childNodes) { for(const OTMLNodePtr& child : m_children) {
if(child->tag() == childTag) if(child->tag() == childTag && !child->isNull())
return child; return child;
} }
throw OTMLException(shared_from_this(), fw::mkstr("child node with tag '", childTag, "' not found"));
return nullptr; return nullptr;
} }
OTMLNodePtr OTMLNode::at(int childIndex) OTMLNodePtr OTMLNode::getIndex(int childIndex) const
{ {
if(childIndex < size() && childIndex >= 0) if(childIndex < size() && childIndex >= 0)
return m_childNodes[childIndex]; return m_children[childIndex];
throw OTMLException(shared_from_this(), fw::mkstr("child node at index '", childIndex, "' not found"));
return nullptr; return nullptr;
} }
OTMLNodePtr OTMLNode::get(const std::string& childTag) const OTMLNodePtr OTMLNode::at(const std::string& childTag)
{ {
for(const OTMLNodePtr& child : m_childNodes) { OTMLNodePtr res;
if(child->tag() == childTag) for(const OTMLNodePtr& child : m_children) {
return child; if(child->tag() == childTag && !child->isNull()) {
res = child;
break;
}
} }
return nullptr; if(!res)
throw OTMLException(shared_from_this(), fw::mkstr("child node with tag '", childTag, "' not found"));
return res;
} }
OTMLNodePtr OTMLNode::get(int childIndex) const OTMLNodePtr OTMLNode::atIndex(int childIndex)
{ {
if(childIndex < size() && childIndex >= 0) if(childIndex >= size() || childIndex < 0)
return m_childNodes[childIndex]; throw OTMLException(shared_from_this(), fw::mkstr("child node with index '", childIndex, "' not found"));
return nullptr; return m_children[childIndex];
} }
void OTMLNode::addChild(const OTMLNodePtr& newChild) void OTMLNode::addChild(const OTMLNodePtr& newChild)
{ {
// replace is needed when the tag is marked as unique // replace is needed when the tag is marked as unique
if(newChild->hasTag()) { if(newChild->hasTag()) {
for(OTMLNodePtr node : m_childNodes) { for(const OTMLNodePtr& node : m_children) {
if(node->tag() == newChild->tag() && (node->isUnique() || newChild->isUnique())) { if(node->tag() == newChild->tag() && (node->isUnique() || newChild->isUnique())) {
newChild->setUnique(); newChild->setUnique(true);
replaceChild(node, newChild); replaceChild(node, newChild);
// remove any other child with the same tag // remove any other child with the same tag
auto it = m_childNodes.begin(); auto it = m_children.begin();
while(it != m_childNodes.end()) { while(it != m_children.end()) {
OTMLNodePtr node = (*it); OTMLNodePtr node = (*it);
if(node != newChild && node->tag() == newChild->tag()) { if(node != newChild && node->tag() == newChild->tag()) {
node->setParent(nullptr); node->setParent(nullptr);
it = m_childNodes.erase(it); it = m_children.erase(it);
} else } else
++it; ++it;
} }
@ -161,60 +90,67 @@ void OTMLNode::addChild(const OTMLNodePtr& newChild)
} }
} }
m_childNodes.push_back(newChild); m_children.push_back(newChild);
newChild->setParent(shared_from_this()); newChild->setParent(shared_from_this());
} }
bool OTMLNode::removeChild(const OTMLNodePtr& oldChild) bool OTMLNode::removeChild(const OTMLNodePtr& oldChild)
{ {
for(auto it = m_childNodes.begin(); it != m_childNodes.end(); ++it) { auto it = std::find(m_children.begin(), m_children.end(), oldChild);
if((*it) == oldChild) { if(it != m_children.end()) {
m_childNodes.erase(it); m_children.erase(it);
oldChild->setParent(nullptr); oldChild->setParent(nullptr);
return true; return true;
}
} }
return false; return false;
} }
bool OTMLNode::replaceChild(const OTMLNodePtr& oldChild, const OTMLNodePtr& newChild) bool OTMLNode::replaceChild(const OTMLNodePtr& oldChild, const OTMLNodePtr& newChild)
{ {
for(auto it = m_childNodes.begin(); it != m_childNodes.end(); ++it) { auto it = std::find(m_children.begin(), m_children.end(), oldChild);
if((*it) == oldChild) { if(it != m_children.end()) {
oldChild->setParent(nullptr); oldChild->setParent(nullptr);
newChild->setParent(shared_from_this()); newChild->setParent(shared_from_this());
it = m_childNodes.erase(it); it = m_children.erase(it);
m_childNodes.insert(it, newChild); m_children.insert(it, newChild);
return true; return true;
}
} }
return false; return false;
} }
void OTMLNode::merge(const OTMLNodePtr& node)
{
for(const OTMLNodePtr& child : node->m_children)
addChild(child->clone());
setTag(node->tag());
setSource(node->source());
}
void OTMLNode::clear() void OTMLNode::clear()
{ {
m_childNodes.clear(); for(const OTMLNodePtr& child : m_children)
child->setParent(nullptr);
m_children.clear();
} }
void OTMLNode::merge(const OTMLNodePtr& node) OTMLNodeList OTMLNode::children() const
{ {
for(const OTMLNodePtr& child : node->childNodes()) { OTMLNodeList children;
OTMLNodePtr newNode(new OTMLNode); for(const OTMLNodePtr& child : m_children)
newNode->setUnique(child->isUnique()); if(!child->isNull())
newNode->setTag(child->tag()); children.push_back(child);
newNode->setValue(child->value()); return children;
addChild(newNode);
newNode->merge(child);
}
} }
OTMLNodePtr OTMLNode::clone() const OTMLNodePtr OTMLNode::clone() const
{ {
OTMLNodePtr myClone(new OTMLNode); OTMLNodePtr myClone(new OTMLNode);
myClone->setTag(tag()); myClone->setTag(m_tag);
myClone->setValue(value()); myClone->setValue(m_value);
myClone->setUnique(isUnique()); myClone->setUnique(m_unique);
for(OTMLNodePtr child : childNodes()) myClone->setNull(m_null);
myClone->setSource(m_source);
for(const OTMLNodePtr& child : m_children)
myClone->addChild(child->clone()); myClone->addChild(child->clone());
return myClone; return myClone;
} }
@ -223,3 +159,4 @@ std::string OTMLNode::emit()
{ {
return OTMLEmitter::emitNode(shared_from_this(), 0); return OTMLEmitter::emitNode(shared_from_this(), 0);
} }

@ -2,214 +2,138 @@
#define OTMLNODE_H #define OTMLNODE_H
#include "declarations.h" #include "declarations.h"
#include "otmlexception.h"
class OTMLNode : public std::enable_shared_from_this<OTMLNode> class OTMLNode : public std::enable_shared_from_this<OTMLNode>
{ {
public: public:
OTMLNode();
virtual ~OTMLNode() { } virtual ~OTMLNode() { }
std::string value() const; static OTMLNodePtr create(std::string tag = fw::empty_string, bool unique = false);
std::string tag() const; static OTMLNodePtr create(std::string tag, std::string value);
int size() const;
OTMLNodePtr parent() const; std::string tag() const { return m_tag; }
const OTMLNodeList& childNodes() const; int size() const { return m_children.size(); }
std::string source() const; OTMLNodePtr parent() const { return m_parent.lock(); }
std::string source() const { return m_source; }
bool hasTag() const;
bool hasValue() const; bool isUnique() const { return m_unique; }
bool hasChildNodes() const; bool isNull() const { return m_null; }
bool hasChild(const std::string& childTag) const;
bool hasChild(int index) const; bool hasTag() const { return !m_tag.empty(); }
bool isUnique() const; bool hasValue() const { return !m_value.empty(); }
bool hasChildren() const;
void setTag(std::string tag); bool hasChildAt(const std::string& childTag) { return !!get(childTag); }
void setValue(const std::string& value); bool hasChildAtIndex(int childIndex) { return !!getIndex(childIndex); }
void setParent(const OTMLNodePtr& parent);
void setUnique(bool unique = true); void setTag(std::string tag) { m_tag = tag; }
void setSource(const std::string& source); void setValue(const std::string& value) { m_value = value; }
void setNull(bool null) { m_null = null; }
/// Same as get but if the child node doesn't exist throws an OTMLException void setUnique(bool unique) { m_unique = unique; }
OTMLNodePtr at(const std::string& childTag); void setParent(const OTMLNodePtr& parent) { m_parent = parent; }
OTMLNodePtr at(int childIndex); void setSource(const std::string& source) { m_source = source; }
/// Get a child node, if doesn't exists returns nullptr
OTMLNodePtr get(const std::string& childTag) const; OTMLNodePtr get(const std::string& childTag) const;
OTMLNodePtr get(int childIndex) const; OTMLNodePtr getIndex(int childIndex) const;
OTMLNodePtr at(const std::string& childTag);
OTMLNodePtr atIndex(int childIndex);
void addChild(const OTMLNodePtr& newChild); void addChild(const OTMLNodePtr& newChild);
bool removeChild(const OTMLNodePtr& oldChild); bool removeChild(const OTMLNodePtr& oldChild);
bool replaceChild(const OTMLNodePtr& oldChild, const OTMLNodePtr& newChild); bool replaceChild(const OTMLNodePtr& oldChild, const OTMLNodePtr& newChild);
/// Remove all children
void clear();
/// Recursively copy children from another node to this node
void merge(const OTMLNodePtr& node); void merge(const OTMLNodePtr& node);
void clear();
/// Recursively clone this node into a new one OTMLNodeList children() const;
OTMLNodePtr clone() const; OTMLNodePtr clone() const;
/// Emits this node to a std::string template<typename T = std::string>
virtual std::string emit(); T value();
template<typename T = std::string>
template<typename T> T valueAt(const std::string& childTag);
T read(); template<typename T = std::string>
T valueAtIndex(int childIndex);
template<typename T> template<typename T = std::string>
T read(const T& def); T valueAt(const std::string& childTag, const T& def);
template<typename T = std::string>
template<typename T, typename U> T valueAtIndex(int childIndex, const T& def);
T readAt(const U& childIdentifier);
template<typename T, typename U>
T readAt(const U& childIdentifier, const T& def);
template<typename T> template<typename T>
void write(const T& v); void write(const T& v);
template<typename T> template<typename T>
void writeAt(const std::string& childTag, const T& v); void writeAt(const std::string& childTag, const T& v);
template<typename T> template<typename T>
void writeIn(const T& v); void writeIn(const T& v);
private: virtual std::string emit();
protected:
OTMLNode() : m_unique(false), m_null(false) { }
OTMLNodeList m_children;
OTMLNodeWeakPtr m_parent;
std::string m_tag; std::string m_tag;
std::string m_value; std::string m_value;
std::string m_source; std::string m_source;
bool m_unique; bool m_unique;
OTMLNodeList m_childNodes; bool m_null;
OTMLNodeWeakPtr m_parent;
}; };
// templates for reading values #include "otmlexception.h"
template<typename T> template<typename T>
T OTMLNode::read() { T OTMLNode::value() {
T v; T ret;
if(!from_otmlnode(shared_from_this(), v)) if(!fw::cast(m_value, ret))
throw OTMLException(shared_from_this(), throw OTMLException(shared_from_this(), fw::mkstr("failed to cast node value to type '", fw::demangle_type<T>(), "'"));
fw::mkstr("failed to cast node value to type '", fw::demangle_type<T>(), "'")); return ret;
return v;
} }
template<typename T> template<typename T>
T OTMLNode::read(const T& def) { T OTMLNode::valueAt(const std::string& childTag) {
if(hasValue()) OTMLNodePtr node = at(childTag);
return read<T>(); return node->value<T>();
return def;
} }
template<typename T, typename U> template<typename T>
T OTMLNode::readAt(const U& childIdentifier) { T OTMLNode::valueAtIndex(int childIndex) {
OTMLNodePtr child = at(childIdentifier); OTMLNodePtr node = atIndex(childIndex);
return child->read<T>(); return node->value<T>();
} }
template<typename T, typename U> template<typename T>
T OTMLNode::readAt(const U& childIdentifier, const T& def) { T OTMLNode::valueAt(const std::string& childTag, const T& def) {
OTMLNodePtr child = get(childIdentifier); if(OTMLNodePtr node = get(childTag))
if(!child) if(!node->isNull())
return def; return node->value<T>();
return child->read<T>(def); return def;
} }
template<typename T>
T OTMLNode::valueAtIndex(int childIndex, const T& def) {
if(OTMLNodePtr node = getIndex(childIndex))
return node->value<T>();
return def;
}
// templates for writing values
template<typename T> template<typename T>
void OTMLNode::write(const T& v) { void OTMLNode::write(const T& v) {
to_otmlnode(shared_from_this(), v); m_value = fw::safe_cast<std::string>(v);
} }
template<typename T> template<typename T>
void OTMLNode::writeAt(const std::string& childTag, const T& v) { void OTMLNode::writeAt(const std::string& childTag, const T& v) {
OTMLNodePtr child = get(childTag); OTMLNodePtr child = OTMLNode::create(childTag);
bool created = false;
if(!child) {
child = OTMLNodePtr(new OTMLNode);
child->setTag(childTag);
child->setUnique();
created = true;
}
child->write<T>(v); child->write<T>(v);
if(created) addChild(child);
addChild(child);
} }
template<typename T> template<typename T>
void OTMLNode::writeIn(const T& v) { void OTMLNode::writeIn(const T& v) {
OTMLNodePtr child = OTMLNodePtr(new OTMLNode); OTMLNodePtr child = OTMLNode::create();
child->write<T>(v); child->write<T>(v);
addChild(child); 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 #endif

@ -1,5 +1,6 @@
#include "otmlparser.h" #include "otmlparser.h"
#include "otmldocument.h" #include "otmldocument.h"
#include "otmlexception.h"
OTMLParser::OTMLParser(OTMLDocumentPtr doc, std::istream& in) : OTMLParser::OTMLParser(OTMLDocumentPtr doc, std::istream& in) :
currentDepth(0), currentLine(0), currentDepth(0), currentLine(0),
@ -52,6 +53,9 @@ void OTMLParser::parseLine(std::string line)
{ {
int depth = getLineDepth(line); int depth = getLineDepth(line);
if(depth == -1)
return;
// remove line sides spaces // remove line sides spaces
boost::trim(line); boost::trim(line);
@ -87,6 +91,7 @@ void OTMLParser::parseNode(const std::string& data)
std::string tag; std::string tag;
std::string value; std::string value;
std::size_t dotsPos = data.find_first_of(':'); std::size_t dotsPos = data.find_first_of(':');
int nodeLine = currentLine;
// node that has no tag and may have a value // node that has no tag and may have a value
if(!data.empty() && data[0] == '-') { if(!data.empty() && data[0] == '-') {
@ -150,11 +155,18 @@ void OTMLParser::parseNode(const std::string& data)
} }
// create the node // create the node
OTMLNodePtr node(new OTMLNode); OTMLNodePtr node = OTMLNode::create(tag);
node->setUnique(dotsPos != std::string::npos); node->setUnique(dotsPos != std::string::npos);
node->setTag(tag); node->setTag(tag);
node->setValue(value); node->setSource(doc->source() + ":" + fw::unsafe_cast<std::string>(nodeLine));
node->setSource(doc->source() + ":" + fw::safe_cast<std::string>(currentLine));
// ~ is considered the null value
if(value == "~")
node->setNull(true);
else
node->setValue(value);
currentParent->addChild(node); currentParent->addChild(node);
previousNode = node; previousNode = node;
} }

@ -37,10 +37,10 @@ void UIButton::loadStyleFromOTML(const OTMLNodePtr& styleNode)
if(OTMLNodePtr node = styleNode->get("state.down")) if(OTMLNodePtr node = styleNode->get("state.down"))
loadStateStyle(m_statesStyle[ButtonDown], node); loadStateStyle(m_statesStyle[ButtonDown], node);
m_text = styleNode->readAt("text", fw::empty_string); m_text = styleNode->valueAt("text", fw::empty_string);
if(OTMLNodePtr node = styleNode->get("onClick")) { if(OTMLNodePtr node = styleNode->get("onClick")) {
g_lua.loadFunction(node->read<std::string>(), "@" + node->source() + "[" + node->tag() + "]"); g_lua.loadFunction(node->value<std::string>(), "@" + node->source() + "[" + node->tag() + "]");
luaSetField("onClick"); luaSetField("onClick");
} }
} }
@ -51,9 +51,9 @@ void UIButton::loadStateStyle(ButtonStateStyle& stateStyle, const OTMLNodePtr& s
stateStyle.image = BorderImage::loadFromOTML(node); stateStyle.image = BorderImage::loadFromOTML(node);
if(OTMLNodePtr node = stateStyleNode->get("image")) if(OTMLNodePtr node = stateStyleNode->get("image"))
stateStyle.image = Image::loadFromOTML(node); stateStyle.image = Image::loadFromOTML(node);
stateStyle.textTranslate = stateStyleNode->readAt("text-translate", Point()); stateStyle.textTranslate = stateStyleNode->valueAt("text-translate", Point());
stateStyle.color = stateStyleNode->readAt("font-color", m_fontColor); stateStyle.color = stateStyleNode->valueAt("font-color", m_fontColor);
stateStyle.color = stateStyleNode->readAt("color", m_color); stateStyle.color = stateStyleNode->valueAt("color", m_color);
} }
void UIButton::render() void UIButton::render()

@ -18,10 +18,10 @@ void UILabel::loadStyleFromOTML(const OTMLNodePtr& styleNode)
{ {
UIWidget::loadStyleFromOTML(styleNode); UIWidget::loadStyleFromOTML(styleNode);
m_text = styleNode->readAt("text", m_text); m_text = styleNode->valueAt("text", m_text);
if(styleNode->hasChild("align")) if(styleNode->hasChildAt("align"))
m_align = fw::translateAlignment(styleNode->readAt<std::string>("align")); m_align = fw::translateAlignment(styleNode->valueAt("align"));
// auto resize if no size supplied // auto resize if no size supplied
if(!m_text.empty() && !getGeometry().isValid()) if(!m_text.empty() && !getGeometry().isValid())

@ -25,7 +25,7 @@ void UILineEdit::loadStyleFromOTML(const OTMLNodePtr& styleNode)
{ {
UIWidget::loadStyleFromOTML(styleNode); UIWidget::loadStyleFromOTML(styleNode);
setText(styleNode->readAt("text", getText())); setText(styleNode->valueAt("text", getText()));
} }
void UILineEdit::render() void UILineEdit::render()

@ -93,7 +93,7 @@ bool UIManager::importStyles(const std::string& file)
try { try {
OTMLDocumentPtr doc = OTMLDocument::parse(file); OTMLDocumentPtr doc = OTMLDocument::parse(file);
for(const OTMLNodePtr& styleNode : doc->childNodes()) for(const OTMLNodePtr& styleNode : doc->children())
importStyleFromOTML(styleNode); importStyleFromOTML(styleNode);
return true; return true;
} catch(std::exception& e) { } catch(std::exception& e) {
@ -129,14 +129,14 @@ void UIManager::importStyleFromOTML(const OTMLNodePtr& styleNode)
OTMLNodePtr UIManager::getStyle(const std::string& styleName) OTMLNodePtr UIManager::getStyle(const std::string& styleName)
{ {
if(boost::starts_with(styleName, "UI")) { if(boost::starts_with(styleName, "UI")) {
OTMLNodePtr node(new OTMLNode()); OTMLNodePtr node = OTMLNode::create();
node->writeAt("__widgetType", styleName); node->writeAt("__widgetType", styleName);
return node; return node;
} }
auto it = m_styles.find(styleName); auto it = m_styles.find(styleName);
if(it == m_styles.end()) if(it == m_styles.end())
throw std::logic_error(fw::mkstr("style '", styleName, "' is not a defined style")); throw std::runtime_error(fw::mkstr("style '", styleName, "' is not a defined style"));
return m_styles[styleName]; return m_styles[styleName];
} }
@ -145,7 +145,7 @@ UIWidgetPtr UIManager::loadUI(const std::string& file)
try { try {
OTMLDocumentPtr doc = OTMLDocument::parse(file); OTMLDocumentPtr doc = OTMLDocument::parse(file);
UIWidgetPtr widget; UIWidgetPtr widget;
for(const OTMLNodePtr& node : doc->childNodes()) { for(const OTMLNodePtr& node : doc->children()) {
std::string tag = node->tag(); std::string tag = node->tag();
// import styles in these files too // import styles in these files too
@ -153,7 +153,7 @@ UIWidgetPtr UIManager::loadUI(const std::string& file)
importStyleFromOTML(node); importStyleFromOTML(node);
else { else {
if(widget) if(widget)
throw OTMLException(node, "cannot have multiple main widgets in .otui files"); throw std::runtime_error("cannot have multiple main widgets in .otui files");
widget = loadWidgetFromOTML(node); widget = loadWidgetFromOTML(node);
} }
} }
@ -172,7 +172,7 @@ UIWidgetPtr UIManager::loadWidgetFromOTML(const OTMLNodePtr& widgetNode)
OTMLNodePtr styleNode = getStyle(widgetNode->tag())->clone(); OTMLNodePtr styleNode = getStyle(widgetNode->tag())->clone();
styleNode->merge(widgetNode); styleNode->merge(widgetNode);
std::string widgetType = styleNode->readAt<std::string>("__widgetType"); std::string widgetType = styleNode->valueAt("__widgetType");
UIWidgetPtr widget; UIWidgetPtr widget;
if(widgetType == "UIWidget") if(widgetType == "UIWidget")
@ -191,7 +191,7 @@ UIWidgetPtr UIManager::loadWidgetFromOTML(const OTMLNodePtr& widgetNode)
widget->loadStyleFromOTML(styleNode); widget->loadStyleFromOTML(styleNode);
widget->updateGeometry(); widget->updateGeometry();
for(const OTMLNodePtr& childNode : widgetNode->childNodes()) { for(const OTMLNodePtr& childNode : widgetNode->children()) {
if(!childNode->isUnique()) if(!childNode->isUnique())
widget->addChild(loadWidgetFromOTML(childNode)); widget->addChild(loadWidgetFromOTML(childNode));
} }

@ -103,7 +103,7 @@ void UIWidget::loadStyleFromOTML(const OTMLNodePtr& styleNode)
assert(!m_destroyed); assert(!m_destroyed);
// load styles used by all widgets // load styles used by all widgets
for(const OTMLNodePtr& node : styleNode->childNodes()) { for(const OTMLNodePtr& node : styleNode->children()) {
// id // id
if(node->tag() == "id") { if(node->tag() == "id") {
setId(node->value()); setId(node->value());
@ -121,48 +121,48 @@ void UIWidget::loadStyleFromOTML(const OTMLNodePtr& styleNode)
} }
// font color // font color
else if(node->tag() == "font-color") { else if(node->tag() == "font-color") {
setFontColor(node->read<Color>()); setFontColor(node->value<Color>());
} }
// color // color
else if(node->tag() == "color") { else if(node->tag() == "color") {
setColor(node->read<Color>()); setColor(node->value<Color>());
} }
// opacity // opacity
else if(node->tag() == "opacity") { else if(node->tag() == "opacity") {
setOpacity(node->read<int>()); setOpacity(node->value<int>());
} }
// size // size
else if(node->tag() == "size") { else if(node->tag() == "size") {
resize(node->read<Size>()); resize(node->value<Size>());
} }
else if(node->tag() == "width") { else if(node->tag() == "width") {
setWidth(node->read<int>()); setWidth(node->value<int>());
} }
else if(node->tag() == "height") { else if(node->tag() == "height") {
setHeight(node->read<int>()); setHeight(node->value<int>());
} }
// position // position
else if(node->tag() == "position") { else if(node->tag() == "position") {
move(node->read<Point>()); move(node->value<Point>());
} }
else if(node->tag() == "x") { else if(node->tag() == "x") {
setX(node->read<int>()); setX(node->value<int>());
} }
else if(node->tag() == "y") { else if(node->tag() == "y") {
setY(node->read<int>()); setY(node->value<int>());
} }
// margins // margins
else if(node->tag() == "margin.left") { else if(node->tag() == "margin.left") {
setMarginLeft(node->read<int>()); setMarginLeft(node->value<int>());
} }
else if(node->tag() == "margin.right") { else if(node->tag() == "margin.right") {
setMarginRight(node->read<int>()); setMarginRight(node->value<int>());
} }
else if(node->tag() == "margin.top") { else if(node->tag() == "margin.top") {
setMarginTop(node->read<int>()); setMarginTop(node->value<int>());
} }
else if(node->tag() == "margin.bottom") { else if(node->tag() == "margin.bottom") {
setMarginBottom(node->read<int>()); setMarginBottom(node->value<int>());
} }
// anchors // anchors
else if(boost::starts_with(node->tag(), "anchors.")) { else if(boost::starts_with(node->tag(), "anchors.")) {
@ -193,7 +193,7 @@ void UIWidget::loadStyleFromOTML(const OTMLNodePtr& styleNode)
} }
} }
else if(node->tag() == "onLoad") { else if(node->tag() == "onLoad") {
g_lua.loadFunction(node->read<std::string>(), "@" + node->source() + "[" + node->tag() + "]"); g_lua.loadFunction(node->value<std::string>(), "@" + node->source() + "[" + node->tag() + "]");
luaSetField("onLoad"); luaSetField("onLoad");
} }
} }
@ -437,8 +437,12 @@ UIWidgetPtr UIWidget::recursiveGetChildById(const std::string& childId)
for(const UIWidgetPtr& child : m_children) { for(const UIWidgetPtr& child : m_children) {
if(child->getId() == childId) if(child->getId() == childId)
return child; return child;
else }
return child->recursiveGetChildById(childId); for(const UIWidgetPtr& child : m_children) {
if(UIWidgetPtr subChild = child->recursiveGetChildById(childId)) {
if(subChild->getId() == childId)
return subChild;
}
} }
} }
return nullptr; return nullptr;
@ -522,6 +526,9 @@ void UIWidget::addChild(const UIWidgetPtr& childToAdd)
{ {
assert(!m_destroyed); assert(!m_destroyed);
if(!childToAdd)
return;
assert(!hasChild(childToAdd)); assert(!hasChild(childToAdd));
m_children.push_back(childToAdd); m_children.push_back(childToAdd);
childToAdd->setParent(asUIWidget()); childToAdd->setParent(asUIWidget());
@ -538,6 +545,9 @@ void UIWidget::removeChild(const UIWidgetPtr& childToRemove)
{ {
assert(!m_destroyed); assert(!m_destroyed);
if(!childToRemove)
return;
// defocus if needed // defocus if needed
if(m_focusedChild == childToRemove) if(m_focusedChild == childToRemove)
focusChild(nullptr, ActiveFocusReason); focusChild(nullptr, ActiveFocusReason);

@ -23,9 +23,9 @@ void UIWindow::loadStyleFromOTML(const OTMLNodePtr& styleNode)
if(OTMLNodePtr headNode = styleNode->get("head")) { if(OTMLNodePtr headNode = styleNode->get("head")) {
if(OTMLNodePtr node = headNode->get("border-image")) if(OTMLNodePtr node = headNode->get("border-image"))
m_headImage = BorderImage::loadFromOTML(node); m_headImage = BorderImage::loadFromOTML(node);
m_headHeight = headNode->readAt("height", m_headImage->getDefaultSize().height()); m_headHeight = headNode->valueAt("height", m_headImage->getDefaultSize().height());
m_headMargin = headNode->readAt("margin", 0); m_headMargin = headNode->valueAt("margin", 0);
m_titleAlign = fw::translateAlignment(headNode->readAt("text align", std::string("center"))); m_titleAlign = fw::translateAlignment(headNode->valueAt("text align", std::string("center")));
} else { } else {
m_headHeight = 0; m_headHeight = 0;
m_headMargin = 0; m_headMargin = 0;
@ -37,7 +37,7 @@ void UIWindow::loadStyleFromOTML(const OTMLNodePtr& styleNode)
m_bodyImage = BorderImage::loadFromOTML(node); m_bodyImage = BorderImage::loadFromOTML(node);
} }
m_title = styleNode->readAt("title", fw::empty_string); m_title = styleNode->valueAt("title", fw::empty_string);
} }
void UIWindow::render() void UIWindow::render()

@ -9,7 +9,7 @@ typedef uint32 RGBA;
class Color class Color
{ {
public: public:
Color() : color(0) { } Color() : color(0xFFFFFFFF) { }
Color(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) : color(((a & 0xff)<<24) | ((b & 0xff)<<16) | ((g & 0xff)<<8) | (r & 0xff)) { } Color(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) : color(((a & 0xff)<<24) | ((b & 0xff)<<16) | ((g & 0xff)<<8) | (r & 0xff)) { }
Color(const Color& other) : color(other.color) { } Color(const Color& other) : color(other.color) { }
Color(RGBA rgba) : color(rgba) { } Color(RGBA rgba) : color(rgba) { }

@ -4,11 +4,11 @@
DatManager g_dat; DatManager g_dat;
bool DatManager::load(const std::string& filename) bool DatManager::load(const std::string& file)
{ {
try { try {
std::stringstream fin; std::stringstream fin;
g_resources.loadFile(filename, fin); g_resources.loadFile(file, fin);
m_signature = fw::getu32(fin); m_signature = fw::getu32(fin);
int numItems = fw::getu16(fin); int numItems = fw::getu16(fin);
@ -34,7 +34,7 @@ bool DatManager::load(const std::string& filename)
return true; return true;
} catch(std::exception& e) { } catch(std::exception& e) {
logError(e.what()); logError("ERROR: failed to load dat from '", file, "': ", e.what());
return false; return false;
} }
} }
@ -87,11 +87,9 @@ void DatManager::parseThingAttributes(std::stringstream& fin, ThingAttributes& t
void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes& thingAttributes, uint8 opt) void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes& thingAttributes, uint8 opt)
{ {
uint8 read_byte;
uint16 read_short;
switch(opt) { switch(opt) {
case 0x00: // Ground tile case 0x00: // Ground tile
fin.read((char*)&thingAttributes.speed, 2); thingAttributes.speed = fw::getu16(fin);
thingAttributes.group = THING_GROUP_GROUND; thingAttributes.group = THING_GROUP_GROUND;
break; break;
case 0x01: // All OnTop case 0x01: // All OnTop
@ -120,16 +118,16 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes
case 0x08: // Writtable case 0x08: // Writtable
thingAttributes.group = THING_GROUP_WRITEABLE; thingAttributes.group = THING_GROUP_WRITEABLE;
thingAttributes.readable = true; thingAttributes.readable = true;
fin.read((char*)&thingAttributes.subParam07, 2); thingAttributes.subParam08 = fw::getu16(fin);
break; break;
case 0x09: // Writtable once case 0x09: // Writtable once
// Writtable objects that can't be edited by players // Writtable objects that can't be edited by players
thingAttributes.readable = true; thingAttributes.readable = true;
fin.read((char*)&thingAttributes.subParam08, 2); thingAttributes.subParam08 = fw::getu16(fin);
break; break;
case 0x0A: // Fluid containers case 0x0A: // Fluid containers
fin.read((char*)&read_byte, 1);
thingAttributes.group = THING_GROUP_FLUID; thingAttributes.group = THING_GROUP_FLUID;
fw::getu8(fin);
break; break;
case 0x0B: // Splashes case 0x0B: // Splashes
thingAttributes.group = THING_GROUP_SPLASH; thingAttributes.group = THING_GROUP_SPLASH;
@ -162,8 +160,8 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes
thingAttributes.rotable = true; thingAttributes.rotable = true;
break; break;
case 0x15: // Light info case 0x15: // Light info
fin.read((char*)&thingAttributes.lightLevel, 2); thingAttributes.lightLevel = fw::getu16(fin);
fin.read((char*)&thingAttributes.lightColor, 2); thingAttributes.lightColor = fw::getu16(fin);
break; break;
case 0x16: case 0x16:
break; break;
@ -171,17 +169,12 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes
break; break;
case 0x18: // Thing must be drawed with offset case 0x18: // Thing must be drawed with offset
thingAttributes.hasHeight = true; thingAttributes.hasHeight = true;
fin.read((char*)&thingAttributes.xOffset, 1); thingAttributes.xOffset = fw::getu8(fin);
fin.read((char*)&thingAttributes.yOffset, 1); thingAttributes.yOffset = fw::getu8(fin);
fw::getu16(fin);
fin.read((char*)&read_short, 2);
break; break;
case 0x19: // pixels characters height case 0x19: // pixels characters height
fw::getu16(fin);
//fin.read((char*)&thingAttributes.xOffset, 1);
//fin.read((char*)&thingAttributes.yOffset, 1);
fin.read((char*)&read_short, 2);
//logDebug((int)thingAttributes.xOffset, " ", (int)thingAttributes.yOffset);
break; break;
case 0x1A: case 0x1A:
//thingAttributes.hasHeight = true; //thingAttributes.hasHeight = true;
@ -189,12 +182,11 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes
case 0x1B: case 0x1B:
break; break;
case 0x1C: // Minimap color case 0x1C: // Minimap color
fin.read((char*)&thingAttributes.miniMapColor, 2); thingAttributes.miniMapColor = fw::getu16(fin);
thingAttributes.hasMiniMapColor = true; thingAttributes.hasMiniMapColor = true;
break; break;
case 0x1D: // Unknown case 0x1D: // Unknown
fin.read((char*)&read_short, 2); if(fw::getu16(fin) == 1112)
if(read_short == 1112)
thingAttributes.readable = true; thingAttributes.readable = true;
break; break;
case 0x1E: case 0x1E:
@ -205,6 +197,6 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes
case 0x20: case 0x20:
break; break;
default: default:
throw std::logic_error(fw::mkstr("ERROR: unknown .dat byte code: 0x", std::hex, (int)opt)); throw std::runtime_error(fw::mkstr("unknown .dat byte code: 0x", std::hex, (int)opt));
} }
} }

@ -7,7 +7,7 @@
class DatManager class DatManager
{ {
public: public:
bool load(const std::string& filename); bool load(const std::string& file);
void unload(); void unload();
void parseThingAttributes(std::stringstream& fin, ThingAttributes& thingAttributes); void parseThingAttributes(std::stringstream& fin, ThingAttributes& thingAttributes);

@ -12,11 +12,16 @@ SpriteManager::SpriteManager()
bool SpriteManager::load(const std::string &filename) bool SpriteManager::load(const std::string &filename)
{ {
g_resources.loadFile(filename, m_fin); try {
m_signature = fw::getu32(m_fin); g_resources.loadFile(filename, m_fin);
m_spritesCount = fw::getu16(m_fin); m_signature = fw::getu32(m_fin);
m_sprites.resize(m_spritesCount); m_spritesCount = fw::getu16(m_fin);
return true; m_sprites.resize(m_spritesCount);
return true;
} catch(std::exception& e) {
logError(e.what());
return false;
}
} }
void SpriteManager::unload() void SpriteManager::unload()

Loading…
Cancel
Save