scripting rework

master
Eduardo Bart 13 years ago
parent f290b4f89c
commit c052723477

@ -16,6 +16,6 @@ end
-- here is where everything starts -- here is where everything starts
if not initialStateLoaded then if not initialStateLoaded then
onEnterMenuState() onEnterMenuState()
App.setOnClose(onApplicationClose) App.onClose = onApplicationClose
initialStateLoaded = true initialStateLoaded = true
end end

@ -1,9 +1,11 @@
function autoDestroyParent()
self.parent:destroy()
end
function messageBox(title, text) function messageBox(title, text)
local msgbox = UI.load("modules/messagebox/messagebox.yml") local msgBox = UI.load("modules/messagebox/messagebox.yml")
local label = msgbox:getChildById("messageBoxLabel") msgBox.locked = true
local okButton = msgbox:getChildById("messageBoxOkButton") msgBox.title = title
msgbox.locked = true msgBox:child("textLabel").text = text
msgbox.title = title msgBox:child("okButton").onClick = autoDestroyParent
label.text = text
okButton.onClick = function() msgbox:destroy() end
end end

@ -4,12 +4,12 @@ window#messageBoxWindow:
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
label#messageBoxLabel: label#textLabel:
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top anchors.top: parent.top
margin.top: 27 margin.top: 27
button#messageBoxOkButton: button#okButton:
text: Ok text: Ok
size: [43, 20] size: [43, 20]
anchors.right: parent.right anchors.right: parent.right

@ -44,7 +44,7 @@ public:
void setValue(const std::string &key, bool value); void setValue(const std::string &key, bool value);
void setValue(const std::string &key, int value); void setValue(const std::string &key, int value);
const std::string &getString(const std::string &key) const; const std::string& getString(const std::string &key) const;
float getFloat(const std::string &key) const; float getFloat(const std::string &key) const;
bool getBoolean(const std::string &key) const; bool getBoolean(const std::string &key) const;
int getInteger(const std::string &key) const; int getInteger(const std::string &key) const;

@ -30,6 +30,7 @@
#include <graphics/fonts.h> #include <graphics/fonts.h>
#include <ui/uicontainer.h> #include <ui/uicontainer.h>
#include <net/connection.h> #include <net/connection.h>
#include <script/luascript.h>
Engine g_engine; Engine g_engine;
@ -116,10 +117,12 @@ void Engine::run()
m_stopping = false; m_stopping = false;
m_running = false; m_running = false;
g_lua.collectGarbage();
// destroy root ui // destroy root ui
rootContainer->destroy(); rootContainer->destroy();
// poll remaning ui events // poll remaning events
g_engine.poll(); g_engine.poll();
} }
@ -130,8 +133,7 @@ void Engine::stop()
void Engine::onClose() void Engine::onClose()
{ {
if(m_onCloseCallback) g_dispatcher.addTask(boost::bind(&LuaScript::callModuleField, &g_lua, "App", "onClose"));
g_dispatcher.addTask(m_onCloseCallback);
} }
void Engine::onResize(const Size& size) void Engine::onResize(const Size& size)

@ -63,16 +63,12 @@ public:
/// Return the current ticks on this frame /// Return the current ticks on this frame
int getCurrentFrameTicks() const { return m_lastFrameTicks; } int getCurrentFrameTicks() const { return m_lastFrameTicks; }
void setOnClose(SimpleCallback onCloseCallback) { m_onCloseCallback = onCloseCallback; }
private: private:
bool m_stopping; bool m_stopping;
bool m_running; bool m_running;
bool m_calculateFps; bool m_calculateFps;
int m_lastFrameTicks; int m_lastFrameTicks;
SimpleCallback m_onCloseCallback;
}; };
extern Engine g_engine; extern Engine g_engine;

@ -53,7 +53,7 @@ public:
void appendCharacter(char c); void appendCharacter(char c);
void removeCharacter(bool right); void removeCharacter(bool right);
const std::string& getText() const { return m_text; } std::string getText() const { return m_text; }
Font *getFont() const { return m_font; } Font *getFont() const { return m_font; }
int getTextPos(Point pos); int getTextPos(Point pos);

