diff --git a/assets/base/script/modules/gui.lua b/assets/base/script/modules/gui.lua index 2e0c4d6f..b2732d3b 100644 --- a/assets/base/script/modules/gui.lua +++ b/assets/base/script/modules/gui.lua @@ -5,31 +5,24 @@ setmetatable(env, {__index = _G}) -- create_element -- Build a GUI Element with the provided constructor data, apply the metatable. local function create_element(elem_type, data) - local elem = GuiElement.new(elem_type, data) - return elem + return GuiElement.new(elem_type, data) end -- register_element -- Add an element to the Gui namespace. local function register_element(key) if type(key) == "table" then - for _,v in pairs(key) do register_element(v) end + for _, v in pairs(key) do register_element(v) end return end env.Gui[key] = function(data) return create_element(key, data) end end -register_element({"Body", "Rect", "Text", "Model", "Button", "InventoryList"}) - --- pc --- Formats a number to be a percent string. -env.pc = function(num) - return tostring(num) .. "%" -end +register_element({ "Box", "Text" }) -- zepha.build_gui -- Allows you to Build UI Elements with the GUI namespace outside of a callback. -zepha.build_gui = function(fn) +zepha.gui = function(fn) setfenv(fn, env) return fn() end \ No newline at end of file diff --git a/assets/textures/ui/font.png b/assets/textures/ui/font.png index 870e4b5b..d784cee5 100644 Binary files a/assets/textures/ui/font.png and b/assets/textures/ui/font.png differ diff --git a/assets/textures/ui/font.xcf b/assets/textures/ui/font.xcf index 90477bda..118d98c0 100644 Binary files a/assets/textures/ui/font.xcf and b/assets/textures/ui/font.xcf differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b2480480..d6f5b2bd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -331,6 +331,6 @@ add_library(Zepha_Core client/gui/compound/GuiCellGraph.cpp client/gui/compound/GuiCellGraph.h client/gui/basic/GuiCells.cpp - client/gui/basic/GuiCells.h client/gui/Gui.h client/gui/Root.cpp client/gui/Root.h client/gui/BoxElement.cpp client/gui/BoxElement.h client/gui/Gui.cpp client/gui/Style.h client/gui/TextElement.cpp client/gui/TextElement.h client/gui/Expression.cpp client/gui/Expression.h) + client/gui/basic/GuiCells.h client/gui/Gui.h client/gui/Root.cpp client/gui/Root.h client/gui/BoxElement.cpp client/gui/BoxElement.h client/gui/Gui.cpp client/gui/Style.h client/gui/TextElement.cpp client/gui/TextElement.h client/gui/Expression.cpp client/gui/Expression.h client/gui/Style.cpp) target_include_directories(Zepha_Core PUBLIC .) \ No newline at end of file diff --git a/src/client/graph/Font.cpp b/src/client/graph/Font.cpp index e13a95c8..83c71a44 100644 --- a/src/client/graph/Font.cpp +++ b/src/client/graph/Font.cpp @@ -16,9 +16,9 @@ Font::Font(TextureAtlas& atlas, std::shared_ptr tex) : getCharWidths(atlas); } -unsigned int Font::getCharWidth(char c) { +u16 Font::getCharWidth(char c) { unsigned int index = static_cast(c) - 32; - if (index >= amountOfChars) throw std::runtime_error("Invalid char index."); + if (index >= C_COUNT) return charWidths[C_COUNT]; return charWidths[index]; } @@ -27,44 +27,44 @@ void Font::getCharWidths(TextureAtlas& atlas) { charWidths[0] = 2; - for (unsigned int i = 1; i < amountOfChars; i++) { - glm::vec2 charPos = { i % 18 * charWidth, std::floor(i / 18) * charHeight }; + for (u16 i = 1; i < C_COUNT + 1; i++) { + glm::vec2 charPos = { i % 18 * C_WIDTH, std::floor(i / 18) * C_HEIGHT }; - unsigned int xBase = static_cast(fontTex->pos.x) + static_cast(charPos.x); - unsigned int yBase = static_cast(fontTex->pos.y) + static_cast(charPos.y); + u32 xBase = static_cast(fontTex->pos.x) + static_cast(charPos.x); + u32 yBase = static_cast(fontTex->pos.y) + static_cast(charPos.y); - unsigned short width = 0; + u16 width = 0; - for (unsigned int j = 0; j < charWidth; j++) { + for (u16 j = 0; j < C_WIDTH; j++) { bool empty = true; - for (unsigned int k = 0; k < charHeight; k++) { - unsigned int xx = xBase + j; - unsigned int yy = yBase + k; + for (u16 k = 0; k < C_HEIGHT; k++) { + u32 xx = xBase + j; + u32 yy = yBase + k; - unsigned int offset = yy * static_cast(atlasSize.x) * 4 + xx * 4 + 3; + u32 offset = yy * static_cast(atlasSize.x) * 4 + xx * 4 + 3; if (data[offset] != 0) { empty = false; break; } } - if (!empty) width = static_cast(j); + if (!empty) width = static_cast(j); } charWidths[i] = width; } } -glm::vec4 Font::getCharUVs(char c) { - unsigned int index = static_cast(c) - 32; - if (index >= amountOfChars) throw std::runtime_error("Invalid char index."); +vec4 Font::getCharUVs(char c) { + u16 index = static_cast(c) - 32; + if (index >= C_COUNT) index = C_COUNT; - glm::vec2 charPos = { (index % 18) * charWidth, std::floor(index / 18) * charHeight }; - glm::vec4 uv = { + vec2 charPos = { (index % 18) * C_WIDTH, std::floor(index / 18) * C_HEIGHT }; + vec4 uv = { fontTex->uv.x + (charPos.x) / atlasSize.x, fontTex->uv.y + (charPos.y) / atlasSize.y, fontTex->uv.x + (charPos.x + getCharWidth(c) + 1) / atlasSize.x, - fontTex->uv.y + (charPos.y + charHeight) / atlasSize.y + fontTex->uv.y + (charPos.y + C_HEIGHT) / atlasSize.y }; return uv; diff --git a/src/client/graph/Font.h b/src/client/graph/Font.h index ac7f6688..eb028449 100644 --- a/src/client/graph/Font.h +++ b/src/client/graph/Font.h @@ -1,35 +1,29 @@ -// -// Created by aurailus on 13/08/19. -// - #pragma once -#include -#include -#include +#include "util/Types.h" class AtlasRef; - class TextureAtlas; class Font { - public: +public: Font() = default; Font(TextureAtlas& atlas, std::shared_ptr tex); - unsigned int getCharWidth(char c); + u16 getCharWidth(char c); - glm::vec4 getCharUVs(char c); + vec4 getCharUVs(char c); - const static unsigned int amountOfChars = 95; - const static unsigned int charWidth = 7; - const static unsigned int charHeight = 9; - private: + constexpr static u16 C_COUNT = 95; + constexpr static u16 C_WIDTH = 7; + constexpr static u16 C_HEIGHT = 9; + +private: void getCharWidths(TextureAtlas& atlas); - glm::vec2 atlasSize{}; + vec2 atlasSize {}; - std::shared_ptr fontTex = nullptr; - std::array charWidths{}; + sptr fontTex = nullptr; + array charWidths {}; }; diff --git a/src/client/gui/Element.cpp b/src/client/gui/Element.cpp index 7c3de565..33a73d93 100644 --- a/src/client/gui/Element.cpp +++ b/src/client/gui/Element.cpp @@ -24,6 +24,10 @@ ivec2 Gui::Element::getComputedSize() { return size; } +void Gui::Element::clear() { + children.clear(); +} + ivec2 Gui::Element::getComputedOuterSize() { let size = getComputedSize(); let margin = getStyle(StyleRule::MARGIN, {}); @@ -195,4 +199,4 @@ void Gui::Element::layoutChildren() { break; } } -} \ No newline at end of file +} diff --git a/src/client/gui/Element.h b/src/client/gui/Element.h index 621ac7a4..b68c1de0 100644 --- a/src/client/gui/Element.h +++ b/src/client/gui/Element.h @@ -79,6 +79,8 @@ namespace Gui { return elem; } + void clear(); + /** Returns the element's computed size. */ virtual ivec2 getComputedSize(); @@ -104,6 +106,7 @@ namespace Gui { for (const let& ss : stylesheets) { for (const string& className : props.classes) { const let& styles = ss.find(className); + if (styles == ss.end()) continue; const optional opt = styles->second.get(rule); if (opt) return *opt; } @@ -119,6 +122,7 @@ namespace Gui { for (const let& ss : stylesheets) { for (const string& className : props.classes) { const let& styles = ss.find(className); + if (styles == ss.end()) continue; const optional opt = styles->second.get(rule); if (opt) return *opt; } diff --git a/src/client/gui/Root.h b/src/client/gui/Root.h index 22fc7c64..f3006bc2 100644 --- a/src/client/gui/Root.h +++ b/src/client/gui/Root.h @@ -1,3 +1,5 @@ +#pragma once + #include #include "client/gui/Gui.h" diff --git a/src/client/gui/Style.cpp b/src/client/gui/Style.cpp new file mode 100644 index 00000000..664aec38 --- /dev/null +++ b/src/client/gui/Style.cpp @@ -0,0 +1,20 @@ +#include "Style.h" + +const std::unordered_map Gui::Style::RULE_STRINGS_TO_ENUMS = { + { "pos", StyleRule::POS }, + { "size", StyleRule::SIZE }, + { "margin", StyleRule::MARGIN }, + { "padding", StyleRule::PADDING }, + { "GAP", StyleRule::GAP }, + { "layout", StyleRule::LAYOUT }, + { "direction", StyleRule::DIRECTION }, + { "h_align", StyleRule::H_ALIGN }, + { "v_align", StyleRule::V_ALIGN }, + { "cursor", StyleRule::CURSOR }, + { "overflow", StyleRule::OVERFLOW }, + { "background", StyleRule::BACKGROUND }, + { "background_hover", StyleRule::BACKGROUND_HOVER }, + { "content", StyleRule::CONTENT }, + { "text_size", StyleRule::TEXT_SIZE }, + { "text_color", StyleRule::TEXT_COLOR } +}; \ No newline at end of file diff --git a/src/client/gui/Style.h b/src/client/gui/Style.h index eeb61052..dba67711 100644 --- a/src/client/gui/Style.h +++ b/src/client/gui/Style.h @@ -22,7 +22,9 @@ namespace Gui { BACKGROUND, BACKGROUND_HOVER, - CONTENT + CONTENT, + TEXT_SIZE, + TEXT_COLOR }; enum class ValueType { @@ -180,6 +182,8 @@ namespace Gui { } std::unordered_map rules {}; + + const static std::unordered_map RULE_STRINGS_TO_ENUMS; }; typedef std::unordered_map StyleSheet; diff --git a/src/client/gui/TextElement.cpp b/src/client/gui/TextElement.cpp index 5690d8c6..b605f66a 100644 --- a/src/client/gui/TextElement.cpp +++ b/src/client/gui/TextElement.cpp @@ -36,7 +36,7 @@ void Gui::TextElement::updateElement() { } vec3 offset = {}; - u32 h = Font::charHeight; + u32 h = Font::C_HEIGHT; bool bold = false; bool italic = false; @@ -192,9 +192,12 @@ void Gui::TextElement::updateElement() { } - entity.setScale(PX_SCALE * (2/3.f)); -// entity.setScale(vec3(getComputedSize() * static_cast(PX_SCALE), 0)); - entity.setPos(vec3(getComputedScreenPos() * static_cast(PX_SCALE), 0)); + let scale = getStyle(StyleRule::TEXT_SIZE, 3.f); + let margin = getStyle(StyleRule::MARGIN, {}); + + entity.setScale(vec3(scale, scale, 0)); + entity.setPos(vec3(getComputedScreenPos() + ivec2 { margin.x, margin.y }, 0)); + Element::updateElement(); } diff --git a/src/client/menu/MenuSandbox.cpp b/src/client/menu/MenuSandbox.cpp index d2292de2..b449baae 100644 --- a/src/client/menu/MenuSandbox.cpp +++ b/src/client/menu/MenuSandbox.cpp @@ -1,7 +1,7 @@ - #include #include #include +#include #include "MenuSandbox.h" @@ -9,29 +9,25 @@ #include "client/Client.h" #include "lua/ErrorFormatter.h" #include "client/menu/SubgameDef.h" -#include "client/gui/basic/GuiText.h" -#include "client/gui/basic/GuiContainer.h" // Modules #include "lua/modules/Time.h" #include "lua/modules/mSetGui.h" #include "lua/modules/mStartGame.h" +#include "lua/usertype/LuaGuiElement.h" -MenuSandbox::MenuSandbox(glm::ivec2& win, Client& client, std::shared_ptr container) : +MenuSandbox::MenuSandbox(Client& client, Gui::Root& root, sptr sandboxRoot) : LuaParser(*client.game), - win(win), - client(client) -// container(container), -// luaContainer(std::dynamic_pointer_cast(container->add(std::make_shared("__lua")))) -// builder(client.game->textures, client.game->models, luaContainer) {} -{} + client(client), + root(root), + sandboxRoot(sandboxRoot) {} void MenuSandbox::reset() { // container->remove("error"); -// builder.clear(true); + sandboxRoot->clear(); core = {}; mod = {}; - lua = sol::state{}; + lua = sol::state {}; lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::math, sol::lib::table, sol::lib::debug); loadApi(); @@ -46,9 +42,10 @@ void MenuSandbox::loadApi() { modules.emplace_back(std::make_unique(Api::State::CLIENT, lua, core)); + Api::Usertype::GuiElement::bind(lua, core, root); // ClientApi::gui_element(lua); -// MenuApi::set_gui(builder, win, lua, core); + MenuApi::set_gui(lua, core, sandboxRoot); MenuApi::start_game(client, core); bindModules(); @@ -60,14 +57,15 @@ void MenuSandbox::loadApi() { void MenuSandbox::load(const SubgameDef& subgame) { reset(); + subgameName = subgame.config.name; - try { - loadAndRunMod(subgame.subgamePath + "/../../assets/base"); - loadAndRunMod(subgame.subgamePath + "/menu"); - } - catch (const std::runtime_error& e) { - showError(e.what(), subgame.config.name); - } +// try { + loadAndRunMod(subgame.subgamePath + "/../../assets/base"); + loadAndRunMod(subgame.subgamePath + "/menu"); +// } +// catch (const std::runtime_error& e) { +// showError(e.what(), subgame.config.name); +// } } void MenuSandbox::windowResized() { @@ -79,7 +77,7 @@ void MenuSandbox::update(double delta) { core["__builtin"]["update_delayed_functions"](); } -sol::protected_function_result MenuSandbox::runFileSandboxed(const std::string& file) { +sol::protected_function_result MenuSandbox::runFileSandboxed(const string& file) { for (LuaMod::File& f : mod.files) { if (f.path != file) continue; @@ -94,18 +92,18 @@ sol::protected_function_result MenuSandbox::runFileSandboxed(const std::string& throw std::runtime_error("Error opening '" + file + "', file not found."); } -void MenuSandbox::loadAndRunMod(const std::string& modPath) { +void MenuSandbox::loadAndRunMod(const string& modPath) { if (!cf_file_exists(modPath.data())) throw std::runtime_error("Directory not found."); LuaMod mod; - std::string root = modPath + "/script"; + string root = modPath + "/script"; - std::list dirsToScan{ root }; - std::list luaFiles{}; + std::list dirsToScan{ root }; + std::list luaFiles{}; cf_dir_t dir; while (!dirsToScan.empty()) { - std::string dirStr = *dirsToScan.begin(); + string dirStr = *dirsToScan.begin(); dirsToScan.erase(dirsToScan.begin()); if (!cf_file_exists(dirStr.data())) throw std::runtime_error("Missing 'script' directory."); @@ -131,9 +129,9 @@ void MenuSandbox::loadAndRunMod(const std::string& modPath) { mod.modPath = modPath; - for (std::string& file : luaFiles) { + for (string& file : luaFiles) { size_t rootPos = file.find(root); - std::string modPath = file; + string modPath = file; if (rootPos == std::string::npos) throw std::runtime_error("Attempted to access file \"" + file + "\", which is outside of the mod root."); @@ -142,66 +140,67 @@ void MenuSandbox::loadAndRunMod(const std::string& modPath) { modPath.resize(modPath.size() - 4); std::ifstream t(file); - std::string fileStr((std::istreambuf_iterator(t)), std::istreambuf_iterator()); + string fileStr((std::istreambuf_iterator(t)), std::istreambuf_iterator()); - LuaMod::File f{ modPath, fileStr }; + LuaMod::File f { modPath, fileStr }; mod.files.push_back(f); } - std::string texPath = modPath + "/textures"; - if (cf_file_exists(texPath.data())) { - this->modAssets = client.game->textures.loadDirectory(texPath, false, true); - } + string texPath = modPath + "/textures"; + if (cf_file_exists(texPath.data())) + menuAssets = client.game->textures.loadDirectory(texPath, false, true); this->mod = mod; runFileSandboxed("init"); } -void MenuSandbox::showError(const std::string& what, const std::string& subgame) { - const std::string errPrefixText = "Encountered an error while loading the menu for " + subgame + " ;-;"; -// Font f(client.game->textures, client.game->textures["font"]); - -// auto errWrap = std::make_shared("error"); -// container->add(errWrap); - -// auto errPrefix = std::make_shared("error_text"); -// errPrefix->create({ 3, 3 }, {}, { 0.7, 0, 0.3, 1 }, { 1, 1, 1, 1 }, f); -// errPrefix->setText(errPrefixText); -// errPrefix->setPos({ 8, 16 }); -// errWrap->add(errPrefix); - -// auto errMsg = std::make_shared("error_text"); -// errMsg->create({ 3, 3 }, {}, {}, { 1, 0.5, 0.6, 1 }, f); -// errMsg->setText(what); -// errMsg->setPos({ 8, 52 }); -// errWrap->add(errMsg); +void MenuSandbox::showError(const string& err) { + const string errPrefixText = "`cfEncountered an error while loading the menu for '" + subgameName + "' ;-;\n\n`r"; + + using Expr = Gui::Expression; + sandboxRoot->append({ + .styles = {{ + { Gui::StyleRule::CONTENT, errPrefixText + err }, + { Gui::StyleRule::TEXT_SIZE, Expr("2px") }, + { Gui::StyleRule::SIZE, array { Expr("100dp"), Expr("-1") } }, + { Gui::StyleRule::MARGIN, array { Expr("4dp"), Expr("4dp"), Expr("4dp"), Expr("4dp") } } + }} + }); } -sol::protected_function_result MenuSandbox::errorCallback(sol::protected_function_result r) const { - sol::error err = r; - std::string errString = err.what(); +sol::protected_function_result MenuSandbox::errorCallback(sol::protected_function_result r) { + string err = static_cast(r).what(); - try { - std::string::size_type lineNumStart = errString.find(':'); - if (lineNumStart == std::string::npos) throw std::out_of_range("Improperly formatted error. [0]"); - std::string::size_type lineNumEnd = errString.find(':', lineNumStart + 1); - if (lineNumEnd == std::string::npos) throw std::out_of_range("Improperly formatted error. [1]"); - - std::string fileName = errString.substr(0, lineNumStart); - int lineNum = std::stoi(errString.substr(lineNumStart + 1, lineNumEnd - lineNumStart - 1)); - - for (const LuaMod::File& file : mod.files) - if (file.path == fileName) - throw std::runtime_error(ErrorFormatter::formatError(fileName, lineNum, errString, file.file)); - - throw std::out_of_range("Error thrown outside of handled files. [2]"); + std::cout << Log::err << err << Log::endl; + + vec lines; + { + string line; + std::stringstream textStream(err); + while (std::getline(textStream, line, '\n')) lines.emplace_back(line); } - catch (const std::runtime_error& e) { - std::cout << Log::err << e.what() << std::endl; - throw; - } - catch (const std::out_of_range& e) { - std::cout << Log::err << "Failed to format error, " << e.what() << Log::endl; - throw std::runtime_error(errString); + + for (const let& line : lines) { + usize lineNumStart = line.find(':'); + if (lineNumStart == string::npos) continue; + usize lineNumEnd = line.find(':', lineNumStart + 1); + if (lineNumEnd == string::npos) continue; + + string fileName = line.substr(0, lineNumStart); + fileName.erase(std::remove_if(fileName.begin(), fileName.end(), isspace), fileName.end()); + + for (const let& file : mod.files) { + if (file.path == fileName) { + let msg = ErrorFormatter::formatError(fileName, + std::stoi(line.substr(lineNumStart + 1, lineNumEnd - lineNumStart - 1)), + err, file.file); + + showError(msg); + return r; + } + } } + + showError(err); + return r; } diff --git a/src/client/menu/MenuSandbox.h b/src/client/menu/MenuSandbox.h index 8ac5b4e3..37ab1178 100644 --- a/src/client/menu/MenuSandbox.h +++ b/src/client/menu/MenuSandbox.h @@ -7,6 +7,8 @@ #include "lua/LuaParser.h" #include "lua/LuaMod.h" +#include "client/gui/Root.h" +#include "client/gui/Element.h" #include "client/gui/GuiBuilder.h" class Client; @@ -16,8 +18,8 @@ class SubgameDef; class GuiContainer; class MenuSandbox : LuaParser { - public: - MenuSandbox(glm::ivec2& window, Client& client, std::shared_ptr container); +public: + MenuSandbox(Client& client, Gui::Root& root, sptr sandboxRoot); void load(const SubgameDef& subgame); @@ -26,28 +28,27 @@ class MenuSandbox : LuaParser { void windowResized(); using LuaParser::update; - private: + +private: void reset(); void loadApi(); - void loadAndRunMod(const std::string& modPath); + void loadAndRunMod(const string& modPath); - void showError(const std::string& what, const std::string& subgame); + void showError(const string& err); - sol::protected_function_result runFileSandboxed(const std::string& file); + sol::protected_function_result runFileSandboxed(const string& file); - virtual sol::protected_function_result errorCallback(sol::protected_function_result r) const override; + virtual sol::protected_function_result errorCallback(sol::protected_function_result r) override; LuaMod mod {}; - std::vector> modAssets{}; - -// GuiRoot gui; - -// std::shared_ptr container = nullptr; -// std::shared_ptr luaContainer = nullptr; -// GuiBuilder builder; + string subgameName; Client& client; - glm::ivec2& win; + + Gui::Root& root; + sptr sandboxRoot; + vec> menuAssets {}; + }; diff --git a/src/client/scene/MainMenuScene.cpp b/src/client/scene/MainMenuScene.cpp index 74b7f611..3da4fe10 100644 --- a/src/client/scene/MainMenuScene.cpp +++ b/src/client/scene/MainMenuScene.cpp @@ -17,36 +17,34 @@ #include "client/gui/compound/GuiImageButton.h" MainMenuScene::MainMenuScene(Client& client) : Scene(client), - root(client.renderer.window, client.game->textures) { + root(client.renderer.window, client.game->textures), + sandboxElem(root.create({ .classes = { "sandbox" }})), + sandbox(client, root, sandboxElem) { client.renderer.setClearColor(0, 0, 0); client.renderer.window.input.setMouseLocked(false); - root.body->setStyle(Gui::StyleRule::BACKGROUND, string("#123")); + using Expr = Gui::Expression; root.addStylesheet({ - { "sandbox", {{ - { Gui::StyleRule::H_ALIGN, string("center") }, - { Gui::StyleRule::V_ALIGN, string("center") } - }}}, { "navigation", {{ - { Gui::StyleRule::SIZE, array { Gui::Expression("-1"), Gui::Expression("18dp") } } + { Gui::StyleRule::SIZE, array { Expr("-1"), Expr("18dp") } } }}}, { "navigationWrap", {{ { Gui::StyleRule::DIRECTION, string("row") }, - { Gui::StyleRule::POS, array { Gui::Expression("0"), Gui::Expression("0") } } + { Gui::StyleRule::POS, array { Expr("0"), Expr("0") } } }}}, { "navigationBackground", {{ - { Gui::StyleRule::SIZE, array { Gui::Expression("64dp"), Gui::Expression("18dp") } }, + { Gui::StyleRule::SIZE, array { Expr("64dp"), Expr("18dp") } }, { Gui::StyleRule::BACKGROUND, string("menu_bar_bg") } }}}, { "navigationButton", {{ - { Gui::StyleRule::SIZE, array { Gui::Expression("16dp"), Gui::Expression("16dp") } }, + { Gui::StyleRule::SIZE, array { Expr("16dp"), Expr("16dp") } }, { Gui::StyleRule::CURSOR, string("pointer") } }}} }); - let sandbox = root.body->append({ .classes = { "sandbox" } }); + root.body->append(sandboxElem); let navigation = root.body->append({ .classes = { "navigation" } }); let navigationBG = navigation->append({ .classes = { "navigationWrap" } }); @@ -56,9 +54,8 @@ MainMenuScene::MainMenuScene(Client& client) : Scene(client), let navigationList = navigation->append({ .classes = { "navigationWrap" }, .styles = {{ - { Gui::StyleRule::PADDING, array - { Gui::Expression("1dp"), Gui::Expression("1dp"), Gui::Expression("1dp"), Gui::Expression("1dp") } }, - { Gui::StyleRule::GAP, array { Gui::Expression("1dp"), Gui::Expression("1dp") } } + { Gui::StyleRule::PADDING, array { Expr("1dp"), Expr("1dp"), Expr("1dp"), Expr("1dp") } }, + { Gui::StyleRule::GAP, array { Expr("1dp"), Expr("1dp") } } }} }); @@ -81,9 +78,8 @@ MainMenuScene::MainMenuScene(Client& client) : Scene(client), navigationList->append({ .styles = {{ { Gui::StyleRule::BACKGROUND, string("#fff5") }, - { Gui::StyleRule::SIZE, array { Gui::Expression("1dp"), Gui::Expression("10dp") } }, - { Gui::StyleRule::MARGIN, array - { Gui::Expression("2dp"), Gui::Expression("3dp"), Gui::Expression("2dp"), Gui::Expression("3dp") } } + { Gui::StyleRule::SIZE, array { Expr("1dp"), Expr("10dp") } }, + { Gui::StyleRule::MARGIN, array { Expr("2dp"), Expr("3dp"), Expr("2dp"), Expr("3dp") } } }} }); @@ -108,7 +104,7 @@ MainMenuScene::MainMenuScene(Client& client) : Scene(client), if (subgames.size() > 0) { selectedSubgame = &subgames[0]; -// sandbox.load(*selectedSubgame); + sandbox.load(*selectedSubgame); } navigationList->append(); diff --git a/src/client/scene/MainMenuScene.h b/src/client/scene/MainMenuScene.h index e44e2f15..7a2cbcdb 100644 --- a/src/client/scene/MainMenuScene.h +++ b/src/client/scene/MainMenuScene.h @@ -28,11 +28,16 @@ private: /** Find valid subgames in the subgames folder. */ void findSubgames(); + + /** The GUI root. */ + Gui::Root root; + + /** The GUI sandbox element root. */ + sptr sandboxElem; /** Provides the API for menu mods. */ -// MenuSandbox sandbox; - Gui::Root root; - + MenuSandbox sandbox; + /** A list of found subgames. */ vec subgames; diff --git a/src/lua/ErrorFormatter.cpp b/src/lua/ErrorFormatter.cpp index 139a93a7..189ed84c 100644 --- a/src/lua/ErrorFormatter.cpp +++ b/src/lua/ErrorFormatter.cpp @@ -4,23 +4,25 @@ #include #include +#include #include #include "ErrorFormatter.h" -#include "../util/Log.h" - -std::string -ErrorFormatter::formatError(const string& fileName, usize line, const string& stack, string file, - bool ansiColors) noexcept { - const string red = (ansiColors ? Log::red : ""); - const string unbl = (ansiColors ? Log::unbl : ""); - const string endl = (ansiColors ? Log::endl : "\n"); +std::string ErrorFormatter::formatError(const string& fileName, usize line, + const string& stack, string file, bool ansiColors) noexcept { + const string RED = "`cf"; + const string LTGRAY = "`c1"; + const string GRAY = "`c2"; + const string BOLD = "`b"; + const string UNDL = "`u"; + const string ENDL = "`r\n"; - std::stringstream out{}; + std::stringstream out {}; - // Split the file into lines, and add them to a vector - vec fileLines{}; + out << BOLD << UNDL << fileName << ".lua" << ENDL << "\n"; + + vec fileLines {}; usize pos = 0; string token; @@ -33,14 +35,28 @@ ErrorFormatter::formatError(const string& fileName, usize line, const string& st while (fileLines.back() == "") fileLines.pop_back(); - // Format and add lines to the stringstream - for (usize i = (std::max)(static_cast(0), line - 6); i < (std::min)(fileLines.size(), line + 5); i++) { - for (usize j = 0; j < 3 - std::to_string(i + 1).length(); j++) out << " "; - out << red << (i + 1 == line ? unbl : "") << (i + 1) << (i + 1 == line ? " # " : " | ") << fileLines[i] << endl; + usize printStart = (std::max)(0, static_cast(line - LOOK_AROUND - 1)); + usize printEnd = (std::min)(fileLines.size(), line + LOOK_AROUND); + + if (printStart != 0) { + for (usize j = 0; j < 3 - std::to_string(printStart).length(); j++) out << " ` ` "; + out << GRAY << printStart << " | -- snip --" << ENDL; } - // Add the stack trace at the bottom - out << endl << red << stack << endl; + for (i32 i = printStart; i < printEnd; i++) { + for (usize j = 0; j < 3 - std::to_string(i + 1).length(); j++) out << " ` ` "; + out << (i + 1 == line ? RED : LTGRAY) << (i + 1) + << (i + 1 == line ? "" : "`cr") + << " | " << (i + 1 == line ? BOLD : "") + << fileLines[i] << ENDL; + } + + if (printEnd != fileLines.size()) { + for (usize j = 0; j < 3 - std::to_string(printEnd + 1).length(); j++) out << " ` ` "; + out << GRAY << (printEnd + 1) << " | -- snip --" << ENDL; + } + + out << "\n" << BOLD << UNDL << "Traceback" << ENDL << "\n" << RED << stack << ENDL; return out.str(); } diff --git a/src/lua/ErrorFormatter.h b/src/lua/ErrorFormatter.h index a30d0dbf..553a4568 100644 --- a/src/lua/ErrorFormatter.h +++ b/src/lua/ErrorFormatter.h @@ -10,4 +10,6 @@ class ErrorFormatter { public: static string formatError(const string& fileName, usize line, const string& stack, string file, bool ansiColors = true) noexcept; + + constexpr static i32 LOOK_AROUND = 4; }; diff --git a/src/lua/LocalLuaParser.cpp b/src/lua/LocalLuaParser.cpp index df7973fc..22f8ce4a 100644 --- a/src/lua/LocalLuaParser.cpp +++ b/src/lua/LocalLuaParser.cpp @@ -62,7 +62,7 @@ void LocalLuaParser::loadApi(WorldPtr world, PlayerPtr player) { core["__builtin"] = lua.create_table(); // Types - ClientApi::gui_element(lua); +// ClientApi::gui_element(lua); Api::Usertype::Target::bind(Api::State::CLIENT, lua, core); Api::Usertype::Entity::bind(Api::State::CLIENT, lua, core); @@ -116,7 +116,7 @@ void LocalLuaParser::loadApi(WorldPtr world, PlayerPtr player) { lua.set_function("runfile", &LocalLuaParser::runFileSandboxed, this); } -sol::protected_function_result LocalLuaParser::errorCallback(sol::protected_function_result r) const { +sol::protected_function_result LocalLuaParser::errorCallback(sol::protected_function_result r) { sol::error err = r; std::string errString = err.what(); diff --git a/src/lua/LocalLuaParser.h b/src/lua/LocalLuaParser.h index 45ac2ba8..c8ffb880 100644 --- a/src/lua/LocalLuaParser.h +++ b/src/lua/LocalLuaParser.h @@ -28,7 +28,7 @@ class LocalLuaParser : public LuaParser { private: void loadApi(WorldPtr world, PlayerPtr player); - virtual sol::protected_function_result errorCallback(sol::protected_function_result r) const override; + virtual sol::protected_function_result errorCallback(sol::protected_function_result r) override; sol::protected_function_result runFileSandboxed(const std::string& file); diff --git a/src/lua/LuaKeybindHandler.h b/src/lua/LuaKeybindHandler.h index 834d4a45..202da89b 100644 --- a/src/lua/LuaKeybindHandler.h +++ b/src/lua/LuaKeybindHandler.h @@ -26,5 +26,5 @@ class LuaKeybindHandler { std::array, 1024> callbacksDown{}; std::array, 1024> callbacksUp{}; - const LocalLuaParser* parser; + LocalLuaParser* parser; }; \ No newline at end of file diff --git a/src/lua/LuaParser.h b/src/lua/LuaParser.h index 929610e4..b2786d48 100644 --- a/src/lua/LuaParser.h +++ b/src/lua/LuaParser.h @@ -26,13 +26,13 @@ class LuaParser { void bindModules(); template - sol::protected_function_result safe_function(sol::protected_function f, Args... args) const { + sol::protected_function_result safe_function(sol::protected_function f, Args... args) { auto res = f(args...); if (!res.valid()) errorCallback(res); return res; } - virtual sol::protected_function_result errorCallback(sol::protected_function_result r) const = 0; + virtual sol::protected_function_result errorCallback(sol::protected_function_result r) = 0; Subgame& game; diff --git a/src/lua/ServerLuaParser.cpp b/src/lua/ServerLuaParser.cpp index e2848b0c..02e6c171 100644 --- a/src/lua/ServerLuaParser.cpp +++ b/src/lua/ServerLuaParser.cpp @@ -145,7 +145,7 @@ void ServerLuaParser::loadApi(WorldPtr world) { lua.set_function("runfile", &ServerLuaParser::runFileSandboxed, this); } -sol::protected_function_result ServerLuaParser::errorCallback(sol::protected_function_result r) const { +sol::protected_function_result ServerLuaParser::errorCallback(sol::protected_function_result r) { sol::error err = r; std::string errString = err.what(); diff --git a/src/lua/ServerLuaParser.h b/src/lua/ServerLuaParser.h index 4c46b38d..41e50f79 100644 --- a/src/lua/ServerLuaParser.h +++ b/src/lua/ServerLuaParser.h @@ -33,7 +33,7 @@ public: private: void loadApi(WorldPtr world); - virtual sol::protected_function_result errorCallback(sol::protected_function_result r) const override; + virtual sol::protected_function_result errorCallback(sol::protected_function_result r) override; sol::protected_function_result runFileSandboxed(const std::string& file); diff --git a/src/lua/modules/mSetGui.h b/src/lua/modules/mSetGui.h index 70be2f7f..41c15062 100644 --- a/src/lua/modules/mSetGui.h +++ b/src/lua/modules/mSetGui.h @@ -1,7 +1,3 @@ -// -// Created by aurailus on 2019-12-12. -// - #pragma once #include "lua/Lua.h" @@ -10,10 +6,10 @@ class LuaGuiElement; namespace MenuApi { -// void set_gui(GuiBuilder& builder, glm::ivec2& win, sol::state& lua, sol::table& core) { -// core.set_function("set_gui", [&](std::shared_ptr gui) { -// builder.setGuiRoot(gui); -// builder.build(win); -// }); -// } + void set_gui(sol::state& lua, sol::table& core, sptr& root) { + core.set_function("set_gui", [&](sptr elem) { + root->clear(); + root->append(elem); + }); + } } diff --git a/src/lua/usertype/ItemStack.h b/src/lua/usertype/ItemStack.h index 0ac38135..f242c5c8 100644 --- a/src/lua/usertype/ItemStack.h +++ b/src/lua/usertype/ItemStack.h @@ -12,12 +12,11 @@ #include "../../util/CovariantPtr.h" class Subgame; - class ItemStack; namespace Api::Usertype { class ItemStack : SubgameUsertype { - public: + public: ItemStack() = default; explicit ItemStack(sol::table tbl); @@ -38,7 +37,7 @@ namespace Api::Usertype { static void bind(State state, sol::state& lua, sol::table& core); - private: + private: std::string name; unsigned short count; }; diff --git a/src/lua/usertype/LuaGuiElement.cpp b/src/lua/usertype/LuaGuiElement.cpp index a90b8a83..309f6f13 100644 --- a/src/lua/usertype/LuaGuiElement.cpp +++ b/src/lua/usertype/LuaGuiElement.cpp @@ -1,180 +1,297 @@ -// -// Created by aurailus on 2020-04-12. -// - -#include -#include - #include "LuaGuiElement.h" -#include "client/gui/SerialGui.h" +#include "client/gui/Gui.h" +#include "client/gui/Root.h" +#include "client/gui/Element.h" +#include "client/gui/BoxElement.h" +#include "client/gui/TextElement.h" -std::shared_ptr LuaGuiElement::create(const std::string& type, sol::table data) { - auto elem = std::make_shared(); - elem->type = type; +static const Gui::Expression parseObjectToExpr(sol::object value) { + if (value.is()) return Gui::Expression(std::to_string(value.as()) + "dp"); + if (value.is()) return Gui::Expression(value.as()); + throw std::invalid_argument("Object cannot be converted to an expression."); +} + +template +static const array parseLengthTableVal(sol::object value) { + array arr {}; - for (const auto& pair : data) { - if (pair.first.is()) { - if (!pair.second.is>()) continue; - elem->children.push_back(pair.second.as>()); - elem->children.back()->parent = elem.get(); - } - else if (pair.first.is()) elem->set_trait(pair.first.as(), pair.second); + if (value.is()) { + const let& t = value.as(); + + vec exprs {}; + exprs.reserve(t.size()); + for (let& v : t) exprs.emplace_back(parseObjectToExpr(v.second)); + + for (usize i = 0; i < arr.size() / exprs.size(); i++) + for (usize j = 0; j < exprs.size(); j++) + arr[j + i * exprs.size()] = exprs[j]; + + return arr; + } + + let v = parseObjectToExpr(value); + for (usize i = 0; i < arr.size(); i++) arr[i] = v; + return arr; + + throw std::invalid_argument("Invalid length table configuration."); +} + +void Api::Usertype::GuiElement::parseRule(const string& ruleStr, const sol::object& value, Gui::Style& styles) { + using namespace Gui; + + const let ruleIt = Style::RULE_STRINGS_TO_ENUMS.find(ruleStr); + if (ruleIt == Style::RULE_STRINGS_TO_ENUMS.end()) + throw std::invalid_argument("Style rule '" + ruleStr + "' doesn't exist."); + const StyleRule rule = ruleIt->second; + + switch (rule) { + default: + throw std::invalid_argument("Unhandled rule '" + ruleStr + "'! This is an engine error!"); + + case StyleRule::LAYOUT: + case StyleRule::DIRECTION: + case StyleRule::H_ALIGN: + case StyleRule::V_ALIGN: + case StyleRule::CURSOR: + case StyleRule::OVERFLOW: + case StyleRule::TEXT_COLOR: + case StyleRule::BACKGROUND: + case StyleRule::BACKGROUND_HOVER: + case StyleRule::CONTENT: + styles.rules[rule] = value.as(); + break; + + case StyleRule::POS: + case StyleRule::SIZE: + case StyleRule::GAP: + styles.rules[rule] = parseLengthTableVal<2>(value); + break; + + case StyleRule::MARGIN: + case StyleRule::PADDING: + styles.rules[rule] = parseLengthTableVal<4>(value); + break; + + case StyleRule::TEXT_SIZE: + styles.rules[rule] = parseObjectToExpr(value); + break; + } +} + +std::shared_ptr Api::Usertype::GuiElement::create(const string& type, sol::table data, Gui::Root& root) { + Gui::Element::Props props {}; + + for (let& style : data) { + if (!style.first.is()) continue; + GuiElement::parseRule(style.first.as(), style.second, props.styles); + } + + sptr elem = nullptr; + switch (Util::hash(type.data())) { + default: throw std::invalid_argument("Invalid element type '" + type + "'."); + case Util::hash("Box"): elem = root.create(props); break; + case Util::hash("Text"): elem = root.create(props); break; + } + + for (usize i = 1; i <= data.size(); i++) { + const sol::object& child = data.get(i); + if (!child.is>()) continue; + elem->append(child.as>()); } return elem; -} - -sol::object LuaGuiElement::get_trait(sol::this_state s, const std::string& key) { - if (key == "key") return sol::make_object(s, this->key); - if (key == "type") return sol::make_object(s, this->type); - if (traits.count(key)) return traits.at(key); - return sol::nil; -} - -sol::object LuaGuiElement::set_trait(const std::string& key, sol::object val) { - if (key == "callbacks") { - callbacks.clear(); - for (auto pair : val.as()) callbacks[pair.first.as()] = pair.second.as(); - } - else if (key == "key") { - this->key = val.as(); - } - else { - traits.erase(key); - traits.emplace(key, val); - } - - if (updateFunction) updateFunction(); - return val; -} - -sol::object LuaGuiElement::call(sol::this_state s, sol::protected_function fun) { - sol::table tbl = sol::state_view(s)["zepha"]["__builtin"]["gui_env"]; - sol::environment env(s, sol::create, tbl); - - sol::set_environment(env, fun); - return fun(this); -} - -sol::object LuaGuiElement::get_child(sol::this_state s, sol::object key) { - if (key.is() && key.as() <= children.size()) { - auto begin = children.begin(); - std::advance(begin, key.as() - 1); - return sol::make_object>(s, *begin); - } - else if (key.is()) { - for (auto& child : children) { - if (child->key == key.as()) return sol::make_object>(s, child); - } - - for (auto& child : children) { - auto recurse = child->get_child(s, key); - if (recurse) return recurse; - } - } - - return sol::nil; -} - -void LuaGuiElement::append(sol::this_state s, sol::object elem) { - if (elem.is>()) children.push_back(elem.as>()); - else if (elem.is()) - children.push_back(call(s, elem.as()).as>()); - else throw std::runtime_error("Append arg is not an element or a function to generate one."); - - children.back()->parent = this; - if (updateFunction) updateFunction(); -} - -void LuaGuiElement::prepend(sol::this_state s, sol::object elem) { - if (elem.is>()) - children.insert(children.begin(), elem.as>()); - else if (elem.is()) - children.insert(children.begin(), call(s, elem.as()).as>()); - else throw std::runtime_error("Append arg is not an element or a function to generate one."); - - children.front()->parent = this; - if (updateFunction) updateFunction(); -} - -void LuaGuiElement::remove(sol::this_state s, sol::object elem) { - if (!elem) { - if (parent != nullptr) parent->remove(s, sol::make_object(s, key)); - else throw std::runtime_error("Tried to remove self from nil parent."); - } - else if (elem.is()) { - auto child = this->get_child(s, sol::make_object(s, elem.as())); - if (child) remove(s, child); - } - else if (elem.is>()) { - auto parent = elem.as>()->parent; - - for (auto it = parent->children.cbegin(); it != parent->children.cend(); it++) { - if ((*it)->key == elem.as>()->key) { - (*it)->parent = nullptr; - (*it)->updateFunction = nullptr; - - parent->children.erase(it); - if (parent->updateFunction) parent->updateFunction(); - return; - } - } - } -} - -void LuaGuiElement::clear(sol::this_state s) { - for (auto it = children.cbegin(); it != children.cend();) { - (*it)->parent = nullptr; - (*it)->updateFunction = nullptr; - it = children.erase(it); - } - - if (updateFunction) updateFunction(); -} - -Any LuaGuiElement::getAsAny(const std::string& key) const { - if (!traits.count(key)) return Any(); -// auto object = traits.at(key); +// let elem = root.create(props); +// return elem; + // auto elem = std::make_shared(); // -// if (object.is()) return Any::from(object.as()); -// else if (object.is()) return Any::from(object.as()); -// else if (object.is()) return Any::from(object.as()); -// else if (object.is()) { -// auto table = object.as(); +// elem->type = type; // -// if (table.size() == 2) { -// auto x = table.get(1); -// auto y = table.get(2); -// -// glm::vec2 values = {}; -// if (x.is()) values.x = x.as(); -// else if (x.is()) values.x = SerialGui::toDouble(x.as()); -// if (y.is()) values.y = y.as(); -// else if (y.is()) values.y = SerialGui::toDouble(y.as()); -// -// return Any::from(values); +// for (const auto& pair : data) { +// if (pair.first.is()) { +// if (!pair.second.is>()) continue; +// elem->children.push_back(pair.second.as>()); +// elem->children.back()->parent = elem.get(); // } -// else if (table.size() == 4) { -// auto x = table.get(1); -// auto y = table.get(2); -// auto z = table.get(3); -// auto w = table.get(4); +// else if (pair.first.is()) elem->set_trait(pair.first.as(), pair.second); +// } // -// glm::vec4 values = {}; -// if (x.is()) values.x = x.as(); -// else if (x.is()) values.x = SerialGui::toDouble(x.as()); -// if (y.is()) values.y = y.as(); -// else if (y.is()) values.y = SerialGui::toDouble(y.as()); -// if (z.is()) values.z = z.as(); -// else if (z.is()) values.z = SerialGui::toDouble(z.as()); -// if (w.is()) values.w = w.as(); -// else if (w.is()) values.w = SerialGui::toDouble(w.as()); +// return elem; +} + +void Api::Usertype::GuiElement::bind(sol::state& lua, sol::table& core, Gui::Root& root) { + lua.new_usertype("GuiElement", + sol::meta_function::construct, sol::factories([&](const string& type, sol::table data) { + return GuiElement::create(type, data, root); + }) + ); +} + // -// return Any::from(values); +//// sol::meta_function::index, &LuaGuiElement::get_trait, +//// sol::meta_function::new_index, &LuaGuiElement::set_trait, +// +//// sol::meta_function::call, &LuaGuiElement::call, +// +//// "get", &LuaGuiElement::get_child, +//// "append", &LuaGuiElement::append, +//// "prepend", &LuaGuiElement::prepend, +//// "remove", &LuaGuiElement::remove, +//// "clear", &LuaGuiElement::clear + + +// +//sol::object LuaGuiElement::get_trait(sol::this_state s, const std::string& key) { +// if (key == "key") return sol::make_object(s, this->key); +// if (key == "type") return sol::make_object(s, this->type); +// +// if (traits.count(key)) return traits.at(key); +// return sol::nil; +//} +// +//sol::object LuaGuiElement::set_trait(const std::string& key, sol::object val) { +// if (key == "callbacks") { +// callbacks.clear(); +// for (auto pair : val.as()) callbacks[pair.first.as()] = pair.second.as(); +// } +// else if (key == "key") { +// this->key = val.as(); +// } +// else { +// traits.erase(key); +// traits.emplace(key, val); +// } +// +// if (updateFunction) updateFunction(); +// return val; +//} +// +//sol::object LuaGuiElement::call(sol::this_state s, sol::protected_function fun) { +// sol::table tbl = sol::state_view(s)["zepha"]["__builtin"]["gui_env"]; +// sol::environment env(s, sol::create, tbl); +// +// sol::set_environment(env, fun); +// return fun(this); +//} +// +//sol::object LuaGuiElement::get_child(sol::this_state s, sol::object key) { +// if (key.is() && key.as() <= children.size()) { +// auto begin = children.begin(); +// std::advance(begin, key.as() - 1); +// return sol::make_object>(s, *begin); +// } +// else if (key.is()) { +// for (auto& child : children) { +// if (child->key == key.as()) return sol::make_object>(s, child); +// } +// +// for (auto& child : children) { +// auto recurse = child->get_child(s, key); +// if (recurse) return recurse; // } // } - - throw std::runtime_error("Invalid type requested in getAsAny"); -} \ No newline at end of file +// +// return sol::nil; +//} +// +//void LuaGuiElement::append(sol::this_state s, sol::object elem) { +// if (elem.is>()) children.push_back(elem.as>()); +// else if (elem.is()) +// children.push_back(call(s, elem.as()).as>()); +// else throw std::runtime_error("Append arg is not an element or a function to generate one."); +// +// children.back()->parent = this; +// if (updateFunction) updateFunction(); +//} +// +//void LuaGuiElement::prepend(sol::this_state s, sol::object elem) { +// if (elem.is>()) +// children.insert(children.begin(), elem.as>()); +// else if (elem.is()) +// children.insert(children.begin(), call(s, elem.as()).as>()); +// else throw std::runtime_error("Append arg is not an element or a function to generate one."); +// +// children.front()->parent = this; +// if (updateFunction) updateFunction(); +//} +// +//void LuaGuiElement::remove(sol::this_state s, sol::object elem) { +// if (!elem) { +// if (parent != nullptr) parent->remove(s, sol::make_object(s, key)); +// else throw std::runtime_error("Tried to remove self from nil parent."); +// } +// else if (elem.is()) { +// auto child = this->get_child(s, sol::make_object(s, elem.as())); +// if (child) remove(s, child); +// } +// else if (elem.is>()) { +// auto parent = elem.as>()->parent; +// +// for (auto it = parent->children.cbegin(); it != parent->children.cend(); it++) { +// if ((*it)->key == elem.as>()->key) { +// (*it)->parent = nullptr; +// (*it)->updateFunction = nullptr; +// +// parent->children.erase(it); +// if (parent->updateFunction) parent->updateFunction(); +// return; +// } +// } +// } +//} +// +//void LuaGuiElement::clear(sol::this_state s) { +// for (auto it = children.cbegin(); it != children.cend();) { +// (*it)->parent = nullptr; +// (*it)->updateFunction = nullptr; +// it = children.erase(it); +// } +// +// if (updateFunction) updateFunction(); +//} +// +//Any LuaGuiElement::getAsAny(const std::string& key) const { +// if (!traits.count(key)) return Any(); +//// auto object = traits.at(key); +//// +//// if (object.is()) return Any::from(object.as()); +//// else if (object.is()) return Any::from(object.as()); +//// else if (object.is()) return Any::from(object.as()); +//// else if (object.is()) { +//// auto table = object.as(); +//// +//// if (table.size() == 2) { +//// auto x = table.get(1); +//// auto y = table.get(2); +//// +//// glm::vec2 values = {}; +//// if (x.is()) values.x = x.as(); +//// else if (x.is()) values.x = SerialGui::toDouble(x.as()); +//// if (y.is()) values.y = y.as(); +//// else if (y.is()) values.y = SerialGui::toDouble(y.as()); +//// +//// return Any::from(values); +//// } +//// else if (table.size() == 4) { +//// auto x = table.get(1); +//// auto y = table.get(2); +//// auto z = table.get(3); +//// auto w = table.get(4); +//// +//// glm::vec4 values = {}; +//// if (x.is()) values.x = x.as(); +//// else if (x.is()) values.x = SerialGui::toDouble(x.as()); +//// if (y.is()) values.y = y.as(); +//// else if (y.is()) values.y = SerialGui::toDouble(y.as()); +//// if (z.is()) values.z = z.as(); +//// else if (z.is()) values.z = SerialGui::toDouble(z.as()); +//// if (w.is()) values.w = w.as(); +//// else if (w.is()) values.w = SerialGui::toDouble(w.as()); +//// +//// return Any::from(values); +//// } +//// } +// +// throw std::runtime_error("Invalid type requested in getAsAny"); +//} \ No newline at end of file diff --git a/src/lua/usertype/LuaGuiElement.h b/src/lua/usertype/LuaGuiElement.h index 51b6f706..27df5b07 100644 --- a/src/lua/usertype/LuaGuiElement.h +++ b/src/lua/usertype/LuaGuiElement.h @@ -1,84 +1,97 @@ -// -// Created by aurailus on 2020-04-12. -// - #pragma once -#include +#include "lua/Lua.h" -#include "../Lua.h" -#include "../../util/Any.h" +#include "util/Types.h" +//#include "BaseUsertype.h" +//#include "../../util/CovariantPtr.h" -class LuaGuiElement { - public: - LuaGuiElement() = default; +//class Subgame; +//class ItemStack; + +namespace Gui { + class Style; + class Root; + class Element; +} + +namespace Api::Usertype::GuiElement { + void parseRule(const string& ruleStr, const sol::object& value, Gui::Style& styles); - // Lua Functions and Properties - static std::shared_ptr create(const std::string& type, sol::table data); - - sol::object get_trait(sol::this_state s, const std::string& key); - - sol::object set_trait(const std::string& key, sol::object val); + std::shared_ptr create(const string& type, sol::table data, Gui::Root& root); sol::object call(sol::this_state s, sol::protected_function fun); - sol::object get_child(sol::this_state s, sol::object key); - - void append(sol::this_state s, sol::object elem); - - void prepend(sol::this_state s, sol::object elem); - - void remove(sol::this_state s, sol::object elem); - - void clear(sol::this_state s); - - std::string type{}, key{}; - - LuaGuiElement* parent = nullptr; - std::list> children{}; - - std::unordered_map callbacks{}; - std::unordered_map traits{}; - - // C++ Functions and Properties - Any getAsAny(const std::string& key) const; - - template - const T& get(const std::string& key) const { - return getAsAny(key).get(); - } - - template - const T& get_or(const std::string& key, const T& other) const noexcept { - Any a = getAsAny(key); - if (a.empty() || !a.is()) return other; - return a.get(); - } - - template - const bool has(const std::string& key) const noexcept { - Any a = getAsAny(key); - return !a.empty() && a.is(); - } - - std::function updateFunction = nullptr; -}; - -namespace ClientApi { - static void gui_element(sol::state& lua) { - lua.new_usertype("GuiElement", - sol::meta_function::construct, sol::factories(&LuaGuiElement::create), - - sol::meta_function::index, &LuaGuiElement::get_trait, - sol::meta_function::new_index, &LuaGuiElement::set_trait, - - sol::meta_function::call, &LuaGuiElement::call, - - "get", &LuaGuiElement::get_child, - "append", &LuaGuiElement::append, - "prepend", &LuaGuiElement::prepend, - "remove", &LuaGuiElement::remove, - "clear", &LuaGuiElement::clear - ); - } + void bind(sol::state& lua, sol::table& core, Gui::Root& root); } +//class LuaGuiElement { +// public: +// LuaGuiElement() = default; +// +// // Lua Functions and Properties +// +// sol::object get_trait(sol::this_state s, const std::string& key); +// +// sol::object set_trait(const std::string& key, sol::object val); +// +// +// sol::object get_child(sol::this_state s, sol::object key); +// +// void append(sol::this_state s, sol::object elem); +// +// void prepend(sol::this_state s, sol::object elem); +// +// void remove(sol::this_state s, sol::object elem); +// +// void clear(sol::this_state s); +// +// std::string type{}, key{}; +// +// LuaGuiElement* parent = nullptr; +// std::list> children{}; +// +// std::unordered_map callbacks{}; +// std::unordered_map traits{}; +// +// // C++ Functions and Properties +// Any getAsAny(const std::string& key) const; +// +// template +// const T& get(const std::string& key) const { +// return getAsAny(key).get(); +// } +// +// template +// const T& get_or(const std::string& key, const T& other) const noexcept { +// Any a = getAsAny(key); +// if (a.empty() || !a.is()) return other; +// return a.get(); +// } +// +// template +// const bool has(const std::string& key) const noexcept { +// Any a = getAsAny(key); +// return !a.empty() && a.is(); +// } +// +// std::function updateFunction = nullptr; +//}; +// +//namespace ClientApi { +// static void gui_element(sol::state& lua) { +// lua.new_usertype("GuiElement", +// sol::meta_function::construct, sol::factories(&LuaGuiElement::create), +// +// sol::meta_function::index, &LuaGuiElement::get_trait, +// sol::meta_function::new_index, &LuaGuiElement::set_trait, +// +// sol::meta_function::call, &LuaGuiElement::call, +// +// "get", &LuaGuiElement::get_child, +// "append", &LuaGuiElement::append, +// "prepend", &LuaGuiElement::prepend, +// "remove", &LuaGuiElement::remove, +// "clear", &LuaGuiElement::clear +// ); +// } +//} diff --git a/src/lua/usertype/Player.cpp b/src/lua/usertype/Player.cpp index 8581f9da..6fe33b7f 100644 --- a/src/lua/usertype/Player.cpp +++ b/src/lua/usertype/Player.cpp @@ -8,7 +8,6 @@ #include "ItemStack.h" #include "InventoryList.h" -#include "LuaGuiElement.h" #include "world/LocalWorld.h" #include "world/ServerWorld.h" #include "world/inv/Inventory.h" @@ -168,21 +167,25 @@ bool Api::Usertype::LocalPlayer::is_in_menu() { return player.l()->isInMenu(); } -void Api::Usertype::LocalPlayer::show_menu(std::shared_ptr root) { - return player.l()->showMenu(root); -} +//void Api::Usertype::LocalPlayer::show_menu(std::shared_ptr root) { +//// return player.l()->showMenu(root); +// return; +//} void Api::Usertype::LocalPlayer::close_menu() { - return player.l()->closeMenu(); +// return player.l()->closeMenu(); + return; } -std::shared_ptr Api::Usertype::LocalPlayer::get_hud() { - return player.l()->getHud(); -} +//std::shared_ptr Api::Usertype::LocalPlayer::get_hud() { +//// return player.l()->getHud(); +// return nullptr; +//} -void Api::Usertype::LocalPlayer::set_hud(std::shared_ptr hud) { - player.l()->setHud(hud); -} +//void Api::Usertype::LocalPlayer::set_hud(std::shared_ptr hud) { +//// player.l()->setHud(hud); +// return; +//} void Api::Usertype::LocalPlayer::bind(State, sol::state& lua, sol::table& core) { lua.new_usertype("Player", @@ -209,10 +212,10 @@ void Api::Usertype::LocalPlayer::bind(State, sol::state& lua, sol::table& core) "get_dimension", &LocalPlayer::get_dimension, - "show_menu", &LocalPlayer::show_menu, +// "show_menu", &LocalPlayer::show_menu, "close_menu", &LocalPlayer::close_menu, - "set_hud", &LocalPlayer::set_hud, - "get_hud", &LocalPlayer::get_hud, +// "set_hud", &LocalPlayer::set_hud, +// "get_hud", &LocalPlayer::get_hud, "pos", sol::property(&LocalPlayer::get_pos, &LocalPlayer::set_pos), "block_pos", sol::property(&LocalPlayer::get_block_pos, &LocalPlayer::set_pos), diff --git a/src/lua/usertype/Player.h b/src/lua/usertype/Player.h index dad4e38e..fe736d20 100644 --- a/src/lua/usertype/Player.h +++ b/src/lua/usertype/Player.h @@ -12,7 +12,7 @@ #include "Dimension.h" #include "world/player/LocalPlayer.h" -class LuaGuiElement; +//class LuaGuiElement; namespace Api::Usertype { class ServerPlayer; @@ -82,13 +82,13 @@ public: bool is_in_menu(); - void show_menu(std::shared_ptr root); +// void show_menu(std::shared_ptr root); void close_menu(); - std::shared_ptr get_hud(); +// std::shared_ptr get_hud(); - void set_hud(std::shared_ptr hud); +// void set_hud(std::shared_ptr hud); static void bind(State state, sol::state& lua, sol::table& core); }; \ No newline at end of file diff --git a/src/world/player/LocalPlayer.cpp b/src/world/player/LocalPlayer.cpp index a5fffacb..f3b33256 100644 --- a/src/world/player/LocalPlayer.cpp +++ b/src/world/player/LocalPlayer.cpp @@ -100,23 +100,23 @@ bool LocalPlayer::isInMenu() { // return gameGui.isInMenu(); } -void LocalPlayer::showMenu(sptr root) { -// gameGui.showMenu(root); - renderer.window.input.setMouseLocked(false); -} +//void LocalPlayer::showMenu(sptr root) { +//// gameGui.showMenu(root); +// renderer.window.input.setMouseLocked(false); +//} void LocalPlayer::closeMenu() { // gameGui.closeMenu(); renderer.window.input.setMouseLocked(true); } -sptr LocalPlayer::getHud() { -// return gameGui.getHud(); -} +//sptr LocalPlayer::getHud() { +//// return gameGui.getHud(); +//} -void LocalPlayer::setHud(sptr hud) { -// gameGui.setHud(hud); -} +//void LocalPlayer::setHud(sptr hud) { +//// gameGui.setHud(hud); +//} void LocalPlayer::setHudVisible(bool hudVisible) { // gameGui.setVisible(hudVisible); diff --git a/src/world/player/LocalPlayer.h b/src/world/player/LocalPlayer.h index 48d19cb0..5362a66e 100644 --- a/src/world/player/LocalPlayer.h +++ b/src/world/player/LocalPlayer.h @@ -11,7 +11,6 @@ class Input; class Deserializer; -class LuaGuiElement; class LocalInventory; class LocalInventoryRefs; enum class NetPlayerField; @@ -89,7 +88,7 @@ public: * @param root - The root GUI element to display. */ - void showMenu(sptr root); +// void showMenu(sptr root); /** * Closes the currently open menu. @@ -102,7 +101,7 @@ public: * @returns the root GUI element of the hud. */ - sptr getHud(); +// sptr getHud(); /** * Sets the HUD to the specified GUI tree. The hud does not constitute @@ -111,7 +110,7 @@ public: * @param hud - The root GUI element to display. */ - void setHud(sptr hud); +// void setHud(sptr hud); /** * Sets the visibility state of the HUD. diff --git a/subgames/minimal/conf.json b/subgames/minimal/conf.json deleted file mode 100644 index e98d7d86..00000000 --- a/subgames/minimal/conf.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "minimal", - "display_name": "Minimal Subgame", - "author": "@aurailus", - "description": "Minimal subgame for development.", - "version": "0.0.1" -} diff --git a/subgames/minimal/menu/script/init.lua b/subgames/minimal/menu/script/init.lua index 5d6d0e20..569c1f0a 100644 --- a/subgames/minimal/menu/script/init.lua +++ b/subgames/minimal/menu/script/init.lua @@ -1,31 +1,31 @@ -local gui = zepha.build_gui(function() - return Gui.Body { --- background = "#214a21", +zepha.set_gui(zepha.gui(function() + return Gui.Box { background = "#334", Gui.Text { - position = { 4, 4 }, + pos = { 4, 4 }, + text_size = "2px", content = "Minimalminimalmmnal" }, - Gui.Rect { - position = { 64, 64 }, + Gui.Box { + pos = { 64, 64 }, size = { 128 * (16/9), 128 }, background = "zeus_background" }, - Gui.Rect { - position = { 64 + 128, 64 + 64 }, + Gui.Box { + pos = { 64 + 128, 64 + 64 }, size = { 128 * (16/9), 128 }, background = "zeus_background", Gui.Text { + pos = 4, + text_size = "4px", content = "What's the fuck it'd going on?" } } } -end) - -zepha.set_gui(gui) \ No newline at end of file +end)) \ No newline at end of file diff --git a/subgames/parentheses/menu/script/init.lua b/subgames/parentheses/menu/script/init.lua index f6d33f2e..83c8b197 100644 --- a/subgames/parentheses/menu/script/init.lua +++ b/subgames/parentheses/menu/script/init.lua @@ -1,9 +1,11 @@ -zepha.set_gui(zepha.build_gui(function() - return Gui.Body { +zepha.set_gui(zepha.gui(function() + return Gui.Box { background = "#124778", + h_align = "center", + v_align = "center", Gui.Text { - position = { 4, 4 }, + size = { 64, 4 }, content = "Parentheses" } }