From 05589b721e11f1f908bb24b57e84965ace7e3e96 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 13 Feb 2024 18:16:18 +0300 Subject: [PATCH] lua: gui library (WIP) --- res/layouts/inventory.xml | 9 ++- res/layouts/inventory.xml.lua | 11 ++-- res/modules/document.lua | 22 +++++++ res/scripts/stdlib.lua | 20 +++++++ src/frontend/UiDocument.cpp | 8 +++ src/frontend/UiDocument.h | 1 + src/frontend/gui/UINode.cpp | 4 ++ src/frontend/gui/UINode.h | 1 + src/logic/scripting/LuaState.cpp | 4 +- src/logic/scripting/{ => api}/api_lua.h | 38 ++++++------ src/logic/scripting/api/libgui.cpp | 77 +++++++++++++++++++++++++ src/logic/scripting/api/libgui.h | 15 +++++ src/logic/scripting/lua_util.h | 75 ++++++++++++++++++++++++ src/logic/scripting/scripting.cpp | 2 + 14 files changed, 262 insertions(+), 25 deletions(-) create mode 100644 res/modules/document.lua rename src/logic/scripting/{ => api}/api_lua.h (95%) create mode 100644 src/logic/scripting/api/libgui.cpp create mode 100644 src/logic/scripting/api/libgui.h diff --git a/res/layouts/inventory.xml b/res/layouts/inventory.xml index c33d57d6..1ef2b20f 100644 --- a/res/layouts/inventory.xml +++ b/res/layouts/inventory.xml @@ -1,3 +1,10 @@ - + + diff --git a/res/layouts/inventory.xml.lua b/res/layouts/inventory.xml.lua index 532b9ee5..dfcd39a5 100644 --- a/res/layouts/inventory.xml.lua +++ b/res/layouts/inventory.xml.lua @@ -1,9 +1,12 @@ -function on_open(inv) - print("OPEN", inv) +local Document = require("core:document") +document = Document.new(DOC_NAME) + +function on_open(invid) + print("OPEN", invid) end -function on_close(inv) - print("CLOSE", inv) +function on_close(invid) + print("CLOSE", invid) end function inventory_share_func(invid, slotid) diff --git a/res/modules/document.lua b/res/modules/document.lua new file mode 100644 index 00000000..02877064 --- /dev/null +++ b/res/modules/document.lua @@ -0,0 +1,22 @@ +local Element = {} +function Element.new(docname, name) + return setmetatable({docname=docname, name=name}, { + __index=function(self, k) + return gui.getattr(self.docname, self.name, k) + end, + __newindex=function(self, k, v) + gui.setattr(self.docname, self.name, k, v) + end + }) +end + +local Document = {} +function Document.new(docname) + return setmetatable({name=docname}, { + __index=function(self, k) + return Element.new(self.name, k) + end + }) +end + +return Document diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 09d28f55..e2644f02 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -91,3 +91,23 @@ end function pack.is_installed(packid) return file.isfile(packid..":package.json") end + +vec2_mt = {} +function vec2_mt.__tostring(self) + return "vec2("..self[1]..", "..self[2]..")" +end + +vec3_mt = {} +function vec3_mt.__tostring(self) + return "vec3("..self[1]..", "..self[2]..", "..self[3]..")" +end + +vec4_mt = {} +function vec4_mt.__tostring(self) + return "vec4("..self[1]..", "..self[2]..", "..self[3]..", "..self[4]..")" +end + +color_mt = {} +function color_mt.__tostring(self) + return "rgba("..self[1]..", "..self[2]..", "..self[3]..", "..self[4]..")" +end \ No newline at end of file diff --git a/src/frontend/UiDocument.cpp b/src/frontend/UiDocument.cpp index 9df8f123..301c1f7c 100644 --- a/src/frontend/UiDocument.cpp +++ b/src/frontend/UiDocument.cpp @@ -30,6 +30,14 @@ const std::shared_ptr UiDocument::getRoot() const { return root; } +const std::shared_ptr UiDocument::get(const std::string& id) const { + auto found = map.find(id); + if (found == map.end()) { + return nullptr; + } + return found->second; +} + const uidocscript& UiDocument::getScript() const { return script; } diff --git a/src/frontend/UiDocument.h b/src/frontend/UiDocument.h index 7668a414..8dad5cb0 100644 --- a/src/frontend/UiDocument.h +++ b/src/frontend/UiDocument.h @@ -43,6 +43,7 @@ public: const std::string& getId() const; const uinodes_map& getMap() const; const std::shared_ptr getRoot() const; + const std::shared_ptr get(const std::string& id) const; const uidocscript& getScript() const; int getEnvironment() const; /* Collect map of all uinodes having identifiers */ diff --git a/src/frontend/gui/UINode.cpp b/src/frontend/gui/UINode.cpp index 95e8e4b7..1a726cc8 100644 --- a/src/frontend/gui/UINode.cpp +++ b/src/frontend/gui/UINode.cpp @@ -110,6 +110,10 @@ void UINode::setCoord(glm::vec2 coord) { this->coord = coord; } +glm::vec2 UINode::getCoord() const { + return coord; +} + glm::vec2 UINode::getSize() const { return size; } diff --git a/src/frontend/gui/UINode.h b/src/frontend/gui/UINode.h index 1e195932..45d6ca8b 100644 --- a/src/frontend/gui/UINode.h +++ b/src/frontend/gui/UINode.h @@ -112,6 +112,7 @@ namespace gui { /* Calculate screen position of the element */ virtual glm::vec2 calcCoord() const; virtual void setCoord(glm::vec2 coord); + glm::vec2 getCoord() const; virtual glm::vec2 getSize() const; virtual void setSize(glm::vec2 size); virtual void refresh() {}; diff --git a/src/logic/scripting/LuaState.cpp b/src/logic/scripting/LuaState.cpp index 246f4647..8a42e42a 100644 --- a/src/logic/scripting/LuaState.cpp +++ b/src/logic/scripting/LuaState.cpp @@ -1,6 +1,7 @@ #include "LuaState.h" -#include "api_lua.h" +#include "api/api_lua.h" +#include "api/libgui.h" #include "../../util/stringutil.h" lua::luaerror::luaerror(const std::string& message) : std::runtime_error(message) { @@ -98,6 +99,7 @@ void lua::LuaState::createFuncs() { openlib("item", itemlib, 0); openlib("time", timelib, 0); openlib("file", filelib, 0); + openlib("gui", guilib, 0); addfunc("print", l_print); diff --git a/src/logic/scripting/api_lua.h b/src/logic/scripting/api/api_lua.h similarity index 95% rename from src/logic/scripting/api_lua.h rename to src/logic/scripting/api/api_lua.h index 2bb3a2aa..812498cf 100644 --- a/src/logic/scripting/api_lua.h +++ b/src/logic/scripting/api/api_lua.h @@ -1,29 +1,29 @@ #ifndef LOGIC_SCRIPTING_API_LUA_H_ #define LOGIC_SCRIPTING_API_LUA_H_ -#include "scripting.h" -#include "lua_util.h" +#include "../scripting.h" +#include "../lua_util.h" #include #include -#include "../../files/files.h" -#include "../../physics/Hitbox.h" -#include "../../objects/Player.h" -#include "../../world/Level.h" -#include "../../world/World.h" -#include "../../content/Content.h" -#include "../../voxels/Block.h" -#include "../../voxels/Chunks.h" -#include "../../voxels/voxel.h" -#include "../../items/ItemDef.h" -#include "../../items/ItemStack.h" -#include "../../items/Inventory.h" -#include "../../items/Inventories.h" -#include "../../lighting/Lighting.h" -#include "../../logic/BlocksController.h" -#include "../../window/Window.h" -#include "../../engine.h" +#include "../../../files/files.h" +#include "../../../physics/Hitbox.h" +#include "../../../objects/Player.h" +#include "../../../world/Level.h" +#include "../../../world/World.h" +#include "../../../content/Content.h" +#include "../../../voxels/Block.h" +#include "../../../voxels/Chunks.h" +#include "../../../voxels/voxel.h" +#include "../../../items/ItemDef.h" +#include "../../../items/ItemStack.h" +#include "../../../items/Inventory.h" +#include "../../../items/Inventories.h" +#include "../../../lighting/Lighting.h" +#include "../../../logic/BlocksController.h" +#include "../../../window/Window.h" +#include "../../../engine.h" /* == file library == */ static int l_file_resolve(lua_State* L) { diff --git a/src/logic/scripting/api/libgui.cpp b/src/logic/scripting/api/libgui.cpp new file mode 100644 index 00000000..b9889fb0 --- /dev/null +++ b/src/logic/scripting/api/libgui.cpp @@ -0,0 +1,77 @@ +#include "libgui.h" + +#include +#include "../scripting.h" +#include "../lua_util.h" + +#include "../../../engine.h" +#include "../../../assets/Assets.h" +#include "../../../frontend/gui/UINode.h" +#include "../../../frontend/gui/controls.h" +#include "../../../frontend/UiDocument.h" +#include "../../../util/stringutil.h" + +static gui::UINode* getDocumentNode(lua_State* L, const std::string& name, const std::string& nodeName) { + auto doc = scripting::engine->getAssets()->getLayout(name); + if (doc == nullptr) { + luaL_error(L, "document '%s' not found", name.c_str()); + } + auto node = doc->get(nodeName); + if (node == nullptr) { + luaL_error(L, "document '%s' has no element with id '%s'", name.c_str(), nodeName.c_str()); + } + return node.get(); +} + +static bool getattr(lua_State* L, gui::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; + } + return false; +} + +static bool setattr(lua_State* L, gui::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; + } + return false; +} + +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 node = getDocumentNode(L, docname, element); + + if (attr == "color") { + return lua::pushcolor_arr(L, node->getColor()); + } else if (attr == "coord") { + return lua::pushvec2_arr(L, node->getCoord()); + } else if (attr == "size") { + return lua::pushvec2_arr(L, node->getSize()); + } + + if (getattr(L, dynamic_cast(node), attr)) + return 1; + + return 0; +} + +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 node = getDocumentNode(L, docname, element); + + if (setattr(L, dynamic_cast(node), attr)) + return 0; + + return 0; +} diff --git a/src/logic/scripting/api/libgui.h b/src/logic/scripting/api/libgui.h new file mode 100644 index 00000000..6b83e223 --- /dev/null +++ b/src/logic/scripting/api/libgui.h @@ -0,0 +1,15 @@ +#ifndef LOGIC_SCRIPTING_API_LIBGUI_H_ +#define LOGIC_SCRIPTING_API_LIBGUI_H_ + +#include + +extern int l_gui_getattr(lua_State* L); +extern int l_gui_setattr(lua_State* L); + +static const luaL_Reg guilib [] = { + {"getattr", l_gui_getattr}, + {"setattr", l_gui_setattr}, + {NULL, NULL} +}; + +#endif // LOGIC_SCRIPTING_API_LIBGUI_H_ diff --git a/src/logic/scripting/lua_util.h b/src/logic/scripting/lua_util.h index 2ad5c9e2..95761bde 100644 --- a/src/logic/scripting/lua_util.h +++ b/src/logic/scripting/lua_util.h @@ -2,6 +2,8 @@ #define LOGIC_SCRIPTING_LUA_UTIL_H_ #include +#include +#include "LuaState.h" namespace lua { inline int pushivec3(lua_State* L, luaint x, luaint y, luaint z) { @@ -10,6 +12,79 @@ namespace lua { lua_pushinteger(L, z); return 3; } + + inline int pushvec3(lua_State* L, glm::vec3 vec) { + lua_pushnumber(L, vec.x); + lua_pushnumber(L, vec.y); + lua_pushnumber(L, vec.z); + return 3; + } + + inline int pushvec4(lua_State* L, glm::vec4 vec) { + lua_pushnumber(L, vec.x); + lua_pushnumber(L, vec.y); + lua_pushnumber(L, vec.z); + lua_pushnumber(L, vec.w); + return 4; + } + + inline int pushvec2_arr(lua_State* L, glm::vec2 vec) { + lua_createtable(L, 2, 0); + lua_getglobal(L, "vec2_mt"); + lua_setmetatable(L, -2); + + lua_pushnumber(L, vec.x); + lua_rawseti(L, -2, 1); + lua_pushnumber(L, vec.y); + lua_rawseti(L, -2, 2); + return 1; + } + + inline int pushvec3_arr(lua_State* L, glm::vec3 vec) { + lua_createtable(L, 3, 0); + lua_getglobal(L, "vec3_mt"); + lua_setmetatable(L, -2); + + lua_pushnumber(L, vec.x); + lua_rawseti(L, -2, 1); + lua_pushnumber(L, vec.y); + lua_rawseti(L, -2, 2); + lua_pushnumber(L, vec.z); + lua_rawseti(L, -2, 3); + return 1; + } + + inline int pushvec4_arr(lua_State* L, glm::vec4 vec) { + lua_createtable(L, 4, 0); + lua_getglobal(L, "vec4_mt"); + lua_setmetatable(L, -2); + + lua_pushnumber(L, vec.x); + lua_rawseti(L, -2, 1); + lua_pushnumber(L, vec.y); + lua_rawseti(L, -2, 2); + lua_pushnumber(L, vec.z); + lua_rawseti(L, -2, 3); + lua_pushnumber(L, vec.w); + lua_rawseti(L, -2, 4); + return 1; + } + + inline int pushcolor_arr(lua_State* L, glm::vec4 vec) { + lua_createtable(L, 4, 0); + lua_getglobal(L, "color_mt"); + lua_setmetatable(L, -2); + + lua_pushinteger(L, vec.x*255); + lua_rawseti(L, -2, 1); + lua_pushinteger(L, vec.y*255); + lua_rawseti(L, -2, 2); + lua_pushinteger(L, vec.z*255); + lua_rawseti(L, -2, 3); + lua_pushinteger(L, vec.w*255); + lua_rawseti(L, -2, 4); + return 1; + } } #endif // LOGIC_SCRIPTING_LUA_UTIL_H_ diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index 9daf7c77..e4be8adf 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -16,6 +16,7 @@ #include "../../engine.h" #include "LuaState.h" #include "../../util/stringutil.h" +#include "../../util/timeutil.h" using namespace scripting; @@ -245,6 +246,7 @@ bool scripting::on_item_break_block(Player* player, const ItemDef* item, int x, } void scripting::on_ui_open(UiDocument* layout, Inventory* inventory) { + timeutil::ScopeLogTimer log(555); std::string name = layout->getId()+".open"; if (state->getglobal(name)) { state->pushinteger(inventory->getId());