@ -34,40 +34,44 @@ void registerLuaFunctions()
{ {
// App // App
g_lua.registerModule("App"); g_lua.registerModule("App");
g_lua.registerMemberFunction("App", "exit", &lua_App_exit); g_lua.registerMemberFunction("exit", &lua_App_exit);
g_lua.registerMemberFunction("App", "setOnClose", &lua_App_setOnClose);
// UI // UI
g_lua.registerModule("UI"); g_lua.registerClass("UI");
g_lua.registerMemberFunction("UI", "load", &lua_UI_load); g_lua.registerMemberFunction("load", &lua_UI_load);
g_lua.registerMemberFunction("UI", "getRootContainer", &lua_UI_getRootContainer); g_lua.registerMemberFunction("getRootContainer", &lua_UI_getRootContainer);
// UILayout // UILayout
g_lua.registerClass("UILayout"); g_lua.registerClass("UILayout");
// UIElement // UIElement
g_lua.registerClass("UIElement", "UILayout"); g_lua.registerClass("UIElement", "UILayout");
g_lua.registerMemberField("UIElement", "onLoad", NULL, &lua_UIElement_setOnLoad); g_lua.registerMemberField("id", &lua_UIElement_getId, &lua_UIElement_setId);
g_lua.registerMemberField("UIElement", "onDestroy", NULL, &lua_UIElement_setOnDestroy); g_lua.registerMemberField("enabled", &lua_UIElement_isEnabled, &lua_UIElement_setEnabled);
g_lua.registerMemberField("UIElement", "parent", &lua_UIElement_getParent); g_lua.registerMemberField("visible", &lua_UIElement_isVisible, &lua_UIElement_setVisible);
g_lua.registerMemberFunction("UIElement", "destroy", &lua_UIElement_destroy); g_lua.registerMemberField("focused", &lua_UIElement_isFocused, &lua_UIElement_setFocused);
g_lua.registerMemberField("parent", &lua_UIElement_getParent, &lua_UIElement_setParent);
g_lua.registerMemberField("locked", NULL, &lua_UIElement_setLocked);
g_lua.registerMemberFunction("destroy", &lua_UIElement_destroy);
// UIContainer // UIContainer
g_lua.registerClass("UIContainer", "UIElement"); g_lua.registerClass("UIContainer", "UIElement");
g_lua.registerMemberFunction("UIContainer", "getChildById", &lua_UIContainer_getChildById); g_lua.registerMemberFunction("child", &lua_UIContainer_getChild);
g_lua.registerMemberField("UIContainer", "locked", NULL, &lua_UIContainer_setLocked); g_lua.registerMemberFunction("children", &lua_UIContainer_getChildren);
// UILabel // UILabel
g_lua.registerClass("UILabel", "UIElement"); g_lua.registerClass("UILabel", "UIElement");
g_lua.registerMemberField("UILabel", "text", &lua_UILabel_getText, &lua_UILabel_setText); g_lua.registerMemberField("text", &lua_UILabel_getText, &lua_UILabel_setText);
// UIButton // UIButton
g_lua.registerClass("UIButton", "UIElement"); g_lua.registerClass("UIButton", "UIElement");
g_lua.registerMemberField("UIButton", "onClick", NULL, &lua_UIButton_setOnClick);
// UITextEdit
g_lua.registerClass("UITextEdit", "UIElement");
// UIWindow // UIWindow
g_lua.registerClass("UIWindow", "UIContainer"); g_lua.registerClass("UIWindow", "UIContainer");
g_lua.registerMemberField("UIWindow", "title", &lua_UIWindow_getTitle, &lua_UIWindow_setTitle); g_lua.registerMemberField("title", &lua_UIWindow_getTitle, &lua_UIWindow_setTitle);
} }
@ -80,12 +84,6 @@ int lua_App_exit()
return 1; return 1;
} }
int lua_App_setOnClose()
{
g_engine.setOnClose(g_lua.createSimpleFuncCallback(g_lua.popFunction()));
return 1;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// UI module // UI module
@ -122,63 +120,92 @@ int lua_UI_getRootContainer()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// UIElement // UIElement
int lua_UIElement_setOnLoad() int lua_UIElement_getId()
{ {
g_lua.insert(-2); if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance())) { g_lua.pushString(element->getId());
int funcRef = g_lua.popFunction(); else
element->associateLuaRef("onLoad", funcRef); g_lua.pushNil();
element->setOnLoad(g_lua.createScriptableSelfFuncCallback(funcRef));
} else
g_lua.pop();
return 1; return 1;
} }
int lua_UIElement_setOnDestroy() int lua_UIElement_setId()
{ {
g_lua.insert(-2); std::string id = g_lua.popString();
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance())) { if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
int funcRef = g_lua.popFunction(); element->setId(id);
element->associateLuaRef("onDestroy", funcRef); return 1;
element->setOnDestroy(g_lua.createScriptableSelfFuncCallback(funcRef)); }
}
int lua_UIElement_isEnabled()
{
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
g_lua.pushBoolean(element->isEnabled());
else else
g_lua.pop(); g_lua.pushNil();
return 1; return 1;
} }
int lua_UIElement_getParent() int lua_UIElement_setEnabled()
{ {
bool enabled = g_lua.popBoolean();
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance())) if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
g_lua.pushClassInstance(element->getParent()); element->setEnabled(enabled);
return 1;
}
int lua_UIElement_isVisible()
{
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
g_lua.pushBoolean(element->isVisible());
else else
g_lua.pushNil(); g_lua.pushNil();
return 1; return 1;
} }
int lua_UIElement_destroy() int lua_UIElement_setVisible()
{ {
bool visible = g_lua.popBoolean();
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance())) if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
element->destroy(); element->setVisible(visible);
g_dispatcher.addTask(boost::bind(&LuaScript::collectGarbage, &g_lua));
return 1; return 1;
} }
int lua_UIElement_isFocused()
{
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
g_lua.pushBoolean(element->isFocused());
else
g_lua.pushNil();
return 1;
}
//////////////////////////////////////////////////////////////////////////////// int lua_UIElement_setFocused()
// UIContainer {
bool focused = g_lua.popBoolean();
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
element->setFocused(focused);
return 1;
}
int lua_UIContainer_getChildById() int lua_UIElement_getParent()
{ {
std::string id = g_lua.popString(); if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
if(UIContainerPtr container = boost::dynamic_pointer_cast<UIContainer>(g_lua.popClassInstance())) g_lua.pushClassInstance(element->getParent());
g_lua.pushClassInstance(container->getChildById(id));
else else
g_lua.pushNil(); g_lua.pushNil();
return 1; return 1;
} }
int lua_UIContainer_setLocked() int lua_UIElement_setParent()
{
UIContainerPtr parent = boost::dynamic_pointer_cast<UIContainer>(g_lua.popClassInstance());
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
element->setParent(parent);
return 1;
}
int lua_UIElement_setLocked()
{ {
bool locked = g_lua.popBoolean(); bool locked = g_lua.popBoolean();
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance())) { if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance())) {
@ -194,6 +221,42 @@ int lua_UIContainer_setLocked()
return 1; return 1;
} }
int lua_UIElement_destroy()
{
if(UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(g_lua.popClassInstance()))
element->destroy();
g_dispatcher.addTask(boost::bind(&LuaScript::collectGarbage, &g_lua));
return 1;
}
////////////////////////////////////////////////////////////////////////////////
// UIContainer
int lua_UIContainer_getChild()
{
std::string id = g_lua.popString();
if(UIContainerPtr container = boost::dynamic_pointer_cast<UIContainer>(g_lua.popClassInstance()))
g_lua.pushClassInstance(container->getChildById(id));
else
g_lua.pushNil();
return 1;
}
int lua_UIContainer_getChildren()
{
if(UIContainerPtr container = boost::dynamic_pointer_cast<UIContainer>(g_lua.popClassInstance())) {
g_lua.newTable();
foreach(const UIElementPtr& child, container->getChildren()) {
g_lua.pushClassInstance(child);
if(child->getId().length())
g_lua.setField(child->getId());
}
} else
g_lua.pushNil();
return 1;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// UILabel // UILabel
@ -214,23 +277,6 @@ int lua_UILabel_getText()
return 1; return 1;
} }
////////////////////////////////////////////////////////////////////////////////
// UIButton
int lua_UIButton_setOnClick()
{
g_lua.insert(-2);
if(UIButtonPtr button = boost::dynamic_pointer_cast<UIButton>(g_lua.popClassInstance())) {
int funcRef = g_lua.popFunction();
button->associateLuaRef("onClick", funcRef);
button->setOnClick(g_lua.createScriptableSelfFuncCallback(funcRef));
} else
g_lua.pop();
return 1;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// UIWindow // UIWindow

@ -30,29 +30,39 @@
void registerLuaFunctions(); void registerLuaFunctions();
// global functions // App
int lua_App_exit(); int lua_App_exit();
int lua_App_setOnClose();
// UI
int lua_UI_load(); int lua_UI_load();
int lua_UI_getRootContainer(); int lua_UI_getRootContainer();
// UIElement // UIElement
int lua_UIElement_setOnLoad(); int lua_UIElement_getId();
int lua_UIElement_setOnDestroy(); int lua_UIElement_setId();
int lua_UIElement_isEnabled();
int lua_UIElement_setEnabled();
int lua_UIElement_isVisible();
int lua_UIElement_setVisible();
int lua_UIElement_isFocused();
int lua_UIElement_setFocused();
int lua_UIElement_getParent(); int lua_UIElement_getParent();
int lua_UIElement_setParent();
int lua_UIElement_setLocked();
int lua_UIElement_destroy(); int lua_UIElement_destroy();
void lua_UIElement_onLoad();
void lua_UIElement_onDestroy();
// UIContainer // UIContainer
int lua_UIContainer_getChildById(); int lua_UIContainer_getChild();
int lua_UIContainer_setLocked(); int lua_UIContainer_getChildren();
// UILabel // UILabel
int lua_UILabel_setText(); int lua_UILabel_setText();
int lua_UILabel_getText(); int lua_UILabel_getText();
// UIButton // UIButton
int lua_UIButton_setOnClick(); void lua_UIButton_onClick();
// UIWindow // UIWindow
int lua_UIWindow_setTitle(); int lua_UIWindow_setTitle();

@ -26,6 +26,7 @@
#include <script/luascript.h> #include <script/luascript.h>
#include <script/luafunctions.h> #include <script/luafunctions.h>
#include <core/resources.h> #include <core/resources.h>
#include <lua.hpp>
LuaScript g_lua; LuaScript g_lua;
@ -82,6 +83,7 @@ bool LuaScript::loadBuffer(const std::string& text, const std::string& what)
// check if is loaded as a function // check if is loaded as a function
if(lua_isfunction(L, -1) == 0) { if(lua_isfunction(L, -1) == 0) {
pop();
return false; return false;
} }
@ -95,20 +97,20 @@ bool LuaScript::loadBuffer(const std::string& text, const std::string& what)
return true; return true;
} }
int LuaScript::loadBufferAsFunction(const std::string& text, const std::string& what) bool LuaScript::loadBufferAsFunction(const std::string& text, const std::string& what)
{ {
int ret = luaL_loadbuffer(L, text.c_str(), text.length(), what.c_str()); int ret = luaL_loadbuffer(L, text.c_str(), text.length(), what.c_str());
if(ret != 0){ if(ret != 0){
reportError(popString()); reportError(popString());
return LUA_REFNIL; return false;
} }
// check if is loaded as a function if(!isFunction()) {
if(lua_isfunction(L, -1) == 0) { pop();
return LUA_REFNIL; return false;
} }
return popFunction(); return true;
} }
void LuaScript::reportError(const std::string& errorDesc, const char *funcName) void LuaScript::reportError(const std::string& errorDesc, const char *funcName)
@ -117,7 +119,7 @@ void LuaScript::reportError(const std::string& errorDesc, const char *funcName)
ss << "LUA Script ERROR: "; ss << "LUA Script ERROR: ";
if(funcName) if(funcName)
ss << " in " << funcName << "(): "; ss << " in " << funcName << "(): ";
ss << errorDesc << std::endl; ss << errorDesc;
logError(ss.str()); logError(ss.str());
} }
@ -144,19 +146,156 @@ void LuaScript::insert(int index)
lua_insert(L, index); lua_insert(L, index);
} }
int LuaScript::ref() void LuaScript::remove(int index)
{ {
return luaL_ref(L, LUA_REGISTRYINDEX); lua_remove(L, index);
} }
void LuaScript::unref(int ref) void LuaScript::releaseRef(int ref)
{ {
luaL_unref(L, LUA_REGISTRYINDEX, ref); luaL_unref(L, LUA_REGISTRYINDEX, ref);
} }
void LuaScript::getRef(int ref) void LuaScript::newTable()
{ {
lua_rawgeti(L, LUA_REGISTRYINDEX, ref); lua_newtable(L);
}
void LuaScript::setTable(int index)
{
lua_settable(L, index);
}
void *LuaScript::newUserdata(int size)
{
return lua_newuserdata(L, size);
}
void LuaScript::newMetatable(const std::string& name)
{
luaL_newmetatable(L, name.c_str());
}
void LuaScript::setMetatable(const std::string& name, int index)
{
luaL_getmetatable(L, name.c_str());
if(isNil())
reportError(f("could not retrive metatable %d", name));
else
lua_setmetatable(L, index < 0 ? index-1 : index);
}
void LuaScript::rawGet(const std::string& key)
{
pushString(key);
lua_rawget(L, -2);
}
void LuaScript::rawSet(const std::string& key)
{
pushString(key);
insert(-2);
lua_rawset(L, -3);
}
void LuaScript::getField(const std::string& key)
{
lua_getfield(L, -1, key.c_str());
}
void LuaScript::setField(const std::string& key)
{
lua_setfield(L, -2, key.c_str());
}
void LuaScript::getScriptableField(const ScriptablePtr& scriptable, const std::string& field)
{
if(scriptable) {
pushRef(scriptable->getLuaTableRef());
getField(field);
remove(-2);
} else
pushNil();
}
void LuaScript::setScriptableField(const ScriptablePtr& scriptable, const std::string& field)
{
if(scriptable) {
pushRef(scriptable->getLuaTableRef());
insert(-2);
setField(field);
}
pop();
}
void LuaScript::rawGetGlobalTableField(const std::string& globalTable, const std::string& key)
{
getGlobal(globalTable);
rawGet(key);
remove(-2);
}
void LuaScript::rawSetGlobalTableField(const std::string& globalTable, const std::string& key)
{
getGlobal(globalTable);
insert(-2);
rawSet(key);
pop();
}
void LuaScript::getGlobal(const std::string& key)
{
lua_getfield(L, LUA_GLOBALSINDEX, key.c_str());
}
void LuaScript::setGlobal(const std::string& key)
{
lua_setfield(L, LUA_GLOBALSINDEX, key.c_str());
}
bool LuaScript::isNil(int index)
{
return lua_isnil(L, index);
}
bool LuaScript::isBoolean(int index)
{
return lua_isboolean(L, index);
}
bool LuaScript::isNumber(int index)
{
return lua_isnumber(L, index);
}
bool LuaScript::isString(int index)
{
return lua_isstring(L, index);
}
bool LuaScript::isTable(int index)
{
return lua_istable(L, index);
}
bool LuaScript::isUserdata(int index)
{
return lua_isuserdata(L, index);
}
bool LuaScript::isFunction(int index)
{
return lua_isfunction(L, index);
}
bool LuaScript::isCFunction(int index)
{
return lua_iscfunction(L, index);
}
bool LuaScript::isLuaFunction(int index)
{
return isFunction(index) && !isCFunction(index);
} }
void LuaScript::pop(int n) void LuaScript::pop(int n)
@ -171,7 +310,7 @@ bool LuaScript::popBoolean()
return b; return b;
} }
int32_t LuaScript::popInteger() int LuaScript::popInteger()
{ {
double d = lua_tonumber(L, -1); double d = lua_tonumber(L, -1);
pop(); pop();
@ -187,6 +326,24 @@ std::string LuaScript::popString()
return str; return str;
} }
ScriptablePtr LuaScript::popClassInstance()
{
ScriptablePtr object;
if(isUserdata()) { // instances are store as userdata
object = *((ScriptablePtr *)lua_touserdata(L, -1));
if(!object)
reportErrorWithTraceback("attempt to retrive class instance from a object that is already expired");
} else if(!isNil()) // we accept nil values
reportErrorWithTraceback("couldn't retrive class instance, the value is not a scriptable type");
pop();
return object;
}
int LuaScript::popRef()
{
return luaL_ref(L, LUA_REGISTRYINDEX);
}
void LuaScript::pushNil() void LuaScript::pushNil()
{ {
lua_pushnil(L); lua_pushnil(L);
@ -207,55 +364,23 @@ void LuaScript::pushString(const std::string& str)
lua_pushstring(L, str.c_str()); lua_pushstring(L, str.c_str());
} }
void LuaScript::pushUserdata(void* ptr)
{
lua_pushlightuserdata(L, ptr);
}
void LuaScript::pushValue(int index)
{
lua_pushvalue(L, index);
}
void LuaScript::pushClassInstance(const ScriptablePtr& object) void LuaScript::pushClassInstance(const ScriptablePtr& object)
{ {
if(object) { if(object) {
// create weak_ptr to the scriptable object stored as userdata new(newUserdata(sizeof(ScriptablePtr))) ScriptablePtr(object);
new(lua_newuserdata(L, sizeof(ScriptablePtr))) ScriptablePtr(object); setMetatable(std::string(object->getScriptableName()) + "_mt");
// set object metatable } else
lua_getfield(L, LUA_REGISTRYINDEX, (std::string(object->getScriptableName()) + "_mt").c_str()); pushNil();
lua_setmetatable(L, -2);
} else {
lua_pushnil(L);
}
}
ScriptablePtr LuaScript::popClassInstance()
{
ScriptablePtr object;
if(lua_isuserdata(L, -1)) { // instances are store as userdata
object = *((ScriptablePtr *)lua_touserdata(L, -1));
if(!object)
reportErrorWithTraceback("attempt to retrive class instance from a object that is already expired");
} else if(!lua_isnil(L, -1)) // we accept nil values
reportErrorWithTraceback("couldn't retrive class instance, the value is not a scriptable type");
lua_pop(L, 1);
return object;
}
void LuaScript::pushFunction(int functionRef)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, functionRef);
} }
int LuaScript::popFunction() void LuaScript::pushValue(int index)
{ {
return ref(); lua_pushvalue(L, index);
} }
void LuaScript::releaseFunction(int functionRef) void LuaScript::pushRef(int ref)
{ {
unref(functionRef); lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
} }
void LuaScript::callFunction(int numArgs) void LuaScript::callFunction(int numArgs)
@ -277,53 +402,33 @@ void LuaScript::callFunction(int numArgs)
reportError("stack size changed!"); reportError("stack size changed!");
} }
SimpleCallback LuaScript::createSimpleFuncCallback(int funcRef) void LuaScript::callModuleField(const std::string& module, const std::string& field)
{ {
return [this, funcRef]() { g_lua.rawGetGlobalTableField(module, field);
pushFunction(funcRef); g_lua.callFunction();
callFunction();
};
}
boost::function<void(ScriptablePtr)> LuaScript::createScriptableSelfFuncCallback(int funcRef)
{
return [this, funcRef](ScriptablePtr scriptable) {
pushClassInstance(scriptable);
setGlobal("self");
pushFunction(funcRef);
callFunction();
pushNil();
setGlobal("self");
};
}
void LuaScript::setGlobal(const char *varName)
{
lua_setfield(L, LUA_GLOBALSINDEX, varName);
} }
void LuaScript::setupPackageLoader() void LuaScript::setupPackageLoader()
{ {
lua_getfield(L, LUA_GLOBALSINDEX, "package"); lua_getfield(L, LUA_GLOBALSINDEX, "package"); // package
lua_getfield(L, -1, "loaders"); lua_getfield(L, -1, "loaders"); // package.loaders, package
lua_remove(L, -2); lua_remove(L, -2); // package.loaders
lua_pushnil(L); lua_pushnil(L); // nil, package.loaders
int numLoaders = 0; int numLoaders = 0;
while(lua_next(L, -2) != 0) { while(lua_next(L, -2) != 0) {
lua_pop(L, 1); // value, key, package.loaders
lua_pop(L, 1); // key, package.loaders
numLoaders++; numLoaders++;
} }
lua_pushinteger(L, numLoaders + 1); lua_pushinteger(L, numLoaders + 1); // at, package.loaders
lua_pushcfunction(L, &LuaScript::luaPackageLoader); lua_pushcfunction(L, &LuaScript::luaPackageLoader); // luaPackageLoader, at, package.loaders
lua_rawset(L, -3); lua_rawset(L, -3); // package.loaders
lua_pop(L, 1); lua_pop(L, 1); // (empty)
} }
void LuaScript::registerClass(const std::string& klass, const std::string& baseClass) void LuaScript::registerClass(const std::string& klass, const std::string& baseClass)
{ {
// klass_mt = {} // mt = {}
lua_newtable(L); lua_newtable(L);
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, (klass + "_mt").c_str()); lua_setfield(L, LUA_REGISTRYINDEX, (klass + "_mt").c_str());
@ -344,35 +449,60 @@ void LuaScript::registerClass(const std::string& klass, const std::string& baseC
lua_pushcfunction(L, &LuaScript::luaGarbageCollectMetaMethod); lua_pushcfunction(L, &LuaScript::luaGarbageCollectMetaMethod);
lua_setfield(L, -2, "__gc"); lua_setfield(L, -2, "__gc");
// klass_mt.methods = { } // klass = { }
lua_newtable(L); lua_newtable(L);
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
lua_setfield(L, LUA_GLOBALSINDEX, klass.c_str()); lua_setfield(L, LUA_GLOBALSINDEX, klass.c_str());
// mt.methods = klass
lua_setfield(L, -2, "methods"); lua_setfield(L, -2, "methods");
// klass_mt.fieldmethods = { } // klass_fieldmethods = { }
lua_newtable(L); lua_newtable(L);
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
lua_setfield(L, LUA_GLOBALSINDEX, (klass + "_fieldmethods").c_str()); lua_setfield(L, LUA_GLOBALSINDEX, (klass + "_fieldmethods").c_str());
// mt.fieldmethods = klass_fieldmethods
lua_setfield(L, -2, "fieldmethods"); lua_setfield(L, -2, "fieldmethods");
if(baseClass.length()) { if(baseClass.length()) {
// klass_mt.base = baseClass_mt // get klass
lua_getfield(L, LUA_REGISTRYINDEX, (baseClass + "_mt").c_str()); lua_getfield(L, LUA_GLOBALSINDEX, klass.c_str());
lua_setfield(L, -2, "base");
// redirect = { __index = baseClass }
lua_newtable(L);
lua_getfield(L, LUA_GLOBALSINDEX, baseClass.c_str());
lua_setfield(L, -2, "__index");
// setmetatable(klass, redirect)
lua_setmetatable(L, -2);
lua_pop(L, 1);
// get klass_fieldmethods
lua_getfield(L, LUA_GLOBALSINDEX, (klass + "_fieldmethods").c_str());
// redirect = { __index = baseClass_fieldmethods }
lua_newtable(L);
lua_getfield(L, LUA_GLOBALSINDEX, (baseClass + "_fieldmethods").c_str());
lua_setfield(L, -2, "__index");
// setmetatable(klass_fieldmethods, redirect)
lua_setmetatable(L, -2);
} }
lua_pop(L, 1); lua_pop(L, 1);
m_currentClass = klass;
} }
void LuaScript::registerMemberField(const std::string& klass, const std::string& field, LuaScript::LuaCFunction getFunction, LuaScript::LuaCFunction setFunction) void LuaScript::registerMemberField(const std::string& field, LuaScript::LuaCFunction getFunction, LuaScript::LuaCFunction setFunction)
{ {
if(getFunction) { if(getFunction) {
int functionId = m_functions.size(); int functionId = m_functions.size();
m_functions.push_back(getFunction); m_functions.push_back(getFunction);
// push the class table // push the class table
lua_getfield(L, LUA_GLOBALSINDEX, (klass + "_fieldmethods").c_str()); lua_getfield(L, LUA_GLOBALSINDEX, (m_currentClass + "_fieldmethods").c_str());
// push the function id // push the function id
lua_pushnumber(L, functionId); lua_pushnumber(L, functionId);
// store id in the closure // store id in the closure
@ -388,7 +518,7 @@ void LuaScript::registerMemberField(const std::string& klass, const std::string&
m_functions.push_back(setFunction); m_functions.push_back(setFunction);
// push the class table // push the class table
lua_getfield(L, LUA_GLOBALSINDEX, (klass + "_fieldmethods").c_str()); lua_getfield(L, LUA_GLOBALSINDEX, (m_currentClass + "_fieldmethods").c_str());
// push the function id // push the function id
lua_pushnumber(L, functionId); lua_pushnumber(L, functionId);
// store id in the closure // store id in the closure
@ -400,13 +530,13 @@ void LuaScript::registerMemberField(const std::string& klass, const std::string&
} }
} }
void LuaScript::registerMemberFunction(const std::string& klass, const std::string& functionName, LuaCFunction function) void LuaScript::registerMemberFunction(const std::string& functionName, LuaCFunction function)
{ {
int functionId = m_functions.size(); int functionId = m_functions.size();
m_functions.push_back(function); m_functions.push_back(function);
// push the class table // push the class table
lua_getfield(L, LUA_GLOBALSINDEX, klass.c_str()); lua_getfield(L, LUA_GLOBALSINDEX, m_currentClass.c_str());
// push the function id // push the function id
lua_pushnumber(L, functionId); lua_pushnumber(L, functionId);
// store id in the closure // store id in the closure
@ -432,9 +562,11 @@ void LuaScript::registerGlobalFunction(const std::string& functionName, LuaCFunc
void LuaScript::registerModule(const std::string& module) void LuaScript::registerModule(const std::string& module)
{ {
// module = {} registerClass(module);
lua_newtable(L); // module table lua_getfield(L, LUA_GLOBALSINDEX, module.c_str());
lua_setfield(L, LUA_GLOBALSINDEX, module.c_str()); // register at globals index lua_getfield(L, LUA_REGISTRYINDEX, (module + "_mt").c_str());
lua_setmetatable(L, -2);
lua_pop(L, -1);
} }
int LuaScript::luaPackageLoader(lua_State* L) int LuaScript::luaPackageLoader(lua_State* L)
@ -452,50 +584,52 @@ int LuaScript::luaPackageLoader(lua_State* L)
int LuaScript::luaIndexMetaMethod(lua_State* L) int LuaScript::luaIndexMetaMethod(lua_State* L)
{ {
// stack: key, obj
std::string key = lua_tostring(L, -1); // key, obj std::string key = lua_tostring(L, -1); // key, obj
lua_pop(L, 1); // obj lua_pop(L, 1); // obj
lua_getmetatable(L, -1); // mt, obj lua_getmetatable(L, -1); // mt, obj
while(!lua_isnil(L, -1)) { lua_getfield(L, -1, "fieldmethods"); // fieldmethods, mt, obj
lua_getfield(L, -1, "fieldmethods"); // mt.fieldmethods, mt, obj lua_getfield(L, -1, ("get_" + key).c_str()); // get_method, fieldmethods, mt, obj
lua_getfield(L, -1, ("get_" + key).c_str()); // mt.fieldmethods[get_key], mt.fieldmethods, mt, obj lua_remove(L, -2); // get_method, mt, obj
lua_remove(L, -2); // mt.fieldmethods[get_key], mt, obj if(!lua_isnil(L, -1)) {
lua_remove(L, -2); // get_method, obj
lua_insert(L, -2); // obj, get_method
lua_pushcfunction(L, &LuaScript::luaErrorHandler); // errorfunc, obj,get_method
lua_insert(L, -3); // obj, get_method, errorfunc
int ret = lua_pcall(L, 1, 1, -3); // ret, errorfunc
if(ret != 0) {
g_lua.reportError(g_lua.popString()); // errofunc
lua_pop(L, 1); // (empty)
lua_pushnil(L); // nil
} else {
lua_remove(L, -2); // ret
}
return 1;
} else {
lua_pop(L, 1); // mt, obj
lua_getfield(L, -1, "methods"); // methods, mt, obj
lua_getfield(L, -1, key.c_str()); // method, methods, mt, obj
lua_remove(L, -2); // method, mt, obj
if(!lua_isnil(L, -1)) { if(!lua_isnil(L, -1)) {
lua_remove(L, -2); // mt.fieldmethods[get_key], obj lua_insert(L, -3); // obj, mt, method
lua_insert(L, -2); // obj, mt.fieldmethods[get_key] lua_pop(L, 2); // method
lua_pushcfunction(L, &LuaScript::luaErrorHandler); // errorfunc, obj, mt.fieldmethods[get_key]
lua_insert(L, -3); // obj, mt.fieldmethods[get_key], errorfunc
int ret = lua_pcall(L, 1, 1, -3); // ret, errorfunc
if(ret != 0) {
g_lua.reportError(g_lua.popString()); // errofunc
lua_pop(L, 1); // (empty)
lua_pushnil(L); // nil
} else {
lua_remove(L, -2); // ret
}
return 1; return 1;
} else {
lua_pop(L, 1); // mt, obj
lua_getfield(L, -1, "methods"); // mt.methods, mt, obj
lua_getfield(L, -1, key.c_str()); // mt.methods[key], mt.methods, mt, obj
lua_remove(L, -2); // mt.methods[key], mt, obj
if(!lua_isnil(L, -1)) {
lua_insert(L, -3);
lua_pop(L, 2);
return 1;
}
lua_pop(L, 1);
} }
lua_getfield(L, -1, "base"); // mt.base, mt, obj lua_pop(L, 1); // mt, obj
lua_remove(L, -2); // mt.base, obj
} }
lua_pop(L, 1); lua_pop(L, 1); // obj
ScriptablePtr scriptable = g_lua.popClassInstance(); // stack: obj
int refId = scriptable->getLuaRef(key); if(g_lua.isTable()) {
if(refId != -1) g_lua.rawGet(key);
g_lua.getRef(refId); g_lua.remove(-2);
else } else if(g_lua.isUserdata()) {
g_lua.getScriptableField(g_lua.popClassInstance(), key);
} else {
g_lua.pop();
g_lua.pushNil(); g_lua.pushNil();
g_lua.reportErrorWithTraceback("unknown type in newindex metamethod");
}
return 1; return 1;
} }
@ -503,39 +637,38 @@ int LuaScript::luaIndexMetaMethod(lua_State* L)
int LuaScript::luaNewIndexMetaMethod(lua_State* L) int LuaScript::luaNewIndexMetaMethod(lua_State* L)
{ {
// stack: value, key, obj // stack: value, key, obj
lua_insert(L, -2); lua_insert(L, -2); // key, value, obj
std::string key = lua_tostring(L, -1); std::string key = lua_tostring(L, -1);
lua_pop(L, 1); lua_pop(L, 1); // value, obj
lua_getmetatable(L, -2); lua_getmetatable(L, -2); // mt, value, obj
// stack: mt, value, obj lua_getfield(L, -1, "fieldmethods"); // fieldmethods, mt, value, obj
while(!lua_isnil(L, -1)) { lua_getfield(L, -1, ("set_" + key).c_str()); // set_method, fieldmethods, mt, value, obj
lua_getfield(L, -1, "fieldmethods"); lua_remove(L, -2); // set_method, mt, value, obj
lua_getfield(L, -1, ("set_" + key).c_str()); if(!lua_isnil(L, -1)) {
lua_remove(L, -2); // stack: set method, mt, value, obj lua_remove(L, -2); // set_method, value, obj
if(!lua_isnil(L, -1)) { lua_insert(L, -3); // value, obj, set_method
lua_remove(L, -2); // mt.fieldmethods[get_key], value, obj lua_pushcfunction(L, &LuaScript::luaErrorHandler); // errorfunc, value, obj, set_method
lua_insert(L, -3); // value, obj, mt.fieldmethods[get_key] lua_insert(L, -4); // value, obj, set_method, errorfunc
lua_pushcfunction(L, &LuaScript::luaErrorHandler); // errorfunc, value, obj, mt.fieldmethods[get_key] int ret = lua_pcall(L, 2, 0, -4); // errorfunc
lua_insert(L, -4); // value, obj, mt.fieldmethods[get_key], errorfunc if(ret != 0)
int ret = lua_pcall(L, 2, 0, -4); // errorfunc g_lua.reportError(g_lua.popString()); // errofunc
if(ret != 0) lua_pop(L, 1); // (empty)
g_lua.reportError(g_lua.popString()); // errofunc return 1;
lua_pop(L, 1); }
return 1; lua_pop(L, 2); // mt, value, obj
}
lua_pop(L, 1); // mt, value, obj // stack: value, obj
lua_getfield(L, -1, "base"); // mt.base, mt, value, obj g_lua.insert(-2);
lua_remove(L, -2); // mt.base, value, obj if(g_lua.isTable()) {
g_lua.insert(-2);
g_lua.rawSet(key);
g_lua.pop();
} else if(g_lua.isUserdata()) {
g_lua.setScriptableField(g_lua.popClassInstance(), key);
} else {
g_lua.pop(2);
g_lua.reportErrorWithTraceback("unknown type in index metamethod");
} }
// stack:
g_lua.pop(); // value, obj
g_lua.insert(-2); // obj, value
ScriptablePtr scriptable = g_lua.popClassInstance();
g_lua.pushValue(); // value, value
int refId = g_lua.ref();
scriptable->associateLuaRef(key, refId);
g_lua.pop();
return 1; return 1;
} }
@ -559,8 +692,10 @@ int LuaScript::luaEqualMetaMethod(lua_State* L)
int LuaScript::luaGarbageCollectMetaMethod(lua_State* L) int LuaScript::luaGarbageCollectMetaMethod(lua_State* L)
{ {
ScriptablePtr *objectRef = (ScriptablePtr *)lua_touserdata(L, -1); if(lua_isuserdata(L, -1)) {
objectRef->reset(); ScriptablePtr *objectRef = (ScriptablePtr *)lua_touserdata(L, -1);
objectRef->reset();
}
lua_pop(L, 1); lua_pop(L, 1);
return 1; return 1;
} }

@ -27,11 +27,12 @@
#include <prerequisites.h> #include <prerequisites.h>
#include <script/scriptable.h> #include <script/scriptable.h>
#include <lua.hpp>
#define reportFuncError(a) reportError(a, __FUNCTION__) #define reportFuncError(a) reportError(a, __FUNCTION__)
#define reportFuncErrorWithTraceback(a) reportErrorWithTraceback(a, __FUNCTION__) #define reportFuncErrorWithTraceback(a) reportErrorWithTraceback(a, __FUNCTION__)
struct lua_State;
class LuaScript class LuaScript
{ {
public: public:
@ -41,49 +42,73 @@ public:
void loadAllModules(); void loadAllModules();
bool loadFile(const std::string& fileName); bool loadFile(const std::string& fileName);
bool loadBuffer(const std::string& text, const std::string& what = "luaBuffer"); bool loadBuffer(const std::string& text, const std::string& what = "luaBuffer");
int loadBufferAsFunction(const std::string& text, const std::string& what = "luaBuffer"); bool loadBufferAsFunction(const std::string& text, const std::string& what = "luaBuffer");
void reportError(const std::string& errorDesc, const char *funcName = NULL); void reportError(const std::string& errorDesc, const char *funcName = NULL);
void reportErrorWithTraceback(const std::string& errorDesc, const char *funcName = NULL); void reportErrorWithTraceback(const std::string& errorDesc, const char *funcName = NULL);
void collectGarbage(); void collectGarbage();
int getStackSize(); int getStackSize();
void insert(int index); void insert(int index);
void remove(int index);
void releaseRef(int ref);
void newTable();
void setTable(int index = -3);
void *newUserdata(int size);
void newMetatable(const std::string& name);
void setMetatable(const std::string& name, int index = -1);
void rawGet(const std::string& key);
void rawSet(const std::string& key);
void getField(const std::string& key);
void setField(const std::string& key);
int ref(); void getScriptableField(const ScriptablePtr& scriptable, const std::string& field);
void unref(int ref); void setScriptableField(const ScriptablePtr& scriptable, const std::string& field);
void getRef(int ref);
void rawGetGlobalTableField(const std::string& globalTable, const std::string& key);
void rawSetGlobalTableField(const std::string& globalTable, const std::string& key);
void getGlobal(const std::string& key);
void setGlobal(const std::string& key);
bool isNil(int index = -1);
bool isBoolean(int index = -1);
bool isNumber(int index = -1);
bool isString(int index = -1);
bool isTable(int index = -1);
bool isUserdata(int index = -1);
bool isFunction(int index = -1);
bool isCFunction(int index = -1);
bool isLuaFunction(int index = -1);
void pop(int n = 1);
bool popBoolean();
int popInteger();
std::string popString();
ScriptablePtr popClassInstance();
int popRef();
void pushNil(); void pushNil();
void pushBoolean(bool b); void pushBoolean(bool b);
void pushInteger(int i); void pushInteger(int i);
void pushString(const std::string& str); void pushString(const std::string& str);
void pushUserdata(void* ptr); void pushClassInstance(const ScriptablePtr& object);
void pushValue(int index = -1); void pushValue(int index = -1);
void pushRef(int ref);
void pop(int n = 1);
bool popBoolean();
int32_t popInteger();
std::string popString();
void pushFunction(int functionRef);
int popFunction();
void releaseFunction(int functionRef);
void callFunction(int numArgs = 0); void callFunction(int numArgs = 0);
void callModuleField(const std::string& module, const std::string& field);
SimpleCallback createSimpleFuncCallback(int funcRef);
boost::function<void(ScriptablePtr)> createScriptableSelfFuncCallback(int funcRef);
void setGlobal(const char *varName);
void pushClassInstance(const ScriptablePtr& object);
ScriptablePtr popClassInstance();
typedef int (*LuaCFunction)(); typedef int (*LuaCFunction)();
void setupPackageLoader(); void setupPackageLoader();
void registerClass(const std::string& klass, const std::string& baseClass = ""); void registerClass(const std::string& klass, const std::string& baseClass = "");
void registerMemberField(const std::string& klass, const std::string& field, LuaCFunction getFunction, LuaCFunction setFunction = NULL); void registerMemberField(const std::string& field, LuaCFunction getFunction, LuaCFunction setFunction = NULL);
void registerMemberFunction(const std::string& klass, const std::string& functionName, LuaCFunction function); void registerMemberFunction(const std::string& functionName, LuaCFunction function);
void registerGlobalFunction(const std::string& functionName, LuaCFunction function); void registerGlobalFunction(const std::string& functionName, LuaCFunction function);
void registerModule(const std::string& module); void registerModule(const std::string& module);
@ -99,6 +124,7 @@ public:
private: private:
std::vector<LuaCFunction> m_functions; std::vector<LuaCFunction> m_functions;
std::string m_currentClass;
lua_State *L; lua_State *L;
}; };

@ -27,25 +27,34 @@
#include <script/luascript.h> #include <script/luascript.h>
#include <core/dispatcher.h> #include <core/dispatcher.h>
void Scriptable::associateLuaRef(const std::string& refName, int refId) int Scriptable::getLuaTableRef()
{ {
// check if there is already a ref with this name if(m_luaTableRef == -1) {
if(m_luaRefs.find(refName) != m_luaRefs.end()) g_lua.newTable();
g_lua.unref(m_luaRefs[refName]); m_luaTableRef = g_lua.popRef();
m_luaRefs[refName] = refId; }
return m_luaTableRef;
} }
int Scriptable::getLuaRef(const std::string& refName) void Scriptable::releaseLuaTableRef()
{ {
if(m_luaRefs.find(refName) != m_luaRefs.end()) if(m_luaTableRef != -1) {
return m_luaRefs[refName]; g_lua.releaseRef(m_luaTableRef);
return -1; m_luaTableRef = -1;
}
} }
void Scriptable::clearLuaRefs() void Scriptable::callLuaTableField(const std::string& field)
{ {
foreach(auto pair, m_luaRefs) { g_lua.pushClassInstance(shared_from_this());
g_lua.unref(pair.second); g_lua.setGlobal("self");
}
m_luaRefs.clear(); g_lua.getScriptableField(shared_from_this(), field);
if(g_lua.isFunction())
g_lua.callFunction();
else
g_lua.pop();
g_lua.pushNil();
g_lua.setGlobal("self");
} }

@ -30,14 +30,16 @@
class Scriptable : public boost::enable_shared_from_this<Scriptable> class Scriptable : public boost::enable_shared_from_this<Scriptable>
{ {
public: public:
Scriptable() : m_luaTableRef(-1) { }
virtual const char *getScriptableName() const { return NULL; } virtual const char *getScriptableName() const { return NULL; }
void associateLuaRef(const std::string& refName, int refId); int getLuaTableRef();
int getLuaRef(const std::string& refName); void releaseLuaTableRef();
void clearLuaRefs(); void callLuaTableField(const std::string& field);
private: private:
std::map<std::string, int> m_luaRefs; int m_luaTableRef;
}; };
typedef boost::shared_ptr<Scriptable> ScriptablePtr; typedef boost::shared_ptr<Scriptable> ScriptablePtr;

@ -33,8 +33,7 @@ void UIButton::onInputEvent(const InputEvent& event)
} else if(event.type == EV_MOUSE_LUP && m_state == UI::ButtonDown) { } else if(event.type == EV_MOUSE_LUP && m_state == UI::ButtonDown) {
m_state = UI::ButtonUp; m_state = UI::ButtonUp;
if(getRect().contains(event.mousePos)) { if(getRect().contains(event.mousePos)) {
if(m_onClickCallback) g_dispatcher.addTask(boost::bind(&Scriptable::callLuaTableField, shared_from_this(), "onClick"));
g_dispatcher.addTask(boost::bind(m_onClickCallback, asUIElement()));
} }
} }
} }

