diff --git a/src/graphics/Renderer.cpp b/src/graphics/Renderer.cpp index 7c4d793c7..7b495838a 100644 --- a/src/graphics/Renderer.cpp +++ b/src/graphics/Renderer.cpp @@ -18,6 +18,7 @@ #ifdef LUACONSOLE #include "lua/LuaScriptInterface.h" #include "lua/LuaScriptHelper.h" +#include "lua/LuaSmartRef.h" #endif #include "hmap.h" #ifdef OGLR diff --git a/src/gui/interface/Window.cpp b/src/gui/interface/Window.cpp index a0492f957..bae26f2a7 100644 --- a/src/gui/interface/Window.cpp +++ b/src/gui/interface/Window.cpp @@ -80,6 +80,7 @@ void Window::RemoveComponent(Component* c) Components.erase(Components.begin() + i); // we're done + c->SetParentWindow(NULL); return; } } diff --git a/src/lua/LegacyLuaAPI.cpp b/src/lua/LegacyLuaAPI.cpp index a579a55a2..e45564724 100644 --- a/src/lua/LegacyLuaAPI.cpp +++ b/src/lua/LegacyLuaAPI.cpp @@ -8,6 +8,7 @@ #include "Format.h" #include "LuaScriptInterface.h" #include "LuaScriptHelper.h" +#include "LuaSmartRef.h" #include "Platform.h" #include "PowderToy.h" @@ -136,7 +137,7 @@ int luacon_partsread(lua_State* l) if (i < 0 || i >= NPART) return luaL_error(l, "array index out of bounds"); - lua_rawgeti(l, LUA_REGISTRYINDEX, tptPart); + lua_rawgeti(l, LUA_REGISTRYINDEX, *tptPart); cIndex = i; return 1; } @@ -317,12 +318,9 @@ int luatpt_element_func(lua_State *l) { int element = luaL_optint(l, 2, 0); int replace = luaL_optint(l, 3, 0); - int function; - lua_pushvalue(l, 1); - function = luaL_ref(l, LUA_REGISTRYINDEX); if(element > 0 && element < PT_NUM) { - lua_el_func[element] = function; + lua_el_func[element].Assign(1); if (replace == 2) lua_el_mode[element] = 3; //update before else if (replace) @@ -341,7 +339,7 @@ int luatpt_element_func(lua_State *l) int element = luaL_optint(l, 2, 0); if(element > 0 && element < PT_NUM) { - lua_el_func[element] = 0; + lua_el_func[element].Clear(); lua_el_mode[element] = 0; } else @@ -390,12 +388,9 @@ int luatpt_graphics_func(lua_State *l) if(lua_isfunction(l, 1)) { int element = luaL_optint(l, 2, 0); - int function; - lua_pushvalue(l, 1); - function = luaL_ref(l, LUA_REGISTRYINDEX); if (element > 0 && element < PT_NUM) { - lua_gr_func[element] = function; + lua_gr_func[element].Assign(1); luacon_ren->graphicscache[element].isready = 0; return 0; } @@ -409,7 +404,7 @@ int luatpt_graphics_func(lua_State *l) int element = luaL_optint(l, 2, 0); if (element > 0 && element < PT_NUM) { - lua_gr_func[element] = 0; + lua_gr_func[element].Clear(); luacon_ren->graphicscache[element].isready = 0; return 0; } diff --git a/src/lua/LuaButton.cpp b/src/lua/LuaButton.cpp index 5f0a4a174..64167ffe5 100644 --- a/src/lua/LuaButton.cpp +++ b/src/lua/LuaButton.cpp @@ -20,7 +20,7 @@ Luna::RegType LuaButton::methods[] = { LuaButton::LuaButton(lua_State * l) : LuaComponent(l), - actionFunction(0) + actionFunction(l) { int posX = luaL_optinteger(l, 1, 0); int posY = luaL_optinteger(l, 2, 0); @@ -62,17 +62,7 @@ int LuaButton::enabled(lua_State * l) int LuaButton::action(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - actionFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - actionFunction = 0; - } - return 0; + return actionFunction.CheckAndAssignArg1(); } int LuaButton::text(lua_State * l) @@ -96,7 +86,7 @@ void LuaButton::triggerAction() if(actionFunction) { lua_rawgeti(l, LUA_REGISTRYINDEX, actionFunction); - lua_rawgeti(l, LUA_REGISTRYINDEX, UserData); + lua_rawgeti(l, LUA_REGISTRYINDEX, owner_ref); if (lua_pcall(l, 1, 0, 0)) { ci->Log(CommandInterface::LogError, ByteString(lua_tostring(l, -1)).FromUtf8()); diff --git a/src/lua/LuaButton.h b/src/lua/LuaButton.h index 6a7b965f6..bfc65aa06 100644 --- a/src/lua/LuaButton.h +++ b/src/lua/LuaButton.h @@ -13,7 +13,7 @@ class LuaScriptInterface; class LuaButton: public LuaComponent { ui::Button * button; - int actionFunction; + LuaComponentCallback actionFunction; void triggerAction(); int action(lua_State * l); int text(lua_State * l); diff --git a/src/lua/LuaCheckbox.cpp b/src/lua/LuaCheckbox.cpp index f37d61c09..c669d3bb7 100644 --- a/src/lua/LuaCheckbox.cpp +++ b/src/lua/LuaCheckbox.cpp @@ -20,7 +20,7 @@ Luna::RegType LuaCheckbox::methods[] = { LuaCheckbox::LuaCheckbox(lua_State * l) : LuaComponent(l), - actionFunction(0) + actionFunction(l) { int posX = luaL_optinteger(l, 1, 0); int posY = luaL_optinteger(l, 2, 0); @@ -60,17 +60,7 @@ int LuaCheckbox::checked(lua_State * l) int LuaCheckbox::action(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - actionFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - actionFunction = 0; - } - return 0; + return actionFunction.CheckAndAssignArg1(); } int LuaCheckbox::text(lua_State * l) @@ -93,7 +83,7 @@ void LuaCheckbox::triggerAction() if(actionFunction) { lua_rawgeti(l, LUA_REGISTRYINDEX, actionFunction); - lua_rawgeti(l, LUA_REGISTRYINDEX, UserData); + lua_rawgeti(l, LUA_REGISTRYINDEX, owner_ref); lua_pushboolean(l, checkbox->GetChecked()); if (lua_pcall(l, 2, 0, 0)) { diff --git a/src/lua/LuaCheckbox.h b/src/lua/LuaCheckbox.h index 9dfc5a26a..26fd2e310 100644 --- a/src/lua/LuaCheckbox.h +++ b/src/lua/LuaCheckbox.h @@ -13,7 +13,7 @@ class LuaScriptInterface; class LuaCheckbox: public LuaComponent { ui::Checkbox * checkbox; - int actionFunction; + LuaComponentCallback actionFunction; void triggerAction(); int action(lua_State * l); int checked(lua_State * l); diff --git a/src/lua/LuaComponent.cpp b/src/lua/LuaComponent.cpp index f455732ea..efa8a8746 100644 --- a/src/lua/LuaComponent.cpp +++ b/src/lua/LuaComponent.cpp @@ -5,8 +5,17 @@ #include "LuaScriptInterface.h" #include "gui/interface/Component.h" +int LuaComponentCallback::CheckAndAssignArg1() +{ + if (lua_type(l, 1) != LUA_TNIL) + { + luaL_checktype(l, 1, LUA_TFUNCTION); + } + LuaSmartRef::Assign(1); + return 0; +} -LuaComponent::LuaComponent(lua_State * l) +LuaComponent::LuaComponent(lua_State * l) : owner_ref(LUA_REFNIL) { this->l = l; diff --git a/src/lua/LuaComponent.h b/src/lua/LuaComponent.h index 6d0fad8b2..1c62dfc05 100644 --- a/src/lua/LuaComponent.h +++ b/src/lua/LuaComponent.h @@ -1,6 +1,7 @@ #pragma once #include "LuaLuna.h" +#include "LuaSmartRef.h" namespace ui { @@ -9,6 +10,13 @@ namespace ui class LuaScriptInterface; +class LuaComponentCallback : public LuaSmartRef +{ +public: + using LuaSmartRef::LuaSmartRef; + int CheckAndAssignArg1(); +}; + class LuaComponent { protected: @@ -19,7 +27,7 @@ protected: int visible(lua_State * l); public: LuaScriptInterface * ci; - int UserData; + int owner_ref; ui::Component * GetComponent() { return component; } LuaComponent(lua_State * l); diff --git a/src/lua/LuaLuna.h b/src/lua/LuaLuna.h index 2dbce8a5e..76b51e92c 100644 --- a/src/lua/LuaLuna.h +++ b/src/lua/LuaLuna.h @@ -133,9 +133,6 @@ private: userdataType *ud = static_cast(lua_newuserdata(L, sizeof(userdataType))); ud->pT = obj; // store pointer to object in userdata - obj->UserData = luaL_ref(L, LUA_REGISTRYINDEX); - lua_rawgeti(L, LUA_REGISTRYINDEX, obj->UserData); - luaL_getmetatable(L, T::className); // lookup metatable in Lua registry lua_setmetatable(L, -2); return 1; // userdata containing pointer to T object diff --git a/src/lua/LuaScriptHelper.h b/src/lua/LuaScriptHelper.h index b7b36b727..f2dc0dbdb 100644 --- a/src/lua/LuaScriptHelper.h +++ b/src/lua/LuaScriptHelper.h @@ -11,13 +11,16 @@ extern Renderer * luacon_ren; extern bool *luacon_currentCommand; extern String *luacon_lastError; -extern int *lua_el_func, *lua_el_mode, *lua_gr_func; +class LuaSmartRef; +extern int *lua_el_mode; +extern LuaSmartRef *lua_el_func, *lua_gr_func; extern int getPartIndex_curIdx; extern int tptProperties; //Table for some TPT properties extern int tptPropertiesVersion; extern int tptElements; //Table for TPT element names -extern int tptParts, tptPartsMeta, tptElementTransitions, tptPartsCData, tptPartMeta, tptPart, cIndex; +extern int tptParts, tptPartsMeta, tptElementTransitions, tptPartsCData, tptPartMeta, cIndex; +extern LuaSmartRef *tptPart; void luaopen_eventcompat(lua_State *l); void luacon_hook(lua_State *L, lua_Debug *ar); diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index 953062d8c..9317dc0a0 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -62,13 +62,15 @@ bool *luacon_currentCommand; String *luacon_lastError; String lastCode; -int *lua_el_func, *lua_el_mode, *lua_gr_func; +int *lua_el_mode; +LuaSmartRef *lua_el_func, *lua_gr_func; int getPartIndex_curIdx; int tptProperties; //Table for some TPT properties int tptPropertiesVersion; int tptElements; //Table for TPT element names -int tptParts, tptPartsMeta, tptElementTransitions, tptPartsCData, tptPartMeta, tptPart, cIndex; +int tptParts, tptPartsMeta, tptElementTransitions, tptPartsCData, tptPartMeta, cIndex; +LuaSmartRef *tptPart = nullptr; int atPanic(lua_State *l) { @@ -261,16 +263,20 @@ tpt.partsdata = nil"); lua_setfield(l, tptProperties, "parts"); lua_newtable(l); - tptPart = lua_gettop(l); - lua_newtable(l); - tptPartMeta = lua_gettop(l); - lua_pushcfunction(l, luacon_partwrite); - lua_setfield(l, tptPartMeta, "__newindex"); - lua_pushcfunction(l, luacon_partread); - lua_setfield(l, tptPartMeta, "__index"); - lua_setmetatable(l, tptPart); + { + int top = lua_gettop(l); + lua_newtable(l); + tptPartMeta = lua_gettop(l); + lua_pushcfunction(l, luacon_partwrite); + lua_setfield(l, tptPartMeta, "__newindex"); + lua_pushcfunction(l, luacon_partread); + lua_setfield(l, tptPartMeta, "__index"); + lua_setmetatable(l, top); + } - tptPart = luaL_ref(l, LUA_REGISTRYINDEX); + tptPart = new LuaSmartRef(l); + tptPart->Assign(-1); + lua_pop(l, 1); #endif lua_newtable(l); @@ -314,14 +320,12 @@ tpt.partsdata = nil"); } lua_setfield(l, tptProperties, "eltransition"); - lua_el_func = (int*)calloc(PT_NUM, sizeof(int)); - lua_el_mode = (int*)calloc(PT_NUM, sizeof(int)); - lua_gr_func = (int*)calloc(PT_NUM, sizeof(int)); - for (int i = 0; i < PT_NUM; i++) - { - lua_el_mode[i] = 0; - lua_gr_func[i] = 0; - } + lua_gr_func_v = std::vector(PT_NUM, l); + lua_gr_func = &lua_gr_func_v[0]; + lua_el_func_v = std::vector(PT_NUM, l); + lua_el_func = &lua_el_func_v[0]; + lua_el_mode = new int[PT_NUM]; + std::fill(lua_el_mode, lua_el_mode + PT_NUM, 0); //make tpt.* a metatable lua_newtable(l); @@ -459,47 +463,66 @@ void LuaScriptInterface::initInterfaceAPI() int LuaScriptInterface::interface_addComponent(lua_State * l) { - void * luaComponent = NULL; - ui::Component * component = NULL; - if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); + void *opaque = nullptr; + LuaComponent *luaComponent = nullptr; + if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); else luaL_typerror(l, 1, "Component"); - if (luacon_ci->Window && component) - luacon_ci->Window->AddComponent(component); + if (luacon_ci->Window && luaComponent) + { + auto ok = luacon_ci->grabbed_components.insert(std::make_pair(luaComponent, LuaSmartRef(l))); + if (ok.second) + { + auto it = ok.first; + it->second.Assign(1); + it->first->owner_ref = it->second; + } + luacon_ci->Window->AddComponent(luaComponent->GetComponent()); + } return 0; } int LuaScriptInterface::interface_removeComponent(lua_State * l) { - void * luaComponent = NULL; - ui::Component * component = NULL; - if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); + void *opaque = nullptr; + LuaComponent *luaComponent = nullptr; + if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); else luaL_typerror(l, 1, "Component"); - if(luacon_ci->Window && component) + if(luacon_ci->Window && luaComponent) + { + ui::Component *component = luaComponent->GetComponent(); luacon_ci->Window->RemoveComponent(component); + auto it = luacon_ci->grabbed_components.find(luaComponent); + if (it != luacon_ci->grabbed_components.end()) + { + it->second.Clear(); + it->first->owner_ref = it->second; + luacon_ci->grabbed_components.erase(it); + } + } return 0; } @@ -2672,12 +2695,14 @@ int LuaScriptInterface::elements_element(lua_State * l) lua_getfield(l, -1, "Update"); if(lua_type(l, -1) == LUA_TFUNCTION) { - lua_el_func[id] = luaL_ref(l, LUA_REGISTRYINDEX); + lua_el_func[id].Assign(-1); + lua_pop(l, 1); lua_el_mode[id] = 1; } else if(lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) { - lua_el_func[id] = 0; + lua_el_func[id].Clear(); + lua_pop(l, 1); lua_el_mode[id] = 0; luacon_sim->elements[id].Update = NULL; } @@ -2687,11 +2712,13 @@ int LuaScriptInterface::elements_element(lua_State * l) lua_getfield(l, -1, "Graphics"); if(lua_type(l, -1) == LUA_TFUNCTION) { - lua_gr_func[id] = luaL_ref(l, LUA_REGISTRYINDEX); + lua_gr_func[id].Assign(-1); + lua_pop(l, 1); } else if(lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) { - lua_gr_func[id] = 0; + lua_gr_func[id].Clear(); + lua_pop(l, 1); luacon_sim->elements[id].Graphics = NULL; } else @@ -2781,12 +2808,11 @@ int LuaScriptInterface::elements_property(lua_State * l) } else lua_el_mode[id] = 1; - lua_pushvalue(l, 3); - lua_el_func[id] = luaL_ref(l, LUA_REGISTRYINDEX); + lua_el_func[id].Assign(3); } else if(lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3)) { - lua_el_func[id] = 0; + lua_el_func[id].Clear(); lua_el_mode[id] = 0; luacon_sim->elements[id].Update = NULL; } @@ -2795,12 +2821,11 @@ int LuaScriptInterface::elements_property(lua_State * l) { if(lua_type(l, 3) == LUA_TFUNCTION) { - lua_pushvalue(l, 3); - lua_gr_func[id] = luaL_ref(l, LUA_REGISTRYINDEX); + lua_gr_func[id].Assign(3); } else if(lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) { - lua_gr_func[id] = 0; + lua_gr_func[id].Clear(); luacon_sim->elements[id].Graphics = NULL; } luacon_ren->graphicscache[id].isready = 0; @@ -3709,6 +3734,16 @@ String LuaScriptInterface::FormatCommand(String command) } LuaScriptInterface::~LuaScriptInterface() { + delete tptPart; + for (auto &component_and_ref : grabbed_components) + { + luacon_ci->Window->RemoveComponent(component_and_ref.first->GetComponent()); + component_and_ref.second.Clear(); + component_and_ref.first->owner_ref = component_and_ref.second; + } + delete[] lua_el_mode; + lua_el_func_v.clear(); + lua_gr_func_v.clear(); lua_close(l); delete legacy; } diff --git a/src/lua/LuaScriptInterface.h b/src/lua/LuaScriptInterface.h index 41d267763..9b4a24ff6 100644 --- a/src/lua/LuaScriptInterface.h +++ b/src/lua/LuaScriptInterface.h @@ -2,11 +2,14 @@ #define LUASCRIPTINTERFACE_H_ #include "LuaCompat.h" +#include "LuaSmartRef.h" #include "CommandInterface.h" #include "lua/LuaEvents.h" #include "simulation/Simulation.h" +#include + namespace ui { class Window; @@ -35,6 +38,7 @@ class Tool; lua_setfield(L, -2, #NAME) class TPTScriptInterface; +class LuaComponent; class LuaScriptInterface: public CommandInterface { @@ -177,6 +181,8 @@ class LuaScriptInterface: public CommandInterface static int event_unregister(lua_State * l); static int event_getmodifiers(lua_State * l); + std::vector lua_el_func_v, lua_gr_func_v; + public: int tpt_index(lua_State *l); int tpt_newIndex(lua_State *l); @@ -186,6 +192,7 @@ public: ui::Window * Window; lua_State *l; + std::map grabbed_components; LuaScriptInterface(GameController * c, GameModel * m); void OnTick() override; diff --git a/src/lua/LuaSlider.cpp b/src/lua/LuaSlider.cpp index b215c7c0d..24c897eca 100644 --- a/src/lua/LuaSlider.cpp +++ b/src/lua/LuaSlider.cpp @@ -20,7 +20,7 @@ Luna::RegType LuaSlider::methods[] = { LuaSlider::LuaSlider(lua_State * l) : LuaComponent(l), - onValueChangedFunction(0) + onValueChangedFunction(l) { int posX = luaL_optinteger(l, 1, 0); int posY = luaL_optinteger(l, 2, 0); @@ -60,17 +60,7 @@ int LuaSlider::steps(lua_State * l) int LuaSlider::onValueChanged(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - onValueChangedFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - onValueChangedFunction = 0; - } - return 0; + return onValueChangedFunction.CheckAndAssignArg1(); } int LuaSlider::value(lua_State * l) @@ -93,7 +83,7 @@ void LuaSlider::triggerOnValueChanged() if(onValueChangedFunction) { lua_rawgeti(l, LUA_REGISTRYINDEX, onValueChangedFunction); - lua_rawgeti(l, LUA_REGISTRYINDEX, UserData); + lua_rawgeti(l, LUA_REGISTRYINDEX, owner_ref); lua_pushinteger(l, slider->GetValue()); if (lua_pcall(l, 2, 0, 0)) { diff --git a/src/lua/LuaSlider.h b/src/lua/LuaSlider.h index 3fd919ed5..caa20a340 100644 --- a/src/lua/LuaSlider.h +++ b/src/lua/LuaSlider.h @@ -13,7 +13,7 @@ class LuaScriptInterface; class LuaSlider: public LuaComponent { ui::Slider * slider; - int onValueChangedFunction; + LuaComponentCallback onValueChangedFunction; void triggerOnValueChanged(); int onValueChanged(lua_State * l); int steps(lua_State * l); diff --git a/src/lua/LuaSmartRef.cpp b/src/lua/LuaSmartRef.cpp new file mode 100644 index 000000000..7be6d4b55 --- /dev/null +++ b/src/lua/LuaSmartRef.cpp @@ -0,0 +1,36 @@ +#include "LuaSmartRef.h" + +void LuaSmartRef::Clear() +{ + luaL_unref(l, LUA_REGISTRYINDEX, ref); + ref = LUA_REFNIL; +} + +LuaSmartRef::LuaSmartRef(lua_State *state) : + ref(LUA_REFNIL), + l(state) +{ +} + +LuaSmartRef::~LuaSmartRef() +{ + Clear(); +} + +void LuaSmartRef::Assign(int index) +{ + Clear(); + lua_pushvalue(l, index); + ref = luaL_ref(l, LUA_REGISTRYINDEX); +} + +LuaSmartRef::operator int() const +{ + return ref; +} + +LuaSmartRef::operator bool() const +{ + return ref != LUA_REFNIL; +} + diff --git a/src/lua/LuaSmartRef.h b/src/lua/LuaSmartRef.h new file mode 100644 index 000000000..0f9cc97c4 --- /dev/null +++ b/src/lua/LuaSmartRef.h @@ -0,0 +1,20 @@ +#pragma once + +#include "LuaCompat.h" + +class LuaSmartRef +{ + int ref; + +protected: + lua_State *l; + +public: + LuaSmartRef(lua_State *l); + ~LuaSmartRef(); + void Assign(int index); // Copies the value before getting reference, stack unchanged. + void Clear(); + operator int() const; + operator bool() const; +}; + diff --git a/src/lua/LuaTextbox.cpp b/src/lua/LuaTextbox.cpp index 78dd3d822..d51a3098c 100644 --- a/src/lua/LuaTextbox.cpp +++ b/src/lua/LuaTextbox.cpp @@ -20,7 +20,7 @@ Luna::RegType LuaTextbox::methods[] = { LuaTextbox::LuaTextbox(lua_State * l) : LuaComponent(l), - onTextChangedFunction(0) + onTextChangedFunction(l) { this->l = l; int posX = luaL_optinteger(l, 1, 0); @@ -64,17 +64,7 @@ int LuaTextbox::readonly(lua_State * l) int LuaTextbox::onTextChanged(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - onTextChangedFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - onTextChangedFunction = 0; - } - return 0; + return onTextChangedFunction.CheckAndAssignArg1(); } void LuaTextbox::triggerOnTextChanged() @@ -82,7 +72,7 @@ void LuaTextbox::triggerOnTextChanged() if(onTextChangedFunction) { lua_rawgeti(l, LUA_REGISTRYINDEX, onTextChangedFunction); - lua_rawgeti(l, LUA_REGISTRYINDEX, UserData); + lua_rawgeti(l, LUA_REGISTRYINDEX, owner_ref); if (lua_pcall(l, 1, 0, 0)) { ci->Log(CommandInterface::LogError, ByteString(lua_tostring(l, -1)).FromUtf8()); diff --git a/src/lua/LuaTextbox.h b/src/lua/LuaTextbox.h index 9f56740b7..9c8081fc4 100644 --- a/src/lua/LuaTextbox.h +++ b/src/lua/LuaTextbox.h @@ -12,7 +12,7 @@ class LuaScriptInterface; class LuaTextbox: public LuaComponent { - int onTextChangedFunction; + LuaComponentCallback onTextChangedFunction; ui::Textbox * textbox; int text(lua_State * l); int readonly(lua_State * l); diff --git a/src/lua/LuaWindow.cpp b/src/lua/LuaWindow.cpp index de6717532..58ba63677 100644 --- a/src/lua/LuaWindow.cpp +++ b/src/lua/LuaWindow.cpp @@ -39,20 +39,20 @@ Luna::RegType LuaWindow::methods[] = { }; LuaWindow::LuaWindow(lua_State * l) : - onInitializedFunction(0), - onExitFunction(0), - onTickFunction(0), - onDrawFunction(0), - onFocusFunction(0), - onBlurFunction(0), - onTryExitFunction(0), - onTryOkayFunction(0), - onMouseMoveFunction(0), - onMouseDownFunction(0), - onMouseUpFunction(0), - onMouseWheelFunction(0), - onKeyPressFunction(0), - onKeyReleaseFunction(0) + onInitializedFunction(l), + onExitFunction(l), + onTickFunction(l), + onDrawFunction(l), + onFocusFunction(l), + onBlurFunction(l), + onTryExitFunction(l), + onTryOkayFunction(l), + onMouseMoveFunction(l), + onMouseDownFunction(l), + onMouseUpFunction(l), + onMouseWheelFunction(l), + onKeyPressFunction(l), + onKeyReleaseFunction(l) { this->l = l; int posX = luaL_optinteger(l, 1, 1); @@ -107,47 +107,66 @@ LuaWindow::LuaWindow(lua_State * l) : int LuaWindow::addComponent(lua_State * l) { - void * luaComponent = NULL; - ui::Component * component = NULL; - if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); + void *opaque = nullptr; + LuaComponent *luaComponent = nullptr; + if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); else luaL_typerror(l, 1, "Component"); - if(component) - window->AddComponent(component); + if (luaComponent) + { + auto ok = grabbed_components.insert(std::make_pair(luaComponent, LuaSmartRef(l))); + if (ok.second) + { + auto it = ok.first; + it->second.Assign(1); + it->first->owner_ref = it->second; + } + window->AddComponent(luaComponent->GetComponent()); + } return 0; } int LuaWindow::removeComponent(lua_State * l) { - void * luaComponent = NULL; - ui::Component * component = NULL; - if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); - else if ((luaComponent = Luna::tryGet(l, 1))) - component = Luna::get(luaComponent)->GetComponent(); + void *opaque = nullptr; + LuaComponent *luaComponent = nullptr; + if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); + else if ((opaque = Luna::tryGet(l, 1))) + luaComponent = Luna::get(opaque); else luaL_typerror(l, 1, "Component"); - if(component) + if (luaComponent) + { + ui::Component *component = luaComponent->GetComponent(); window->RemoveComponent(component); + auto it = grabbed_components.find(luaComponent); + if (it != grabbed_components.end()) + { + it->second.Clear(); + it->first->owner_ref = it->second; + grabbed_components.erase(it); + } + } return 0; } @@ -395,217 +414,83 @@ void LuaWindow::triggerOnKeyRelease(int key, int scan, bool repeat, bool shift, int LuaWindow::onInitialized(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - onInitializedFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - onInitializedFunction = 0; - } - return 0; + return onInitializedFunction.CheckAndAssignArg1(); } int LuaWindow::onExit(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - onExitFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - onExitFunction = 0; - } - return 0; + return onExitFunction.CheckAndAssignArg1(); } int LuaWindow::onTick(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - onTickFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - onTickFunction = 0; - } - return 0; + return onTickFunction.CheckAndAssignArg1(); } int LuaWindow::onDraw(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - onDrawFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - onDrawFunction = 0; - } - return 0; + return onDrawFunction.CheckAndAssignArg1(); } int LuaWindow::onFocus(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - onFocusFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - onFocusFunction = 0; - } - return 0; + return onFocusFunction.CheckAndAssignArg1(); } int LuaWindow::onBlur(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - onBlurFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - onBlurFunction = 0; - } - return 0; + return onBlurFunction.CheckAndAssignArg1(); } int LuaWindow::onTryExit(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - onTryExitFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - onTryExitFunction = 0; - } - return 0; + return onTryExitFunction.CheckAndAssignArg1(); } int LuaWindow::onTryOkay(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - onTryOkayFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - onTryOkayFunction = 0; - } - return 0; + return onTryOkayFunction.CheckAndAssignArg1(); } int LuaWindow::onMouseMove(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - onMouseMoveFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - onMouseMoveFunction = 0; - } - return 0; + return onMouseMoveFunction.CheckAndAssignArg1(); } int LuaWindow::onMouseDown(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - onMouseDownFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - onMouseDownFunction = 0; - } - return 0; + return onMouseDownFunction.CheckAndAssignArg1(); } int LuaWindow::onMouseUp(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - onMouseUpFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - onMouseUpFunction = 0; - } - return 0; + return onMouseUpFunction.CheckAndAssignArg1(); } int LuaWindow::onMouseWheel(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - onMouseWheelFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - onMouseWheelFunction = 0; - } - return 0; + return onMouseWheelFunction.CheckAndAssignArg1(); } int LuaWindow::onKeyPress(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - onKeyPressFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - onKeyPressFunction = 0; - } - return 0; + return onKeyPressFunction.CheckAndAssignArg1(); } int LuaWindow::onKeyRelease(lua_State * l) { - if(lua_type(l, 1) != LUA_TNIL) - { - luaL_checktype(l, 1, LUA_TFUNCTION); - lua_pushvalue(l, 1); - onKeyReleaseFunction = luaL_ref(l, LUA_REGISTRYINDEX); - } - else - { - onKeyReleaseFunction = 0; - } - return 0; + return onKeyReleaseFunction.CheckAndAssignArg1(); } LuaWindow::~LuaWindow() { + for (auto &component_and_ref : grabbed_components) + { + window->RemoveComponent(component_and_ref.first->GetComponent()); + component_and_ref.second.Clear(); + component_and_ref.first->owner_ref = component_and_ref.second; + } window->CloseActiveWindow(); delete window; } diff --git a/src/lua/LuaWindow.h b/src/lua/LuaWindow.h index 3c697e6dd..2d88d1cfa 100644 --- a/src/lua/LuaWindow.h +++ b/src/lua/LuaWindow.h @@ -1,6 +1,10 @@ #pragma once #include "LuaLuna.h" +#include "LuaComponent.h" +#include "LuaSmartRef.h" + +#include namespace ui { @@ -10,20 +14,22 @@ namespace ui class LuaScriptInterface; class LuaWindow { - int onInitializedFunction; - int onExitFunction; - int onTickFunction; - int onDrawFunction; - int onFocusFunction; - int onBlurFunction; - int onTryExitFunction; - int onTryOkayFunction; - int onMouseMoveFunction; - int onMouseDownFunction; - int onMouseUpFunction; - int onMouseWheelFunction; - int onKeyPressFunction; - int onKeyReleaseFunction; + LuaComponentCallback onInitializedFunction; + LuaComponentCallback onExitFunction; + LuaComponentCallback onTickFunction; + LuaComponentCallback onDrawFunction; + LuaComponentCallback onFocusFunction; + LuaComponentCallback onBlurFunction; + LuaComponentCallback onTryExitFunction; + LuaComponentCallback onTryOkayFunction; + LuaComponentCallback onMouseMoveFunction; + LuaComponentCallback onMouseDownFunction; + LuaComponentCallback onMouseUpFunction; + LuaComponentCallback onMouseWheelFunction; + LuaComponentCallback onKeyPressFunction; + LuaComponentCallback onKeyReleaseFunction; + + std::map grabbed_components; ui::Window * window; lua_State * l; @@ -65,7 +71,6 @@ class LuaWindow public: LuaScriptInterface * ci; - int UserData; static const char className[]; static Luna::RegType methods[];