diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 2db25fbf..dcc7f382 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -177,7 +177,9 @@ Document = {} function Document.new(docname) return setmetatable({name=docname}, { __index=function(self, k) - return Element.new(self.name, k) + local elem = Element.new(self.name, k) + rawset(self, k, elem) + return elem end }) end diff --git a/src/logic/scripting/lua/LuaState.cpp b/src/logic/scripting/lua/LuaState.cpp index 7303dc16..adabb6af 100644 --- a/src/logic/scripting/lua/LuaState.cpp +++ b/src/logic/scripting/lua/LuaState.cpp @@ -260,6 +260,11 @@ int lua::LuaState::pushglobals() { return 1; } +int lua::LuaState::pushcfunction(lua_CFunction function) { + lua_pushcfunction(L, function); + return 1; +} + void lua::LuaState::pop(int n) { lua_pop(L, n); } @@ -294,6 +299,14 @@ lua::luanumber lua::LuaState::tonumber(int idx) { return lua_tonumber(L, idx); } +glm::vec2 lua::LuaState::tovec2(int idx) { + return lua::tovec2(L, idx); +} + +glm::vec4 lua::LuaState::tocolor(int idx) { + return lua::tocolor(L, idx); +} + const char* lua::LuaState::tostring(int idx) { return lua_tostring(L, idx); } @@ -462,3 +475,7 @@ void lua::LuaState::dumpStack() { std::cout << std::endl; } } + +lua_State* lua::LuaState::getLua() const { + return L; +} diff --git a/src/logic/scripting/lua/LuaState.h b/src/logic/scripting/lua/LuaState.h index 49d797c4..63b68e4c 100644 --- a/src/logic/scripting/lua/LuaState.h +++ b/src/logic/scripting/lua/LuaState.h @@ -42,12 +42,15 @@ namespace lua { int pushvalue(const dynamic::Value& value); int pushnil(); int pushglobals(); + int pushcfunction(lua_CFunction function); void pop(int n=1); bool getfield(const std::string& name, int idx = -1); void setfield(const std::string& name, int idx = -2); bool toboolean(int idx); luaint tointeger(int idx); luanumber tonumber(int idx); + glm::vec2 tovec2(int idx); + glm::vec4 tocolor(int idx); std::unique_ptr tovalue(int idx); const char* tostring(int idx); bool isstring(int idx); @@ -68,8 +71,8 @@ namespace lua { void removeEnvironment(int id); const std::string storeAnonymous(); bool emit_event(const std::string& name, std::function args=[](auto*){return 0;}); - void dumpStack(); + lua_State* getLua() const; }; } diff --git a/src/logic/scripting/lua/libgui.cpp b/src/logic/scripting/lua/libgui.cpp index 6a093da3..0eb44948 100644 --- a/src/logic/scripting/lua/libgui.cpp +++ b/src/logic/scripting/lua/libgui.cpp @@ -25,13 +25,19 @@ using namespace gui; +namespace scripting { + extern lua::LuaState* state; +} + struct DocumentNode { UiDocument* document; std::shared_ptr node; }; +using namespace scripting; + static DocumentNode getDocumentNode(lua_State* L, const std::string& name, const std::string& nodeName) { - auto doc = scripting::engine->getAssets()->getLayout(name); + auto doc = engine->getAssets()->getLayout(name); if (doc == nullptr) { luaL_error(L, "document '%s' not found", name.c_str()); } @@ -42,101 +48,6 @@ static DocumentNode getDocumentNode(lua_State* L, const std::string& name, const return {doc, node}; } -static bool getattr(lua_State* L, TrackBar* bar, const std::string& attr) { - if (bar == nullptr) - return false; - if (attr == "value") { - lua_pushnumber(L, bar->getValue()); return true; - } else if (attr == "min") { - lua_pushnumber(L, bar->getMin()); return true; - } else if (attr == "max") { - lua_pushnumber(L, bar->getMax()); - return true; - } else if (attr == "step") { - lua_pushnumber(L, bar->getStep()); - return true; - } else if (attr == "trackWidth") { - lua_pushnumber(L, bar->getTrackWidth()); - return true; - } else if (attr == "trackColor") { - return lua::pushcolor_arr(L, bar->getTrackColor()); - } - return false; -} - -static bool setattr(lua_State* L, TrackBar* bar, const std::string& attr) { - if (bar == nullptr) - return false; - if (attr == "value") { - bar->setValue(lua_tonumber(L, 4)); - return true; - } else if (attr == "min") { - bar->setMin(lua_tonumber(L, 4)); - return true; - } else if (attr == "max") { - bar->setMax(lua_tonumber(L, 4)); - return true; - } else if (attr == "step") { - bar->setStep(lua_tonumber(L, 4)); - return true; - } else if (attr == "trackWidth") { - bar->setTrackWidth(lua_tonumber(L, 4)); - return true; - } else if (attr == "trackColor") { - bar->setTrackColor(lua::tocolor(L, 4)); - return true; - } - return false; -} - -static bool getattr(lua_State* L, Button* button, const std::string& attr) { - if (button == nullptr) - return false; - if (attr == "text") { - lua_pushstring(L, util::wstr2str_utf8(button->getText()).c_str()); - return true; - } else if (attr == "pressedColor") { - return lua::pushcolor_arr(L, button->getPressedColor()); - } - return false; -} - -static bool getattr(lua_State* L, Label* label, const std::string& attr) { - if (label == nullptr) - return false; - if (attr == "text") { - lua_pushstring(L, util::wstr2str_utf8(label->getText()).c_str()); - return true; - } - return false; -} - -static bool getattr(lua_State* L, FullCheckBox* box, const std::string& attr) { - if (box == nullptr) - return false; - if (attr == "checked") { - lua_pushboolean(L, box->isChecked()); - return true; - } - return false; -} - -static bool getattr(lua_State* L, TextBox* box, const std::string& attr) { - if (box == nullptr) - return false; - if (attr == "text") { - lua_pushstring(L, util::wstr2str_utf8(box->getText()).c_str()); - return true; - } else if (attr == "placeholder") { - lua_pushstring(L, util::wstr2str_utf8(box->getPlaceholder()).c_str()); - return true; - } else if (attr == "valid") { - lua_pushboolean(L, box->validate()); - return true; - } - return false; -} - static DocumentNode getDocumentNode(lua_State* L, int idx=1) { lua_getfield(L, idx, "docname"); lua_getfield(L, idx, "name"); @@ -147,107 +58,21 @@ static DocumentNode getDocumentNode(lua_State* L, int idx=1) { return node; } -static int menu_back(lua_State* L) { +static int l_menu_back(lua_State* L) { auto node = getDocumentNode(L); auto menu = dynamic_cast(node.node.get()); menu->back(); return 0; } -static int menu_reset(lua_State* L) { +static int l_menu_reset(lua_State* L) { auto node = getDocumentNode(L); auto menu = dynamic_cast(node.node.get()); menu->reset(); return 0; } -static bool getattr(lua_State* L, Menu* menu, const std::string& attr) { - if (menu == nullptr) - return false; - if (attr == "page") { - lua_pushstring(L, menu->getCurrent().name.c_str()); - return true; - } else if (attr == "back") { - lua_pushcfunction(L, menu_back); - return true; - } else if (attr == "reset") { - lua_pushcfunction(L, menu_reset); - return true; - } - return false; -} - -static bool setattr(lua_State* L, FullCheckBox* box, const std::string& attr) { - if (box == nullptr) - return false; - if (attr == "checked") { - box->setChecked(lua_toboolean(L, 4)); - return true; - } - return false; -} - -static bool setattr(lua_State* L, Button* button, const std::string& attr) { - if (button == nullptr) - return false; - if (attr == "text") { - button->setText(util::str2wstr_utf8(lua_tostring(L, 4))); - return true; - } else if (attr == "pressedColor") { - button->setPressedColor(lua::tocolor(L, 4)); - } - return false; -} - -static bool setattr(lua_State* L, TextBox* box, const std::string& attr) { - if (box == nullptr) - return false; - if (attr == "text") { - box->setText(util::str2wstr_utf8(lua_tostring(L, 4))); - return true; - } else if (attr == "placeholder") { - box->setPlaceholder(util::str2wstr_utf8(lua_tostring(L, 4))); - return true; - } - return false; -} - -static bool setattr(lua_State* L, Label* label, const std::string& attr) { - if (label == nullptr) - return false; - if (attr == "text") { - label->setText(util::str2wstr_utf8(lua_tostring(L, 4))); - return true; - } - return false; -} - -static bool setattr(lua_State* L, Menu* menu, const std::string& attr) { - if (menu == nullptr) - return false; - if (attr == "page") { - menu->setPage(lua_tostring(L, 4)); - return true; - } - return false; -} - -static bool setattr(lua_State* L, InventoryView* view, const std::string& attr) { - if (view == nullptr) - return false; - if (attr == "inventory") { - auto inventory = scripting::level->inventories->get(lua_tointeger(L, 4)); - if (inventory == nullptr) { - view->unbind(); - } else { - view->bind(inventory, scripting::content); - } - return true; - } - return false; -} - -static int container_add(lua_State* L) { +static int l_container_add(lua_State* L) { auto docnode = getDocumentNode(L); auto node = dynamic_cast(docnode.node.get()); auto xmlsrc = lua_tostring(L, 2); @@ -261,7 +86,7 @@ static int container_add(lua_State* L) { return 0; } -static int container_clear(lua_State* L) { +static int l_container_clear(lua_State* L) { auto node = getDocumentNode(L, 1); if (auto container = std::dynamic_pointer_cast(node.node)) { container->clear(); @@ -269,128 +94,324 @@ static int container_clear(lua_State* L) { return 0; } -static bool getattr(lua_State* L, Container* container, const std::string& attr) { - if (container == nullptr) - return false; - - if (attr == "add") { - lua_pushcfunction(L, container_add); - return true; - } else if (attr == "clear") { - lua_pushcfunction(L, container_clear); - return true; - } - return false; -} - -static bool getattr(lua_State* L, InventoryView* inventory, const std::string& attr) { - if (inventory == nullptr) - return false; - if (attr == "inventory") { - auto inv = inventory->getInventory(); - lua_pushinteger(L, inv ? inv->getId() : 0); - return true; - } - return false; -} - -static int uinode_move_into(lua_State* L) { +static int l_uinode_move_into(lua_State* L) { auto node = getDocumentNode(L, 1); auto dest = getDocumentNode(L, 2); UINode::moveInto(node.node, std::dynamic_pointer_cast(dest.node)); return 0; } -static int l_gui_getattr(lua_State* L) { - auto docname = lua_tostring(L, 1); - auto element = lua_tostring(L, 2); - const std::string attr = lua_tostring(L, 3); - auto docnode = getDocumentNode(L, docname, element); - auto node = docnode.node; - - if (attr == "color") { - return lua::pushcolor_arr(L, node->getColor()); - } else if (attr == "pos") { - return lua::pushvec2_arr(L, node->getPos()); - } else if (attr == "size") { - return lua::pushvec2_arr(L, node->getSize()); - } else if (attr == "hoverColor") { - return lua::pushcolor_arr(L, node->getHoverColor()); - } else if (attr == "interactive") { - lua_pushboolean(L, node->isInteractive()); - return 1; - } else if (attr == "visible") { - lua_pushboolean(L, node->isVisible()); - return 1; - } else if (attr == "enabled") { - lua_pushboolean(L, node->isEnabled()); - return 1; - } else if (attr == "move_into") { - lua_pushcfunction(L, uinode_move_into); - return 1; +static int p_get_inventory(UINode* node) { + if (auto inventory = dynamic_cast(node)) { + auto inv = inventory->getInventory(); + return state->pushinteger(inv ? inv->getId() : 0); } - - if (getattr(L, dynamic_cast(node.get()), attr)) - return 1; - if (getattr(L, dynamic_cast(node.get()), attr)) - return 1; - if (getattr(L, dynamic_cast(node.get()), attr)) - return 1; - if (getattr(L, dynamic_cast(node.get()), attr)) - return 1; - if (getattr(L, dynamic_cast(node.get()), attr)) - return 1; - if (getattr(L, dynamic_cast(node.get()), attr)) - return 1; - if (getattr(L, dynamic_cast(node.get()), attr)) - return 1; - if (getattr(L, dynamic_cast(node.get()), attr)) - return 1; - return 0; } -static int l_gui_getviewport(lua_State* L) { - lua::pushvec2_arr(L, scripting::engine->getGUI()->getContainer()->getSize()); - return 1; +static int p_get_reset(UINode* node) { + if (dynamic_cast(node)) { + return state->pushcfunction(l_menu_reset); + } + return 0; +} + +static int p_get_back(UINode* node) { + if (dynamic_cast(node)) { + return state->pushcfunction(l_menu_back); + } + return 0; +} + +static int p_get_page(UINode* node) { + if (auto menu = dynamic_cast(node)) { + return state->pushstring(menu->getCurrent().name); + } + return 0; +} + +static int p_is_checked(UINode* node) { + if (auto box = dynamic_cast(node)) { + return state->pushboolean(box->isChecked()); + } else if (auto box = dynamic_cast(node)) { + return state->pushboolean(box->isChecked()); + } + return 0; +} + +static int p_get_value(UINode* node) { + if (auto bar = dynamic_cast(node)) { + return state->pushnumber(bar->getValue()); + } + return 0; +} + +static int p_get_min(UINode* node) { + if (auto bar = dynamic_cast(node)) { + return state->pushnumber(bar->getMin()); + } + return 0; +} + +static int p_get_max(UINode* node) { + if (auto bar = dynamic_cast(node)) { + return state->pushnumber(bar->getMax()); + } + return 0; +} + +static int p_get_step(UINode* node) { + if (auto bar = dynamic_cast(node)) { + return state->pushnumber(bar->getStep()); + } + return 0; +} + +static int p_get_track_width(UINode* node) { + if (auto bar = dynamic_cast(node)) { + return state->pushnumber(bar->getTrackWidth()); + } + return 0; +} + +static int p_get_track_color(UINode* node) { + if (auto bar = dynamic_cast(node)) { + return lua::pushcolor_arr(state->getLua(), bar->getTrackColor()); + } + return 0; +} + +static int p_is_valid(UINode* node) { + if (auto box = dynamic_cast(node)) { + return state->pushboolean(box->validate()); + } + return 0; +} + +static int p_get_placeholder(UINode* node) { + if (auto box = dynamic_cast(node)) { + return state->pushstring(util::wstr2str_utf8(box->getPlaceholder())); + } + return 0; +} + +static int p_get_text(UINode* node) { + if (auto button = dynamic_cast(node)) { + return state->pushstring(util::wstr2str_utf8(button->getText())); + } else if (auto label = dynamic_cast(node)) { + return state->pushstring(util::wstr2str_utf8(label->getText())); + } else if (auto box = dynamic_cast(node)) { + return state->pushstring(util::wstr2str_utf8(box->getText())); + } + return 0; +} + +static int p_get_add(UINode* node) { + if (dynamic_cast(node)) { + return state->pushcfunction(l_container_add); + } + return 0; +} + +static int p_get_clear(UINode* node) { + if (dynamic_cast(node)) { + return state->pushcfunction(l_container_clear); + } + return 0; +} + +static int p_get_color(UINode* node) { + return lua::pushcolor_arr(state->getLua(), node->getColor()); +} +static int p_get_hover_color(UINode* node) { + return lua::pushcolor_arr(state->getLua(), node->getHoverColor()); +} +static int p_get_pressed_color(UINode* node) { + return lua::pushcolor_arr(state->getLua(), node->getPressedColor()); +} +static int p_get_pos(UINode* node) { + return lua::pushvec2_arr(state->getLua(), node->getPos()); +} +static int p_get_size(UINode* node) { + return lua::pushvec2_arr(state->getLua(), node->getSize()); +} +static int p_is_interactive(UINode* node) { + return state->pushboolean(node->isInteractive()); +} +static int p_is_visible(UINode* node) { + return state->pushboolean(node->isVisible()); +} +static int p_is_enabled(UINode* node) { + return state->pushboolean(node->isEnabled()); +} +static int p_move_into(UINode* node) { + return state->pushcfunction(l_uinode_move_into); +} + +static int l_gui_getattr(lua_State* L) { + auto docname = lua_tostring(L, 1); + auto element = lua_tostring(L, 2); + auto attr = lua_tostring(L, 3); + auto docnode = getDocumentNode(L, docname, element); + auto node = docnode.node; + + static const std::unordered_map> getters { + {"color", p_get_color}, + {"hoverColor", p_get_hover_color}, + {"pressedColor", p_get_pressed_color}, + {"pos", p_get_pos}, + {"size", p_get_size}, + {"interactive", p_is_interactive}, + {"visible", p_is_visible}, + {"enabled", p_is_enabled}, + {"move_into", p_move_into}, + {"add", p_get_add}, + {"clear", p_get_clear}, + {"placeholder", p_get_placeholder}, + {"valid", p_is_valid}, + {"text", p_get_text}, + {"value", p_get_value}, + {"min", p_get_min}, + {"max", p_get_max}, + {"step", p_get_step}, + {"trackWidth", p_get_track_width}, + {"trackColor", p_get_track_color}, + {"checked", p_is_checked}, + {"page", p_get_page}, + {"back", p_get_back}, + {"reset", p_get_reset}, + {"inventory", p_get_inventory}, + }; + auto func = getters.find(attr); + if (func != getters.end()) { + return func->second(node.get()); + } + return 0; +} + +static void p_set_color(UINode* node, int idx) { + node->setColor(state->tocolor(idx)); +} +static void p_set_hover_color(UINode* node, int idx) { + node->setHoverColor(state->tocolor(idx)); +} +static void p_set_pressed_color(UINode* node, int idx) { + node->setPressedColor(state->tocolor(idx)); +} +static void p_set_pos(UINode* node, int idx) { + node->setPos(state->tovec2(idx)); +} +static void p_set_size(UINode* node, int idx) { + node->setSize(state->tovec2(idx)); +} +static void p_set_interactive(UINode* node, int idx) { + node->setInteractive(state->toboolean(idx)); +} +static void p_set_visible(UINode* node, int idx) { + node->setVisible(state->toboolean(idx)); +} +static void p_set_enabled(UINode* node, int idx) { + node->setEnabled(state->toboolean(idx)); +} +static void p_set_placeholder(UINode* node, int idx) { + if (auto box = dynamic_cast(node)) { + box->setPlaceholder(util::str2wstr_utf8(state->tostring(idx))); + } +} +static void p_set_text(UINode* node, int idx) { + if (auto label = dynamic_cast(node)) { + label->setText(util::str2wstr_utf8(state->tostring(idx))); + } else if (auto button = dynamic_cast(node)) { + button->setText(util::str2wstr_utf8(state->tostring(idx))); + } else if (auto box = dynamic_cast(node)) { + box->setText(util::str2wstr_utf8(state->tostring(idx))); + } +} +static void p_set_value(UINode* node, int idx) { + if (auto bar = dynamic_cast(node)) { + bar->setValue(state->tonumber(idx)); + } +} +static void p_set_min(UINode* node, int idx) { + if (auto bar = dynamic_cast(node)) { + bar->setMin(state->tonumber(idx)); + } +} +static void p_set_max(UINode* node, int idx) { + if (auto bar = dynamic_cast(node)) { + bar->setMax(state->tonumber(idx)); + } +} +static void p_set_step(UINode* node, int idx) { + if (auto bar = dynamic_cast(node)) { + bar->setStep(state->tonumber(idx)); + } +} +static void p_set_track_width(UINode* node, int idx) { + if (auto bar = dynamic_cast(node)) { + bar->setTrackWidth(state->tointeger(idx)); + } +} +static void p_set_track_color(UINode* node, int idx) { + if (auto bar = dynamic_cast(node)) { + bar->setTrackColor(state->tocolor(idx)); + } +} +static void p_set_checked(UINode* node, int idx) { + if (auto box = dynamic_cast(node)) { + box->setChecked(state->toboolean(idx)); + } else if (auto box = dynamic_cast(node)) { + box->setChecked(state->toboolean(idx)); + } +} +static void p_set_page(UINode* node, int idx) { + if (auto menu = dynamic_cast(node)) { + menu->setPage(state->tostring(idx)); + } +} +static void p_set_inventory(UINode* node, int idx) { + if (auto view = dynamic_cast(node)) { + auto inventory = level->inventories->get(state->tointeger(idx)); + if (inventory == nullptr) { + view->unbind(); + } else { + view->bind(inventory, content); + } + } } static int l_gui_setattr(lua_State* L) { auto docname = lua_tostring(L, 1); auto element = lua_tostring(L, 2); - const std::string attr = lua_tostring(L, 3); + auto attr = lua_tostring(L, 3); auto docnode = getDocumentNode(L, docname, element); auto node = docnode.node; - if (attr == "pos") { - node->setPos(lua::tovec2(L, 4)); - } else if (attr == "size") { - node->setSize(lua::tovec2(L, 4)); - } else if (attr == "color") { - node->setColor(lua::tocolor(L, 4)); - } else if (attr == "hoverColor") { - node->setHoverColor(lua::tocolor(L, 4)); - } else if (attr == "interactive") { - node->setInteractive(lua_toboolean(L, 4)); - } else if (attr == "visible") { - node->setVisible(lua_toboolean(L, 4)); - } else if (attr == "enabled") { - node->setEnabled(lua_toboolean(L, 4)); - } else { - if (setattr(L, dynamic_cast(node.get()), attr)) - return 0; - if (setattr(L, dynamic_cast(node.get()), attr)) - return 0; - if (setattr(L, dynamic_cast(node.get()), attr)) - return 0; - if (setattr(L, dynamic_cast(node.get()), attr)) - return 0; - if (setattr(L, dynamic_cast(node.get()), attr)) - return 0; - if (setattr(L, dynamic_cast(node.get()), attr)) - return 0; - if (setattr(L, dynamic_cast(node.get()), attr)) - return 0; + + static const std::unordered_map> setters { + {"color", p_set_color}, + {"hoverColor", p_set_hover_color}, + {"pressedColor", p_set_pressed_color}, + {"pos", p_set_pos}, + {"size", p_set_size}, + {"interactive", p_set_interactive}, + {"visible", p_set_visible}, + {"enabled", p_set_enabled}, + {"placeholder", p_set_placeholder}, + {"text", p_set_text}, + {"value", p_set_value}, + {"min", p_set_min}, + {"max", p_set_max}, + {"step", p_set_step}, + {"trackWidth", p_set_track_width}, + {"trackColor", p_set_track_color}, + {"checked", p_set_checked}, + {"page", p_set_page}, + {"inventory", p_set_inventory}, + }; + auto func = setters.find(attr); + if (func != setters.end()) { + func->second(node.get(), 4); } return 0; } @@ -439,6 +460,11 @@ static int l_gui_get_locales_info(lua_State* L) { return 1; } +static int l_gui_getviewport(lua_State* L) { + lua::pushvec2_arr(L, scripting::engine->getGUI()->getContainer()->getSize()); + return 1; +} + const luaL_Reg guilib [] = { {"get_viewport", lua_wrap_errors}, {"getattr", lua_wrap_errors},