@ -42,18 +42,15 @@ public:
void onInputEvent(const InputEvent& event); void onInputEvent(const InputEvent& event);
void setText(const std::string& text) { m_text = text; } void setText(const std::string& text) { m_text = text; }
const std::string& getText() const { return m_text; } std::string getText() const { return m_text; }
UI::EButtonState getState() { return m_state; } UI::EButtonState getState() { return m_state; }
void setOnClick(const UIElementCallback& callback) { m_onClickCallback = callback; }
virtual const char *getScriptableName() const { return "UIButton"; } virtual const char *getScriptableName() const { return "UIButton"; }
private: private:
std::string m_text; std::string m_text;
UI::EButtonState m_state; UI::EButtonState m_state;
UIElementCallback m_onClickCallback;
}; };
#endif // UIBUTTON_H #endif // UIBUTTON_H

@ -54,13 +54,14 @@ UIContainerPtr& UIContainer::getRoot()
return rootContainer; return rootContainer;
} }
void UIContainer::addChild(UIElementPtr child) void UIContainer::addChild(const UIElementPtr& child)
{ {
m_children.push_back(child); m_children.push_back(child);
child->setParent(asUIContainer()); if(child->getParent() != asUIContainer())
child->setParent(asUIContainer());
} }
void UIContainer::removeChild(UIElementPtr child) void UIContainer::removeChild(const UIElementPtr& child)
{ {
// defocus if needed // defocus if needed
if(m_focusedElement == child) if(m_focusedElement == child)
@ -72,8 +73,16 @@ void UIContainer::removeChild(UIElementPtr child)
// remove from children list // remove from children list
m_children.remove(child); m_children.remove(child);
// child must have this container as parent if(child->getParent() == asUIContainer())
child->setParent(UIContainerPtr()); child->setParent(UIContainerPtr());
}
bool UIContainer::hasChild(const UIElementPtr& child)
{
auto it = std::find(m_children.begin(), m_children.end(), child);
if(it != m_children.end())
return true;
return false;
} }
UIElementPtr UIContainer::getChildById(const std::string& id) UIElementPtr UIContainer::getChildById(const std::string& id)
@ -201,19 +210,15 @@ void UIContainer::focusNextElement()
setFocusedElement(element); setFocusedElement(element);
} }
void UIContainer::setFocusedElement(UIElementPtr focusedElement) void UIContainer::setFocusedElement(const UIElementPtr& focusedElement)
{ {
if(focusedElement != m_focusedElement) { if(focusedElement != m_focusedElement) {
if(m_focusedElement) { if(m_focusedElement)
m_focusedElement->setFocused(false);
m_focusedElement->onFocusChange(); m_focusedElement->onFocusChange();
}
m_focusedElement = focusedElement; m_focusedElement = focusedElement;
if(m_focusedElement) { if(m_focusedElement)
m_focusedElement->setFocused(true);
m_focusedElement->onFocusChange(); m_focusedElement->onFocusChange();
}
} }
// when containers are focused they go to the top // when containers are focused they go to the top
@ -222,7 +227,7 @@ void UIContainer::setFocusedElement(UIElementPtr focusedElement)
} }
} }
bool UIContainer::lockElement(UIElementPtr element) bool UIContainer::lockElement(const UIElementPtr& element)
{ {
if(std::find(m_children.begin(), m_children.end(), element) != m_children.end()) { if(std::find(m_children.begin(), m_children.end(), element) != m_children.end()) {
m_lockedElements.remove(element); m_lockedElements.remove(element);
@ -238,7 +243,7 @@ bool UIContainer::lockElement(UIElementPtr element)
return false; return false;
} }
bool UIContainer::unlockElement(UIElementPtr element) bool UIContainer::unlockElement(const UIElementPtr& element)
{ {
auto it = std::find(m_lockedElements.begin(), m_lockedElements.end(), element); auto it = std::find(m_lockedElements.begin(), m_lockedElements.end(), element);
if(it != m_lockedElements.end()) { if(it != m_lockedElements.end()) {

@ -40,29 +40,33 @@ public:
virtual void onInputEvent(const InputEvent& event); virtual void onInputEvent(const InputEvent& event);
/// Add an element, this must never be called from events loops /// Add an element, this must never be called from events loops
void addChild(UIElementPtr child); void addChild(const UIElementPtr& child);
/// Remove an element, this must never be called from events loops /// Remove an element, this must never be called from events loops
void removeChild(UIElementPtr child); void removeChild(const UIElementPtr& child);
/// Check if has child
bool hasChild(const UIElementPtr& child);
/// Find an element in this container by id /// Find an element in this container by id
UIElementPtr getChildById(const std::string& id); UIElementPtr getChildById(const std::string& id);
/// Find an element by position /// Find an element by position
UIElementPtr getChildByPos(const Point& pos); UIElementPtr getChildByPos(const Point& pos);
/// Find an element in this container and in its children by id /// Find an element in this container and in its children by id
UIElementPtr recursiveGetChildById(const std::string& id); UIElementPtr recursiveGetChildById(const std::string& id);
/// Get children
const std::list<UIElementPtr>& getChildren() const { return m_children; }
/// Pushs a child to the top /// Pushs a child to the top
void pushChildToTop(const UIElementPtr& child); void pushChildToTop(const UIElementPtr& child);
int getChildCount() const { return m_children.size(); } int getChildCount() const { return m_children.size(); }
/// Disable all children except the specified element /// Disable all children except the specified element
bool lockElement(UIElementPtr element); bool lockElement(const UIElementPtr& element);
/// Renable all children /// Renable all children
bool unlockElement(UIElementPtr element); bool unlockElement(const UIElementPtr& element);
/// Focus next element /// Focus next element
void focusNextElement(); void focusNextElement();
/// Focus element /// Focus element
void setFocusedElement(UIElementPtr focusedElement); void setFocusedElement(const UIElementPtr& focusedElement);
/// Get focused element /// Get focused element
UIElementPtr getFocusedElement() const { return m_focusedElement; } UIElementPtr getFocusedElement() const { return m_focusedElement; }

@ -34,8 +34,7 @@ UIElement::UIElement(UI::EElementType type) :
UILayout(), UILayout(),
m_type(type), m_type(type),
m_visible(true), m_visible(true),
m_enabled(true), m_enabled(true)
m_focused(false)
{ {
} }
@ -56,8 +55,7 @@ void UIElement::internalOnDestroy()
//logTraceDebug(getId()); //logTraceDebug(getId());
UIElementPtr me = asUIElement(); UIElementPtr me = asUIElement();
if(m_onDestroyCallback) callLuaTableField("onDestroy");
m_onDestroyCallback(me);
// remove from parent // remove from parent
if(getParent()) { if(getParent()) {
@ -65,7 +63,7 @@ void UIElement::internalOnDestroy()
} }
// free script stuff // free script stuff
clearLuaRefs(); releaseLuaTableRef();
g_dispatcher.addTask(boost::bind(&UIElement::internalDestroyCheck, asUIElement())); g_dispatcher.addTask(boost::bind(&UIElement::internalDestroyCheck, asUIElement()));
} }
@ -90,8 +88,7 @@ void UIElement::setSkin(const UIElementSkinPtr& skin)
void UIElement::onLoad() void UIElement::onLoad()
{ {
if(m_onLoadCallback) g_dispatcher.addTask(boost::bind(&Scriptable::callLuaTableField, shared_from_this(), "onLoad"));
g_dispatcher.addTask(boost::bind(m_onLoadCallback, asUIElement()));
} }
void UIElement::render() void UIElement::render()
@ -139,3 +136,36 @@ void UIElement::moveTo(Point pos)
} }
setRect(newRect); setRect(newRect);
} }
void UIElement::setParent(UIContainerPtr parent)
{
UIElementPtr me = asUIElement();
UIContainerPtr oldParent = m_parent.lock();
m_parent.reset();
if(oldParent && oldParent->hasChild(me)) {
oldParent->removeChild(me);
}
if(parent) {
m_parent = UIContainerWeakPtr(parent);
if(!parent->hasChild(me))
parent->addChild(me);
}
}
bool UIElement::isFocused() const
{
if(UIContainerPtr parent = m_parent.lock())
return (parent->getFocusedElement() == shared_from_this());
return false;
}
void UIElement::setFocused(bool focused)
{
if(UIContainerPtr parent = m_parent.lock()) {
if(focused) {
parent->setFocusedElement(asUIElement());
} else if(parent->getFocusedElement() == asUIElement()) {
parent->setFocusedElement(UIElementPtr());
}
}
}

