#include "lua_commons.hpp" #include "api_lua.hpp" #include "lua_util.hpp" #include "LuaState.hpp" #include "../scripting.hpp" #include "../../../engine.hpp" #include "../../../assets/Assets.hpp" #include "../../../items/Inventories.hpp" #include "../../../graphics/ui/gui_util.hpp" #include "../../../graphics/ui/elements/UINode.hpp" #include "../../../graphics/ui/elements/Button.hpp" #include "../../../graphics/ui/elements/Image.hpp" #include "../../../graphics/ui/elements/CheckBox.hpp" #include "../../../graphics/ui/elements/TextBox.hpp" #include "../../../graphics/ui/elements/TrackBar.hpp" #include "../../../graphics/ui/elements/Panel.hpp" #include "../../../graphics/ui/elements/Menu.hpp" #include "../../../graphics/ui/elements/InventoryView.hpp" #include "../../../frontend/UiDocument.hpp" #include "../../../frontend/locale.hpp" #include "../../../util/stringutil.hpp" #include "../../../world/Level.hpp" 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*, const std::string& name, const std::string& nodeName) { auto doc = engine->getAssets()->getLayout(name); if (doc == nullptr) { throw std::runtime_error("document '"+name+"' not found"); } auto node = doc->get(nodeName); if (node == nullptr) { throw std::runtime_error("document '"+name+"' has no element with id '"+nodeName+"'"); } return {doc, node}; } static DocumentNode getDocumentNode(lua_State* L, int idx=1) { lua_getfield(L, idx, "docname"); lua_getfield(L, idx, "name"); auto docname = lua_tostring(L, -2); auto name = lua_tostring(L, -1); auto node = getDocumentNode(L, docname, name); lua_pop(L, 2); return node; } 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 l_menu_reset(lua_State* L) { auto node = getDocumentNode(L); auto menu = dynamic_cast(node.node.get()); menu->reset(); return 0; } static int l_textbox_paste(lua_State* L) { auto node = getDocumentNode(L); auto box = dynamic_cast(node.node.get()); auto text = lua_tostring(L, 2); box->paste(util::str2wstr_utf8(text)); return 0; } 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); try { auto subnode = guiutil::create(xmlsrc, docnode.document->getEnvironment()); node->add(subnode); UINode::getIndices(subnode, docnode.document->getMapWriteable()); } catch (const std::exception& err) { throw std::runtime_error(err.what()); } return 0; } static int l_container_clear(lua_State* L) { auto node = getDocumentNode(L, 1); if (auto container = std::dynamic_pointer_cast(node.node)) { container->clear(); } return 0; } static int l_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 p_get_inventory(UINode* node) { if (auto inventory = dynamic_cast(node)) { auto inv = inventory->getInventory(); return state->pushinteger(inv ? inv->getId() : 0); } return 0; } 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_paste(UINode* node) { if (dynamic_cast(node)) { return state->pushcfunction(l_textbox_paste); } 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_caret(UINode* node) { if (auto box = dynamic_cast(node)) { return state->pushinteger(static_cast(box->getCaret())); } 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_editable(UINode* node) { if (auto box = dynamic_cast(node)) { return state->pushboolean(box->isEditable()); } return 0; } static int p_get_src(UINode* node) { if (auto image = dynamic_cast(node)) { return state->pushstring(image->getTexture()); } 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_tooltip(UINode* node) { return state->pushstring(util::wstr2str_utf8(node->getTooltip())); } static int p_get_pos(UINode* node) { return lua::pushvec2_arr(state->getLua(), node->getPos()); } static int p_get_wpos(UINode* node) { return lua::pushvec2_arr(state->getLua(), node->calcPos()); } 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*) { return state->pushcfunction(l_move_into); } static int p_get_focused(UINode* node) { return state->pushboolean(node->isFocused()); } 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}, {"tooltip", p_get_tooltip}, {"pos", p_get_pos}, {"wpos", p_get_wpos}, {"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}, {"caret", p_get_caret}, {"text", p_get_text}, {"editable", p_get_editable}, {"src", p_get_src}, {"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}, {"paste", p_get_paste}, {"inventory", p_get_inventory}, {"focused", p_get_focused}, }; 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_tooltip(UINode* node, int idx) { node->setTooltip(util::str2wstr_utf8(state->tostring(idx))); } static void p_set_pos(UINode* node, int idx) { node->setPos(state->tovec2(idx)); } static void p_set_wpos(UINode* node, int idx) { node->setPos(state->tovec2(idx)-node->calcPos()); } 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_caret(UINode* node, int idx) { if (auto box = dynamic_cast(node)) { box->setCaret(static_cast(state->tointeger(idx))); } } static void p_set_editable(UINode* node, int idx) { if (auto box = dynamic_cast(node)) { box->setEditable(state->toboolean(idx)); } } static void p_set_src(UINode* node, int idx) { if (auto image = dynamic_cast(node)) { image->setTexture(state->requireString(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 void p_set_focused(std::shared_ptr node, int idx) { if (state->toboolean(idx) && !node->isFocused()) { scripting::engine->getGUI()->setFocus(node); } else if (node->isFocused()){ node->defocus(); } } static int l_gui_setattr(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> setters { {"color", p_set_color}, {"hoverColor", p_set_hover_color}, {"pressedColor", p_set_pressed_color}, {"tooltip", p_set_tooltip}, {"pos", p_set_pos}, {"wpos", p_set_wpos}, {"size", p_set_size}, {"interactive", p_set_interactive}, {"visible", p_set_visible}, {"enabled", p_set_enabled}, {"placeholder", p_set_placeholder}, {"text", p_set_text}, {"editable", p_set_editable}, {"src", p_set_src}, {"caret", p_set_caret}, {"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); } static const std::unordered_map,int)>> setters2 { {"focused", p_set_focused}, }; auto func2 = setters2.find(attr); if (func2 != setters2.end()) { func2->second(node, 4); } return 0; } static int l_gui_get_env(lua_State* L) { auto name = lua_tostring(L, 1); auto doc = scripting::engine->getAssets()->getLayout(name); if (doc == nullptr) { throw std::runtime_error("document '"+std::string(name)+"' not found"); } lua_getglobal(L, lua::LuaState::envName(*doc->getEnvironment()).c_str()); return 1; } static int l_gui_str(lua_State* L) { auto text = util::str2wstr_utf8(lua_tostring(L, 1)); if (!lua_isnoneornil(L, 2)) { auto context = util::str2wstr_utf8(lua_tostring(L, 2)); lua_pushstring(L, util::wstr2str_utf8(langs::get(text, context)).c_str()); } else { lua_pushstring(L, util::wstr2str_utf8(langs::get(text)).c_str()); } return 1; } static int l_gui_reindex(lua_State* L) { auto name = lua_tostring(L, 1); auto doc = scripting::engine->getAssets()->getLayout(name); if (doc == nullptr) { throw std::runtime_error("document '"+std::string(name)+"' not found"); } doc->rebuildIndices(); return 0; } /// @brief gui.get_locales_info() -> table of tables static int l_gui_get_locales_info(lua_State* L) { auto& locales = langs::locales_info; lua_createtable(L, 0, locales.size()); for (auto& entry : locales) { lua_createtable(L, 0, 1); lua_pushstring(L, entry.second.name.c_str()); lua_setfield(L, -2, "name"); lua_setfield(L, -2, entry.first.c_str()); } return 1; } static int l_gui_getviewport(lua_State* L) { return lua::pushvec2_arr(L, scripting::engine->getGUI()->getContainer()->getSize()); } const luaL_Reg guilib [] = { {"get_viewport", lua_wrap_errors}, {"getattr", lua_wrap_errors}, {"setattr", lua_wrap_errors}, {"get_env", lua_wrap_errors}, {"str", lua_wrap_errors}, {"reindex", lua_wrap_errors}, {"get_locales_info", lua_wrap_errors}, {NULL, NULL} };