@ -67,9 +67,9 @@ public:
void moveTo(Point pos); void moveTo(Point pos);
void setSkin(const UIElementSkinPtr& skin); void setSkin(const UIElementSkinPtr& skin);
const UIElementSkinPtr& getSkin() const { return m_skin; } UIElementSkinPtr getSkin() const { return m_skin; }
void setParent(UIContainerPtr parent) { m_parent = parent; } void setParent(UIContainerPtr parent);
UIContainerPtr getParent() const { return m_parent.lock(); } UIContainerPtr getParent() const { return m_parent.lock(); }
void setId(const std::string& id) { m_id = id; } void setId(const std::string& id) { m_id = id; }
@ -78,8 +78,8 @@ public:
void setEnabled(bool enabled) { m_enabled = enabled; } void setEnabled(bool enabled) { m_enabled = enabled; }
bool isEnabled() const { return m_enabled; } bool isEnabled() const { return m_enabled; }
void setFocused(bool focused) { m_focused = focused; } void setFocused(bool focused);
bool isFocused() const { return m_focused; } bool isFocused() const;
void setVisible(bool visible) { m_visible = visible; } void setVisible(bool visible) { m_visible = visible; }
bool isVisible() const { return m_visible; } bool isVisible() const { return m_visible; }
@ -91,9 +91,6 @@ public:
virtual UIContainerPtr asUIContainer() { return UIContainerPtr(); } virtual UIContainerPtr asUIContainer() { return UIContainerPtr(); }
virtual const char *getScriptableName() const { return "UIElement"; } virtual const char *getScriptableName() const { return "UIElement"; }
void setOnDestroy(const UIElementCallback& onDestroyCallback) { m_onDestroyCallback = onDestroyCallback; }
void setOnLoad(const UIElementCallback& onLoadCallback) { m_onLoadCallback = onLoadCallback; }
private: private:
UI::EElementType m_type; UI::EElementType m_type;
UIContainerWeakPtr m_parent; UIContainerWeakPtr m_parent;
@ -101,9 +98,6 @@ private:
std::string m_id; std::string m_id;
bool m_visible; bool m_visible;
bool m_enabled; bool m_enabled;
bool m_focused;
UIElementCallback m_onLoadCallback;
UIElementCallback m_onDestroyCallback;
}; };
#endif // UIELEMENT_H #endif // UIELEMENT_H

@ -38,7 +38,7 @@ public:
m_color(Color::white) { } m_color(Color::white) { }
void setText(const std::string& text); void setText(const std::string& text);
const std::string& getText() const { return m_text; } std::string getText() const { return m_text; }
void setAlign(int align) { m_align = align; } void setAlign(int align) { m_align = align; }
int getAlign() const { return m_align; } int getAlign() const { return m_align; }

@ -66,7 +66,7 @@ private:
class UILayout : public Scriptable class UILayout : public Scriptable
{ {
public: public:
UILayout() : UILayout() : Scriptable(),
m_marginLeft(0), m_marginLeft(0),
m_marginRight(0), m_marginRight(0),
m_marginTop(0), m_marginTop(0),
@ -79,7 +79,7 @@ public:
/// Set the layout rect, always absolute position /// Set the layout rect, always absolute position
void setRect(const Rect& rect); void setRect(const Rect& rect);
/// Get layout size, it always return the absolute position /// Get layout size, it always return the absolute position
const Rect& getRect() const{ return m_rect; } Rect getRect() const { return m_rect; }
// anchors add methods // anchors add methods
bool addAnchor(EAnchorType type, const AnchorLine& anchorLine); bool addAnchor(EAnchorType type, const AnchorLine& anchorLine);

@ -215,23 +215,17 @@ void UILoader::loadElement(const UIElementPtr& element, const YAML::Node& node)
// load events // load events
if(node.FindValue("onLoad")) { if(node.FindValue("onLoad")) {
const YAML::Node& cnode = node["onLoad"]; const YAML::Node& cnode = node["onLoad"];
int funcRef = g_lua.loadBufferAsFunction(cnode.Read<std::string>(), element->getId() + ":onLoad"); if(g_lua.loadBufferAsFunction(cnode.Read<std::string>(), element->getId() + ":onLoad"))
if(funcRef != LUA_REFNIL) { g_lua.setScriptableField(element, "onLoad");
g_lua.pushClassInstance(element); else
g_lua.pushFunction(funcRef);
lua_UIElement_setOnLoad();
} else
logError(YAML::Exception(cnode.GetMark(), "failed to parse inline lua script").what()); logError(YAML::Exception(cnode.GetMark(), "failed to parse inline lua script").what());
} }
if(node.FindValue("onDestroy")) { if(node.FindValue("onDestroy")) {
const YAML::Node& cnode = node["onDestroy"]; const YAML::Node& cnode = node["onDestroy"];
int funcRef = g_lua.loadBufferAsFunction(cnode.Read<std::string>(), element->getId() + ":onDestroy"); if(g_lua.loadBufferAsFunction(cnode.Read<std::string>(), element->getId() + ":onDestroy"))
if(funcRef != LUA_REFNIL) { g_lua.setScriptableField(element, "onDestroy");
g_lua.pushClassInstance(element); else
g_lua.pushFunction(funcRef);
lua_UIElement_setOnDestroy();
} else
logError(YAML::Exception(cnode.GetMark(), "failed to parse inline lua script").what()); logError(YAML::Exception(cnode.GetMark(), "failed to parse inline lua script").what());
} }
@ -314,13 +308,9 @@ void UILoader::loadButton(const UIButtonPtr& button, const YAML::Node& node)
// set on click event // set on click event
if(node.FindValue("onClick")) { if(node.FindValue("onClick")) {
int funcRef = g_lua.loadBufferAsFunction(node["onClick"].Read<std::string>(), button->getId() + ":onClick"); if(g_lua.loadBufferAsFunction(node["onClick"].Read<std::string>(), button->getId() + ":onClick"))
if(funcRef != LUA_REFNIL) { g_lua.setScriptableField(button, "onClick");
g_lua.pushClassInstance(button); else
g_lua.pushFunction(funcRef);
lua_UIButton_setOnClick();
} else {
logError(YAML::Exception(node["onClick"].GetMark(), "failed to parse inline lua script").what()); logError(YAML::Exception(node["onClick"].GetMark(), "failed to parse inline lua script").what());
}
} }
} }

@ -41,7 +41,7 @@ public:
void onFocusChange(); void onFocusChange();
void setText(const std::string& text); void setText(const std::string& text);
const std::string& getText() const { return m_textArea.getText(); } std::string getText() const { return m_textArea.getText(); }
TextArea& getTextArea() { return m_textArea; } TextArea& getTextArea() { return m_textArea; }
bool isFocusable() const { return true; } bool isFocusable() const { return true; }

@ -38,7 +38,7 @@ public:
void onInputEvent(const InputEvent& event); void onInputEvent(const InputEvent& event);
void setTitle(const std::string& title) { m_title = title; } void setTitle(const std::string& title) { m_title = title; }
const std::string& getTitle() const { return m_title; } std::string getTitle() const { return m_title; }
virtual const char *getScriptableName() const { return "UIWindow"; } virtual const char *getScriptableName() const { return "UIWindow"; }

Loading…
Cancel
Save