From 9aec996b74cd28192626297224c7aab312a79a6d Mon Sep 17 00:00:00 2001 From: Auri Date: Tue, 24 Aug 2021 01:48:53 -0700 Subject: [PATCH] More Lua GuiElement functionality. --- assets/base/script/game/hud.lua | 2 +- src/CMakeLists.txt | 4 +- src/client/gui/BoxElement.cpp | 8 +- src/client/gui/Element.cpp | 69 ++-- src/client/gui/Element.h | 72 ++-- src/client/gui/Root.cpp | 18 +- src/client/gui/Root.h | 4 +- src/client/gui/Style.cpp | 36 +- src/client/gui/Style.h | 100 +++--- src/client/gui/TextElement.cpp | 10 +- src/client/menu/MenuSandbox.cpp | 16 +- src/client/scene/ConnectScene.cpp | 53 +-- src/client/scene/LuaErrorScene.cpp | 14 +- src/client/scene/MainMenuScene.cpp | 106 +++--- src/lua/LocalLuaParser.cpp | 13 +- src/lua/usertype/GuiElement.cpp | 212 +++++++++++ .../{LuaGuiElement.h => GuiElement.h} | 8 +- src/lua/usertype/LuaGuiElement.cpp | 333 ------------------ src/world/player/LocalPlayer.cpp | 16 +- subgames/zeus/menu/script/init.lua | 16 +- subgames/zeus/mods/auri_chat/script/gui.lua | 23 +- subgames/zeus/mods/auri_chat/script/init.lua | 2 +- .../zeus/mods/auri_health/script/init.lua | 12 +- .../mods/auri_health/script/interface.lua | 2 +- .../zeus/mods/auri_hot_wheel/script/init.lua | 20 +- .../zeus/mods/zeus_inventory/script/chest.lua | 84 +++-- .../zeus/mods/zeus_inventory/script/menu.lua | 200 ++++++----- 27 files changed, 662 insertions(+), 791 deletions(-) create mode 100644 src/lua/usertype/GuiElement.cpp rename src/lua/usertype/{LuaGuiElement.h => GuiElement.h} (91%) delete mode 100644 src/lua/usertype/LuaGuiElement.cpp diff --git a/assets/base/script/game/hud.lua b/assets/base/script/game/hud.lua index 17811ff2..d2fb272b 100644 --- a/assets/base/script/game/hud.lua +++ b/assets/base/script/game/hud.lua @@ -5,7 +5,7 @@ zepha.player:set_hud(zepha.gui(function() Gui.Box { -- id = "crosshair", - size = { "22dp", "22dp" }, + size = { "22px", "22px" }, pos = { "50cw - 50sw", "50ch - 50sh" }, background = "base:crosshair" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8c81bb7a..aac15769 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -184,8 +184,8 @@ add_library(Zepha_Core lua/usertype/InventoryList.h lua/usertype/ItemStack.cpp lua/usertype/ItemStack.h - lua/usertype/LuaGuiElement.cpp - lua/usertype/LuaGuiElement.h + lua/usertype/GuiElement.cpp + lua/usertype/GuiElement.h lua/usertype/Player.cpp lua/usertype/Player.h lua/usertype/SubgameUsertype.h diff --git a/src/client/gui/BoxElement.cpp b/src/client/gui/BoxElement.cpp index d6885024..9d3dbf7f 100644 --- a/src/client/gui/BoxElement.cpp +++ b/src/client/gui/BoxElement.cpp @@ -5,8 +5,8 @@ #include "client/graph/mesh/EntityMesh.h" void Gui::BoxElement::updateElement() { - const let bgRule = hovered && getStyle(StyleRule::BACKGROUND_HOVER) ? - StyleRule::BACKGROUND_HOVER : StyleRule::BACKGROUND; + const let bgRule = hovered && getStyle(Prop::BACKGROUND_HOVER) ? + Prop::BACKGROUND_HOVER : Prop::BACKGROUND; let rawBg = getStyle(bgRule); @@ -20,7 +20,7 @@ void Gui::BoxElement::updateElement() { curBg = rawBg; if (isDirty) { - const let bgColor = getStyle(bgRule); + const let bgColor = getStyle(bgRule); const string bgImage = getStyle(bgRule, ""); let mesh = std::make_unique(); @@ -48,7 +48,7 @@ void Gui::BoxElement::updateElement() { entity.setModel(model); } - let margin = getStyle(StyleRule::MARGIN, {}); + let margin = getStyle(Prop::MARGIN, {}); entity.setScale(vec3(getComputedSize(), 0)); entity.setPos(vec3(getComputedScreenPos() + ivec2 { margin.x, margin.y }, 0)); diff --git a/src/client/gui/Element.cpp b/src/client/gui/Element.cpp index c29178be..fa203fb5 100644 --- a/src/client/gui/Element.cpp +++ b/src/client/gui/Element.cpp @@ -8,17 +8,17 @@ Gui::Element::~Element() { for (let& child : children) child->parent = nullptr; } +const Gui::Props& Gui::Element::getProps() const { + return props; +} + void Gui::Element::setProps(const Props& props) { this->props = props; updateElement(); } -void Gui::Element::setStyle(StyleRule style, const any& value) { - props.styles.rules[style] = value; -} - -const optional Gui::Element::getStyleRaw(Gui::StyleRule style) const { - return getStyle(style); +void Gui::Element::setProp(Gui::Prop prop, const any& value) { + props.props[prop] = value; } sptr Gui::Element::get(u32 ind) { @@ -26,10 +26,33 @@ sptr Gui::Element::get(u32 ind) { return children[ind]; } +sptr Gui::Element::get(const string& id) { + for (let& child : children) { + if (child->props.get(Prop::ID) == id) return child; + } + for (let& child : children) { + let res = child->get(id); + if (res != nullptr) return res; + } + return nullptr; +} + void Gui::Element::clear() { children.clear(); } +void Gui::Element::remove() { + if (parent) { + for (let it = parent->children.begin(); it != parent->children.end(); it++) { + if (it->get() == this) { + parent->children.erase(it); + break; + } + } + parent = nullptr; + } +} + void Gui::Element::onClick(const std::function& cb) { clickCb = cb; } @@ -42,7 +65,7 @@ Gui::ExpressionInfo Gui::Element::getExpr() const { } ivec2 Gui::Element::getComputedSize() const { - let size = getStyleWithExpr(StyleRule::SIZE, vec2(nanf("")), + let size = getStyleWithExpr(Prop::SIZE, vec2(nanf("")), { parent ? parent->computedSize : ivec2 {}, {} }); if (std::isnan(size.x)) size.x = std::max(layoutSize.x, 0); if (std::isnan(size.y)) size.y = std::max(layoutSize.y, 0); @@ -50,24 +73,18 @@ ivec2 Gui::Element::getComputedSize() const { return size; } -ivec2 Gui::Element::getComputedOuterSize() const { - let size = getComputedSize(); - let margin = getStyle(StyleRule::MARGIN, {}); - return ivec2 { size.x + margin.x + margin.z, size.y + margin.y + margin.w }; -} - ivec2 Gui::Element::getComputedContentSize() const { let size = getComputedSize(); - let padding = getStyle(StyleRule::PADDING, {}); + let padding = getStyle(Prop::PADDING, {}); return glm::max(ivec2 { size.x - padding.x - padding.z, size.y - padding.y - padding.w }, 0); } ivec2 Gui::Element::getExplicitSize() const { - return getStyle(StyleRule::SIZE, ivec2(-1)); + return getStyle(Prop::SIZE, ivec2(-1)); } ivec2 Gui::Element::getComputedPos() const { - return getStyle(StyleRule::POS, layoutPosition); + return getStyle(Prop::POS, layoutPosition); } ivec2 Gui::Element::getComputedScreenPos() const { @@ -91,7 +108,7 @@ bool Gui::Element::handleMouseHover(ivec2 mousePos, bool& pointer) { bool intersects = mousePos.x >= pos.x && mousePos.x <= pos.x + size.x && mousePos.y >= pos.y && mousePos.y <= pos.y + size.y; - let cursor = getStyle(StyleRule::CURSOR); + let cursor = getStyle(Prop::CURSOR); if (intersects && cursor) pointer = *cursor == "pointer"; if (hovered != intersects) { @@ -126,12 +143,12 @@ void Gui::Element::updateElement() { } void Gui::Element::layoutChildren() { - const string& layout = getStyle(StyleRule::LAYOUT, ""); + const string& layout = getStyle(Prop::LAYOUT, ""); switch (Util::hash(layout.data())) { default: case Util::hash("flex"): { - const string& direction = getStyle(StyleRule::DIRECTION, ""); + const string& direction = getStyle(Prop::DIRECTION, ""); /** * The primary flex direction. Stored as a bool but interpreted as an index into a vec2. @@ -140,8 +157,8 @@ void Gui::Element::layoutChildren() { const bool primary = direction != "row"; - const string& hAlignRaw = getStyle(StyleRule::H_ALIGN, ""); - const string& vAlignRaw = getStyle(StyleRule::V_ALIGN, ""); + const string& hAlignRaw = getStyle(Prop::H_ALIGN, ""); + const string& vAlignRaw = getStyle(Prop::V_ALIGN, ""); /** * Parsed alignment of the horizontal and vertical axes. @@ -157,8 +174,8 @@ void Gui::Element::layoutChildren() { * The element gap across the primary axis. */ - const i32 gap = getStyle(StyleRule::GAP, ivec2(0))[primary]; - const ivec4& padding = getStyle(StyleRule::PADDING, ivec4 {}); + const i32 gap = getStyle(Prop::GAP, ivec2(0))[primary]; + const ivec4& padding = getStyle(Prop::PADDING, ivec4 {}); /* * Calculates the explicit spaced used up by children across the primary axis, @@ -174,7 +191,7 @@ void Gui::Element::layoutChildren() { let childExplicitSize = child->getExplicitSize(); if (childExplicitSize[primary] != -1) explicitSize += childExplicitSize[primary]; else implicitCount++; - let childMargin = child->getStyle(StyleRule::MARGIN, {}); + let childMargin = child->getStyle(Prop::MARGIN, {}); explicitSize += childMargin[primary] + childMargin[primary + 2]; } @@ -201,7 +218,7 @@ void Gui::Element::layoutChildren() { for (const let& child : children) { let childExplicitSize = child->getExplicitSize(); - let childMargin = child->getStyle(StyleRule::MARGIN, {}); + let childMargin = child->getStyle(Prop::MARGIN, {}); child->layoutSize[primary] = (childExplicitSize[primary] == -1 && align[primary] == 2) ? implicitElemSize : 0; @@ -227,4 +244,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 193fac89..c127d19d 100644 --- a/src/client/gui/Element.h +++ b/src/client/gui/Element.h @@ -3,10 +3,10 @@ #include #include "client/gui/Gui.h" -#include "client/gui/Style.h" #include "world/dim/ent/DrawableEntity.h" #include "util/Types.h" +#include "client/gui/Style.h" class Window; class Renderer; @@ -25,23 +25,18 @@ namespace Gui { friend class TextElement; public: - struct Props {; - string id {}; - vec classes {}; - Style styles {}; - }; - Element(Root& root, vec& stylesheets): root(root), stylesheets(stylesheets) {} ~Element(); + + /** Gets a reference to the element's props. */ + const Props& getProps() const; /** Sets the element's props to the struct specified. */ virtual void setProps(const Props& props); /** Sets a style rule on the element. */ - virtual void setStyle(StyleRule style, const std::any& value); - - virtual const optional getStyleRaw(StyleRule style) const; + virtual void setProp(Prop prop, const std::any& value); /** Recalculates the element based on its props. Call when props or stylesheets change. */ virtual void updateElement(); @@ -51,6 +46,8 @@ namespace Gui { sptr get(u32 ind); + sptr get(const string& id); + template, bool> = true> sptr get(u32 ind) { return std::dynamic_pointer_cast(get(ind)); @@ -92,14 +89,13 @@ namespace Gui { void clear(); + void remove(); + void onClick(const std::function& cb); /** Returns the element's computed size. */ virtual ivec2 getComputedSize() const; - /** Returns the element's computed size + margins. */ - virtual ivec2 getComputedOuterSize() const; - /** Returns the element's computed content size, which is its size - padding. */ virtual ivec2 getComputedContentSize() const; @@ -113,11 +109,13 @@ namespace Gui { virtual ivec2 getComputedScreenPos() const; /** Gets a style value from the element's styles or the root's stylesheets. */ - const optional getStyle(StyleRule rule) const { - const optional opt = props.styles.get(rule); + const optional getStyle(Prop rule) const { + const optional opt = props.get(rule); if (opt) return *opt; + const let& classes = props.get>(Prop::CLASS); + if (!classes) return std::nullopt; for (const let& ss : stylesheets) { - for (const string& className : props.classes) { + for (const string& className : *classes) { const let& styles = ss.find(className); if (styles == ss.end()) continue; const optional opt = styles->second.get(rule); @@ -128,14 +126,15 @@ namespace Gui { } /** Gets a generic value from the element's styles or the root's stylesheets. */ - template = true> + template = true> - const optional getStyle(StyleRule rule) const { - const optional opt = props.styles.get(rule); + const optional getStyle(Prop rule) const { + const optional opt = props.get(rule); if (opt) return *opt; + const let& classes = props.get>(Prop::CLASS); + if (!classes) return std::nullopt; for (const let& ss : stylesheets) { - for (const string& className : props.classes) { + for (const string& className : *classes) { const let& styles = ss.find(className); if (styles == ss.end()) continue; const optional opt = styles->second.get(rule); @@ -146,15 +145,16 @@ namespace Gui { } /** Gets a LENGTH value from the element's styles or the root's stylesheets. */ - template = true> + template = true> - const optional getStyle(StyleRule rule) const { + const optional getStyle(Prop rule) const { ExpressionInfo info = getExpr(); - const optional opt = props.styles.get(rule, info); + const optional opt = props.get(rule, info); if (opt) return *opt; + const let& classes = props.get>(Prop::CLASS); + if (!classes) return std::nullopt; for (const let& ss : stylesheets) { - for (const string& className : props.classes) { + for (const string& className : *classes) { const let& styles = ss.find(className); if (styles == ss.end()) continue; const optional opt = styles->second.get(rule, info); @@ -165,14 +165,15 @@ namespace Gui { } /** Gets a LENGTH value from the element's styles or the root's stylesheets. */ - template = true> + template = true> - const optional getStyleWithExpr(StyleRule rule, const ExpressionInfo& expr) const { - const optional opt = props.styles.get(rule, expr); + const optional getStyleWithExpr(Prop rule, const ExpressionInfo& expr) const { + const optional opt = props.get(rule, expr); if (opt) return *opt; + const let& classes = props.get>(Prop::CLASS); + if (!classes) return std::nullopt; for (const let& ss : stylesheets) { - for (const string& className : props.classes) { + for (const string& className : *classes) { const let& styles = ss.find(className); if (styles == ss.end()) continue; const optional opt = styles->second.get(rule, expr); @@ -183,19 +184,18 @@ namespace Gui { } /** Gets a style value from the element's styles or the root's stylesheets. */ - template + template - const V getStyle(StyleRule rule, V def) const { + const V getStyle(Prop rule, V def) const { const optional opt = getStyle(rule); if (opt) return *opt; return def; } /** Gets a LENGTH value from the element's styles or the root's stylesheets, with a custom ExpressionInfo. */ - template = true> + template = true> - const V getStyleWithExpr(StyleRule rule, V def, const ExpressionInfo& info) const { + const V getStyleWithExpr(Prop rule, V def, const ExpressionInfo& info) const { const optional opt = getStyleWithExpr(rule, info); if (opt) return *opt; return def; diff --git a/src/client/gui/Root.cpp b/src/client/gui/Root.cpp index 584b4fb8..b9592728 100644 --- a/src/client/gui/Root.cpp +++ b/src/client/gui/Root.cpp @@ -10,17 +10,15 @@ Gui::Root::Root(Window& window, TextureAtlas& atlas) : body(make_shared(*this, stylesheets)) { const ivec2 size = window.getSize(); - body->setProps({ - .id = "body", - .styles = {{ - { StyleRule::SIZE, array { - Expression(std::to_string(size.x)), Expression(std::to_string(size.y)) }} - }} - }); + using Expr = Expression; + body->setProps({{ + { Prop::ID, string("body") }, + { Prop::SIZE, array { Expr(std::to_string(size.x)), Expr(std::to_string(size.y)) }} + }}); callbacks.emplace_back(window.resize.bind([&](ivec2 size) { - body->setStyle(StyleRule::SIZE, array { - Expression(std::to_string(size.x)), Expression(std::to_string(size.y)) }); + body->setProp(Prop::SIZE, array { + Expr(std::to_string(size.x)), Expr(std::to_string(size.y)) }); Timer t("Resize UI"); body->updateElement(); t.printElapsedMs(); @@ -36,7 +34,7 @@ Gui::Root::~Root() { window.setCursorHand(false); } -void Gui::Root::addStylesheet(const std::unordered_map& sheet) { +void Gui::Root::addStylesheet(const StyleSheet& sheet) { stylesheets.emplace_back(sheet); } diff --git a/src/client/gui/Root.h b/src/client/gui/Root.h index d98bdfc8..d60b639f 100644 --- a/src/client/gui/Root.h +++ b/src/client/gui/Root.h @@ -25,7 +25,7 @@ namespace Gui { template, bool> = true> - sptr create(const Element::Props& props = {}, const vec>& children = {}) { + sptr create(const Props& props = {}, const vec>& children = {}) { let elem = make_shared(*this, stylesheets); elem->setProps(props); @@ -39,7 +39,7 @@ namespace Gui { * styles for elements with specific classes. */ - void addStylesheet(const std::unordered_map& sheet); + void addStylesheet(const StyleSheet& sheet); /** Processes mouse events. */ void update(); diff --git a/src/client/gui/Style.cpp b/src/client/gui/Style.cpp index bf856ac5..deb36336 100644 --- a/src/client/gui/Style.cpp +++ b/src/client/gui/Style.cpp @@ -1,20 +1,22 @@ #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 } +const std::unordered_map Gui::Props::PROP_NAMES_TO_ENUM = { + { "id", Prop::ID }, + { "class", Prop::CLASS }, + { "pos", Prop::POS }, + { "size", Prop::SIZE }, + { "margin", Prop::MARGIN }, + { "padding", Prop::PADDING }, + { "gap", Prop::GAP }, + { "layout", Prop::LAYOUT }, + { "direction", Prop::DIRECTION }, + { "h_align", Prop::H_ALIGN }, + { "v_align", Prop::V_ALIGN }, + { "cursor", Prop::CURSOR }, + { "overflow", Prop::OVERFLOW }, + { "background", Prop::BACKGROUND }, + { "background_hover", Prop::BACKGROUND_HOVER }, + { "content", Prop::CONTENT }, + { "text_size", Prop::TEXT_SIZE }, + { "text_color", Prop::TEXT_COLOR } }; \ No newline at end of file diff --git a/src/client/gui/Style.h b/src/client/gui/Style.h index 3eed5ac0..07395316 100644 --- a/src/client/gui/Style.h +++ b/src/client/gui/Style.h @@ -5,7 +5,10 @@ #include "client/gui/Expression.h" namespace Gui { - enum class StyleRule { + enum class Prop { + ID, + CLASS, + POS, SIZE, MARGIN, @@ -27,25 +30,25 @@ namespace Gui { TEXT_COLOR }; - enum class ValueType { + enum class Type { LITERAL, COLOR, LENGTH }; - class Style { + class Props { public: - Style() = default; - Style(const std::unordered_map& rules): rules(rules) {} + Props() = default; + Props(const std::unordered_map& props): props(props) {} /** * Simple get. Returns an optional containing an any of * the Rule's value, or an empty optional if the rule is not defined. */ - const optional get(StyleRule rule) const { - const let it = rules.find(rule); - if (it == rules.end()) return std::nullopt; + const optional get(Prop prop) const { + const let it = props.find(prop); + if (it == props.end()) return std::nullopt; return optional(it->second); } @@ -54,14 +57,14 @@ namespace Gui { * or an empty optional if the rule is not defined, or not the type V. */ - template || std::is_floating_point_v || std::is_same_v) && - T == ValueType::LITERAL, bool> = true> + T == Type::LITERAL, bool> = true> - const optional get(StyleRule rule) const { - const optional raw = get(rule); + const optional get(Prop prop) const { + const optional raw = get(prop); if (!raw || raw->type() != typeid(V)) return std::nullopt; return any_cast(*raw); } @@ -70,15 +73,14 @@ namespace Gui { * get specialization for string-like values. */ - template && - T == ValueType::LITERAL, bool> = true> + T == Type::LITERAL, bool> = true> - const optional get(StyleRule rule) const { - const optional raw = get(rule); + const optional get(Prop prop) const { + const optional raw = get(prop); if (!raw) return std::nullopt; if (raw->type() == typeid(string)) return any_cast(*raw); -// if (raw->type() == typeid(const char*)) return any_cast(*raw); return std::nullopt; } @@ -86,26 +88,15 @@ namespace Gui { * get specialization for numeric values. */ - template || std::is_floating_point_v) && - T == ValueType::LITERAL, bool> = true> + T == Type::LITERAL, bool> = true> - const optional get(StyleRule rule) const { - const optional raw = get(rule); + const optional get(Prop prop) const { + const optional raw = get(prop); if (!raw) return std::nullopt; if (raw->type() == typeid(N)) return any_cast(*raw); -// if (raw->type() == typeid(i8)) return static_cast(any_cast(*raw)); -// if (raw->type() == typeid(i16)) return static_cast(any_cast(*raw)); -// if (raw->type() == typeid(i32)) return static_cast(any_cast(*raw)); -// if (raw->type() == typeid(i64)) return static_cast(any_cast(*raw)); -// if (raw->type() == typeid(f32)) return static_cast(any_cast(*raw)); -// if (raw->type() == typeid(f64)) return static_cast(any_cast(*raw)); -// if (raw->type() == typeid(u8)) return static_cast(any_cast(*raw)); -// if (raw->type() == typeid(u16)) return static_cast(any_cast(*raw)); -// if (raw->type() == typeid(u32)) return static_cast(any_cast(*raw)); -// if (raw->type() == typeid(u64)) return static_cast(any_cast(*raw)); -// if (raw->type() == typeid(usize)) return static_cast(any_cast(*raw)); return std::nullopt; } @@ -114,23 +105,18 @@ namespace Gui { * which is interpreted as a vec4 color from several different formats. */ - template && - C == ValueType::COLOR, bool> = true> + C == Type::COLOR, bool> = true> - const optional get(StyleRule rule, optional def = std::nullopt) const { - const optional raw = get(rule); + const optional get(Prop prop, optional def = std::nullopt) const { + const optional raw = get(prop); if (!raw) return std::nullopt; if (raw->type() == typeid(void) && def) return *def; if (raw->type() == typeid(void)) throw std::runtime_error("Field is missing with no default."); if (raw->type() == typeid(vec4)) return any_cast(*raw); - try { - if (raw->type() == typeid(string)) return Util::hexToColorVec(any_cast(*raw)); -// if (raw->type() == typeid(const char*)) return Util::hexToColorVec(string(any_cast(*raw))); - } - catch (std::exception) { - return std::nullopt; - } + try { if (raw->type() == typeid(string)) return Util::hexToColorVec(any_cast(*raw)); } + catch (std::exception) { return std::nullopt; } return std::nullopt; } @@ -139,12 +125,12 @@ namespace Gui { * which is interpreted as a length. */ - template || std::is_floating_point_v) && - L == ValueType::LENGTH, bool> = true> + L == Type::LENGTH, bool> = true> - optional get(StyleRule rule, const ExpressionInfo& info) const { - let raw = get(rule); + optional get(Prop prop, const ExpressionInfo& info) const { + let raw = get(prop); if (!raw) return std::nullopt; return raw->eval(info); } @@ -154,13 +140,13 @@ namespace Gui { * which is interpreted as a length. */ - template || std::is_floating_point_v) && std::is_same_v> && - L == ValueType::LENGTH, bool> = true> + L == Type::LENGTH, bool> = true> - optional get(StyleRule rule, const ExpressionInfo& info) const { - let raw = get>(rule); + optional get(Prop prop, const ExpressionInfo& info) const { + let raw = get>(prop); if (!raw) return std::nullopt; VN vec; for (usize i = 0; i < VN::length(); i++) vec[i] = (*raw)[i].eval(info); @@ -173,18 +159,18 @@ namespace Gui { * Throws if the rule is defined to a different type. */ - template + template - const V get(StyleRule rule, V def) const { - const optional raw = get(rule); + const V get(Prop prop, V def) const { + const optional raw = get(prop); if (!raw) return def; return *raw; } - std::unordered_map rules {}; + std::unordered_map props {}; - const static std::unordered_map RULE_STRINGS_TO_ENUMS; + const static std::unordered_map PROP_NAMES_TO_ENUM; }; - typedef std::unordered_map StyleSheet; + typedef std::unordered_map StyleSheet; } \ No newline at end of file diff --git a/src/client/gui/TextElement.cpp b/src/client/gui/TextElement.cpp index 5337e36c..6a32aa32 100644 --- a/src/client/gui/TextElement.cpp +++ b/src/client/gui/TextElement.cpp @@ -7,7 +7,7 @@ #include "client/graph/mesh/EntityMesh.h" void Gui::TextElement::updateElement() { - const string text = getStyle(StyleRule::CONTENT, ""); + const string text = getStyle(Prop::CONTENT, ""); if (!font) font = std::make_unique(root.atlas, root.atlas["font"]); @@ -15,8 +15,8 @@ void Gui::TextElement::updateElement() { if (hash != newHash) { hash = newHash; - vec4 textColor = getStyle(StyleRule::TEXT_COLOR, vec4(1)); - vec4 backgroundColor = getStyle(StyleRule::BACKGROUND, vec4(0)); + vec4 textColor = getStyle(Prop::TEXT_COLOR, vec4(1)); + vec4 backgroundColor = getStyle(Prop::BACKGROUND, vec4(0)); u32 ind = 0; u32 width = 0; @@ -190,8 +190,8 @@ void Gui::TextElement::updateElement() { } - let scale = getStyle(StyleRule::TEXT_SIZE, 3.f); - let margin = getStyle(StyleRule::MARGIN, {}); + let scale = getStyle(Prop::TEXT_SIZE, 3.f); + let margin = getStyle(Prop::MARGIN, {}); entity.setScale(vec3(scale, scale, 0)); entity.setPos(vec3(getComputedScreenPos() + ivec2 { margin.x, margin.y }, 0)); diff --git a/src/client/menu/MenuSandbox.cpp b/src/client/menu/MenuSandbox.cpp index b5873305..d91a867a 100644 --- a/src/client/menu/MenuSandbox.cpp +++ b/src/client/menu/MenuSandbox.cpp @@ -14,7 +14,7 @@ #include "lua/modules/Time.h" #include "lua/modules/mSetGui.h" #include "lua/modules/mStartGame.h" -#include "lua/usertype/LuaGuiElement.h" +#include "lua/usertype/GuiElement.h" MenuSandbox::MenuSandbox(Client& client, Gui::Root& root, sptr sandboxRoot) : LuaParser(*client.game), @@ -152,14 +152,12 @@ void MenuSandbox::showError(const string& err) { using Expr = Gui::Expression; sandboxRoot->clear(); - 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") } } - }} - }); + sandboxRoot->append({{ + { Gui::Prop::CONTENT, errPrefixText + err }, + { Gui::Prop::TEXT_SIZE, Expr("2px") }, + { Gui::Prop::SIZE, array { Expr("100dp"), Expr("-1") } }, + { Gui::Prop::MARGIN, array { Expr("4dp"), Expr("4dp"), Expr("4dp"), Expr("4dp") } } + }}); } sol::protected_function_result MenuSandbox::errorCallback(sol::protected_function_result r) { diff --git a/src/client/scene/ConnectScene.cpp b/src/client/scene/ConnectScene.cpp index f819a292..4dfafcb6 100644 --- a/src/client/scene/ConnectScene.cpp +++ b/src/client/scene/ConnectScene.cpp @@ -19,14 +19,12 @@ ConnectScene::ConnectScene(Client& client, Address addr) : Scene(client), client.renderer.setClearColor(10, 10, 10); using Expr = Gui::Expression; - status = root.body->append({ - .styles = {{ - { Gui::StyleRule::TEXT_SIZE, Expr("2px") }, - { Gui::StyleRule::SIZE, array { Expr("100dp"), Expr("-1") } }, - { Gui::StyleRule::CONTENT, string("`c1Connecting to `b`c0" + addr.toString() + "`r`c1...") }, - { Gui::StyleRule::MARGIN, array { Expr("4dp"), Expr("4dp"), Expr("4dp"), Expr("4dp") } } - }} - }); + status = root.body->append({{ + { Gui::Prop::TEXT_SIZE, Expr("2px") }, + { Gui::Prop::SIZE, array { Expr("100dp"), Expr("-1") } }, + { Gui::Prop::CONTENT, string("`c1Connecting to `b`c0" + addr.toString() + "`r`c1...") }, + { Gui::Prop::MARGIN, array { Expr("4dp"), Expr("4dp"), Expr("4dp"), Expr("4dp") } } + }}); connection.attemptConnect(std::move(addr)); } @@ -50,8 +48,8 @@ void ConnectScene::update() { PacketView p(e.packet); if (p.type == Packet::Type::SERVER_INFO) { - status->setStyle(Gui::StyleRule::CONTENT, status->getStyle(Gui::StyleRule::CONTENT, "") - + "Received server properties.\n"); + status->setProp(Gui::Prop::CONTENT, status->getStyle(Gui::Prop::CONTENT, "") + + "Received server properties.\n"); const u32 seed = p.d.read(); std::cout << seed << std::endl; @@ -76,8 +74,9 @@ void ConnectScene::update() { resp.sendTo(connection.getPeer(), Packet::Channel::CONNECT); } else if (p.type == Packet::Type::BIOME_IDENTIFIER_LIST) { - status->setStyle(Gui::StyleRule::CONTENT, status->getStyle(Gui::StyleRule::CONTENT, "") - + "Received block & biome index-identifier table.\nDownloading mods... "); + status->setProp(Gui::Prop::CONTENT, status->getStyle(Gui::Prop::CONTENT, "") + + + "Received block & biome index-identifier table.\nDownloading mods... "); client.game->getBiomes().setIdentifiers(p.d.read>()); state = State::MODS; @@ -95,17 +94,19 @@ void ConnectScene::update() { if (p.type == Packet::Type::MODS) { auto mod = LuaMod(p); - status->setStyle(Gui::StyleRule::CONTENT, status->getStyle(Gui::StyleRule::CONTENT, "") + - (modsFound == 0 ? "" : ", ") + ((modsFound) % 8 == 0 && modsFound != 0 ? "\n" : "") + - "`c0`u" + mod.config.name + "`r`c1"); + status->setProp(Gui::Prop::CONTENT, status->getStyle(Gui::Prop::CONTENT, "") + + (modsFound == 0 ? "" : ", ") + + ((modsFound) % 8 == 0 && modsFound != 0 ? "\n" : "") + + "`c0`u" + mod.config.name + "`r`c1"); modsFound++; client.game->getParser().addMod(std::move(mod)); } else if (p.type == Packet::Type::MOD_ORDER) { client.game->getParser().setModLoadOrder(p.d.read>()); - status->setStyle(Gui::StyleRule::CONTENT, status->getStyle(Gui::StyleRule::CONTENT, "") - + ".\n`c7Done`c1 downloading mods. Received the mods order.\nReceiving media"); + status->setProp(Gui::Prop::CONTENT, status->getStyle(Gui::Prop::CONTENT, "") + + + ".\n`c7Done`c1 downloading mods. Received the mods order.\nReceiving media"); state = State::MEDIA; Packet resp(Packet::Type::MEDIA); @@ -126,8 +127,8 @@ void ConnectScene::update() { while (t != AssetType::END) { string assetName = p.d.read(); - status->setStyle(Gui::StyleRule::CONTENT, - status->getStyle(Gui::StyleRule::CONTENT, "") + "."); + status->setProp(Gui::Prop::CONTENT, + status->getStyle(Gui::Prop::CONTENT, "") + "."); if (t == AssetType::TEXTURE) { u16 width = p.d.read(); @@ -152,8 +153,8 @@ void ConnectScene::update() { } } else if (p.type == Packet::Type::MEDIA_DONE) { - status->setStyle(Gui::StyleRule::CONTENT, status->getStyle(Gui::StyleRule::CONTENT, "") - + " `c7Done.`c1\nLoading complete. `c0`bJoining world...\n"); + status->setProp(Gui::Prop::CONTENT, status->getStyle(Gui::Prop::CONTENT, "") + + " `c7Done.`c1\nLoading complete. `c0`bJoining world...\n"); state = State::DONE; let gameScene = make_unique(client); @@ -179,8 +180,8 @@ void ConnectScene::handleConnecting() { case ServerConnection::State::FAILED_CONNECT: state = State::FAILED_CONNECT; - status->setStyle(Gui::StyleRule::CONTENT, - status->getStyle(Gui::StyleRule::CONTENT, "") + " `cfFailed to init :(\n"); + status->setProp(Gui::Prop::CONTENT, + status->getStyle(Gui::Prop::CONTENT, "") + " `cfFailed to init :(\n"); break; case ServerConnection::State::ATTEMPTING_CONNECT: @@ -189,15 +190,15 @@ void ConnectScene::handleConnecting() { dotsTime += client.getDelta(); if (dotsTime > 1) { dotsTime -= 1; - status->setStyle(Gui::StyleRule::CONTENT, status->getStyle(Gui::StyleRule::CONTENT, "") + "."); + status->setProp(Gui::Prop::CONTENT, status->getStyle(Gui::Prop::CONTENT, "") + "."); } break; case ServerConnection::State::CONNECTED: { state = State::PROPERTIES; - status->setStyle(Gui::StyleRule::CONTENT, - status->getStyle(Gui::StyleRule::CONTENT, "") + " `c7Connected!~`c1\n"); + status->setProp(Gui::Prop::CONTENT, + status->getStyle(Gui::Prop::CONTENT, "") + " `c7Connected!~`c1\n"); Packet resp(Packet::Type::SERVER_INFO); resp.sendTo(connection.getPeer(), Packet::Channel::CONNECT); diff --git a/src/client/scene/LuaErrorScene.cpp b/src/client/scene/LuaErrorScene.cpp index fedc9ff2..c9827b38 100644 --- a/src/client/scene/LuaErrorScene.cpp +++ b/src/client/scene/LuaErrorScene.cpp @@ -13,14 +13,12 @@ LuaErrorScene::LuaErrorScene(Client& client, const std::string& err) : Scene(cli client.renderer.window.input.setMouseLocked(false); using Expr = Gui::Expression; - root.body->append({ - .styles = {{ - { Gui::StyleRule::TEXT_SIZE, Expr("2px") }, - { Gui::StyleRule::SIZE, array { Expr("100dp"), Expr("-1") } }, - { Gui::StyleRule::CONTENT, string("`cfEncountered a fatal mod error ;-;\n\n`r") + err }, - { Gui::StyleRule::MARGIN, array { Expr("4dp"), Expr("4dp"), Expr("4dp"), Expr("4dp") } } - }} - }); + root.body->append({{ + { Gui::Prop::TEXT_SIZE, Expr("2px") }, + { Gui::Prop::SIZE, array { Expr("100dp"), Expr("-1") } }, + { Gui::Prop::CONTENT, string("`cfEncountered a fatal mod error ;-;\n\n`r") + err }, + { Gui::Prop::MARGIN, array { Expr("4dp"), Expr("4dp"), Expr("4dp"), Expr("4dp") } } + }}); root.body->onClick([&](i32 button, bool down) { if (button != GLFW_MOUSE_BUTTON_1 || !down) return; diff --git a/src/client/scene/MainMenuScene.cpp b/src/client/scene/MainMenuScene.cpp index 62d90d1e..3e595489 100644 --- a/src/client/scene/MainMenuScene.cpp +++ b/src/client/scene/MainMenuScene.cpp @@ -18,7 +18,7 @@ MainMenuScene::MainMenuScene(Client& client) : Scene(client), root(client.renderer.window, client.game->textures), - sandboxElem(root.create({ .classes = { "sandbox" }})), + sandboxElem(root.create()), sandbox(client, root, sandboxElem) { client.renderer.setClearColor(0, 0, 0); @@ -28,78 +28,68 @@ MainMenuScene::MainMenuScene(Client& client) : Scene(client), root.addStylesheet({ { "navigation", {{ - { Gui::StyleRule::SIZE, array { Expr(""), Expr("18dp") } } + { Gui::Prop::SIZE, array { Expr(""), Expr("18dp") } } }}}, { "navigationWrap", {{ - { Gui::StyleRule::DIRECTION, string("row") }, - { Gui::StyleRule::POS, array { Expr("0"), Expr("0") } } + { Gui::Prop::DIRECTION, string("row") }, + { Gui::Prop::POS, array { Expr("0"), Expr("0") } } }}}, { "navigationBackground", {{ - { Gui::StyleRule::SIZE, array { Expr("64dp"), Expr("18dp") } }, - { Gui::StyleRule::BACKGROUND, string("menu_bar_bg") } + { Gui::Prop::SIZE, array { Expr("64dp"), Expr("18dp") } }, + { Gui::Prop::BACKGROUND, string("menu_bar_bg") } }}}, { "navigationButton", {{ - { Gui::StyleRule::SIZE, array { Expr("16dp"), Expr("16dp") } }, - { Gui::StyleRule::CURSOR, string("pointer") } + { Gui::Prop::SIZE, array { Expr("16dp"), Expr("16dp") } }, + { Gui::Prop::CURSOR, string("pointer") } }}} }); root.body->append(sandboxElem); - let navigation = root.body->append({ .classes = { "navigation" } }); - let navigationBG = navigation->append({ .classes = { "navigationWrap" } }); + let navigation = root.body->append({{{ Gui::Prop::CLASS, vec { "navigation" } }}}); + let navigationBG = navigation->append({{{ Gui::Prop::CLASS, vec { "navigationWrap" } }}}); for (usize i = 0; i < 2000 / Gui::PX_SCALE / 64; i++) - navigationBG->append({ .classes = { "navigationBackground" } }); + navigationBG->append({{{ Gui::Prop::CLASS, vec { "navigationBackground" } }}}); - let navigationList = navigation->append({ - .classes = { "navigationWrap" }, - .styles = {{ - { Gui::StyleRule::PADDING, array { Expr("1dp"), Expr("1dp"), Expr("1dp"), Expr("1dp") } }, - { Gui::StyleRule::GAP, array { Expr("1dp"), Expr("1dp") } } - }} - }); + let navigationList = navigation->append({{ + { Gui::Prop::CLASS, vec { "navigationWrap" } }, + { Gui::Prop::GAP, array { Expr("1dp"), Expr("1dp") } }, + { Gui::Prop::PADDING, array { Expr("1dp"), Expr("1dp"), Expr("1dp"), Expr("1dp") } } + }}); - navigationList->append({ - .classes = { "navigationButton" }, - .styles = {{ - { Gui::StyleRule::BACKGROUND, string("crop(0, 0, 16, 16, menu_flag_multiplayer)") }, - { Gui::StyleRule::BACKGROUND_HOVER, string("crop(16, 0, 16, 16, menu_flag_multiplayer)") } - }} - }); + navigationList->append({{ + { Gui::Prop::CLASS, vec { "navigationButton" } }, + { Gui::Prop::BACKGROUND, string("crop(0, 0, 16, 16, menu_flag_multiplayer)") }, + { Gui::Prop::BACKGROUND_HOVER, string("crop(16, 0, 16, 16, menu_flag_multiplayer)") } + }}); - let contentButton = navigationList->append({ - .classes = { "navigationButton" }, - .styles = {{ - { Gui::StyleRule::BACKGROUND, string("crop(0, 0, 16, 16, menu_flag_content)") }, - { Gui::StyleRule::BACKGROUND_HOVER, string("crop(16, 0, 16, 16, menu_flag_content)") } - }} - }); + let contentButton = navigationList->append({{ + { Gui::Prop::CLASS, vec { "navigationButton" } }, + { Gui::Prop::BACKGROUND, string("crop(0, 0, 16, 16, menu_flag_content)") }, + { Gui::Prop::BACKGROUND_HOVER, string("crop(16, 0, 16, 16, menu_flag_content)") } + }}); contentButton->onClick([&](u32 button, bool down) { if (button != GLFW_MOUSE_BUTTON_1 || !down) return; client.scene.setScene(make_unique(client, Address { "127.0.0.1" })); }); - navigationList->append({ - .styles = {{ - { Gui::StyleRule::BACKGROUND, string("#fff5") }, - { Gui::StyleRule::SIZE, array { Expr("1dp"), Expr("10dp") } }, - { Gui::StyleRule::MARGIN, array { Expr("2dp"), Expr("3dp"), Expr("2dp"), Expr("3dp") } } - }} - }); + navigationList->append({{ + { Gui::Prop::BACKGROUND, string("#fff5") }, + { Gui::Prop::SIZE, array { Expr("1dp"), Expr("10dp") } }, + { Gui::Prop::MARGIN, array { Expr("2dp"), Expr("3dp"), Expr("2dp"), Expr("3dp") } } + }}); findSubgames(); for (usize i = 0; i < subgames.size(); i++) { let& subgame = subgames[i]; - let elem = navigationList->append({ - .classes = { "navigationButton" }, - .styles = {{ - { Gui::StyleRule::BACKGROUND, string("crop(0, 0, 16, 16, " + subgame.iconRef->name + ")") }, - { Gui::StyleRule::BACKGROUND_HOVER, string("crop(16, 0, 16, 16, " + subgame.iconRef->name + ")") } - }} - }); + let elem = navigationList->append({{ + { Gui::Prop::CLASS, vec { "navigationButton" } }, + { Gui::Prop::BACKGROUND, string("crop(0, 0, 16, 16, " + subgame.iconRef->name + ")") }, + { Gui::Prop::BACKGROUND_HOVER, string("crop(16, 0, 16, 16, " + subgame.iconRef->name + ")") } + }}); elem->onClick([&](u32 button, bool down) { if (button != GLFW_MOUSE_BUTTON_1 || !down) return; @@ -115,21 +105,17 @@ MainMenuScene::MainMenuScene(Client& client) : Scene(client), navigationList->append(); - navigationList->append({ - .classes = { "navigationButton" }, - .styles = {{ - { Gui::StyleRule::BACKGROUND, string("crop(0, 0, 16, 16, menu_flag_settings)") }, - { Gui::StyleRule::BACKGROUND_HOVER, string("crop(16, 0, 16, 16, menu_flag_settings)") } - }} - }); + navigationList->append({{ + { Gui::Prop::CLASS, vec { "navigationButton" } }, + { Gui::Prop::BACKGROUND, string("crop(0, 0, 16, 16, menu_flag_settings)") }, + { Gui::Prop::BACKGROUND_HOVER, string("crop(16, 0, 16, 16, menu_flag_settings)") } + }}); - let closeButton = navigationList->append({ - .classes = { "navigationButton" }, - .styles = {{ - { Gui::StyleRule::BACKGROUND, string("crop(0, 0, 16, 16, menu_flag_quit)") }, - { Gui::StyleRule::BACKGROUND_HOVER, string("crop(16, 0, 16, 16, menu_flag_quit)") } - }} - }); + let closeButton = navigationList->append({{ + { Gui::Prop::CLASS, vec { "navigationButton" } }, + { Gui::Prop::BACKGROUND, string("crop(0, 0, 16, 16, menu_flag_quit)") }, + { Gui::Prop::BACKGROUND_HOVER, string("crop(16, 0, 16, 16, menu_flag_quit)") } + }}); closeButton->onClick([](u32 button, bool down) { if (button != GLFW_MOUSE_BUTTON_1 || !down) return; diff --git a/src/lua/LocalLuaParser.cpp b/src/lua/LocalLuaParser.cpp index aef7c2c0..3e4d1774 100644 --- a/src/lua/LocalLuaParser.cpp +++ b/src/lua/LocalLuaParser.cpp @@ -22,7 +22,7 @@ #include "usertype/InventoryList.h" #include "usertype/AnimationManager.h" -#include "usertype/LuaGuiElement.h" +#include "usertype/GuiElement.h" // Modules #include "modules/Time.h" @@ -57,17 +57,18 @@ void LocalLuaParser::init(WorldPtr world, PlayerPtr player, Client& client) { } for (const let& line : lines) { - usize lineNumStart = line.find(':'); + usize fileNameStart = line.find('/'); + if (fileNameStart == string::npos) continue; + usize lineNumStart = line.find(':', fileNameStart + 1); if (lineNumStart == string::npos) continue; usize lineNumEnd = line.find(':', lineNumStart + 1); if (lineNumEnd == string::npos) continue; string fullPath = line.substr(0, lineNumStart); fullPath.erase(std::remove_if(fullPath.begin(), fullPath.end(), isspace), fullPath.end()); - - usize slashPos = fullPath.find('/'); - if (slashPos == string::npos) continue; - string modName = fullPath.substr(0, slashPos); + + fileNameStart = fullPath.find('/'); + string modName = fullPath.substr(0, fileNameStart); if (modName == "base") continue; let iter = mods.find(modName); diff --git a/src/lua/usertype/GuiElement.cpp b/src/lua/usertype/GuiElement.cpp new file mode 100644 index 00000000..262386de --- /dev/null +++ b/src/lua/usertype/GuiElement.cpp @@ -0,0 +1,212 @@ +#include "GuiElement.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" + +static const Gui::Expression parseObjectToExpr(sol::object value) { + if (!value.valid()) return Gui::Expression(""); + 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 {}; + + if (value.is()) { + const let& t = value.as(); + + vec exprs {}; + exprs.reserve(t.size()); + for (usize i = 1; i <= t.size(); i++) + exprs.emplace_back(parseObjectToExpr(t.get(i))); + + 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; +} + +Gui::Prop Api::Usertype::GuiElement::nameToProp(const string& str) { + using namespace Gui; + + const let ruleIt = Props::PROP_NAMES_TO_ENUM.find(str); + if (ruleIt == Props::PROP_NAMES_TO_ENUM.end()) + throw std::invalid_argument("Style rule '" + str + "' doesn't exist."); + return ruleIt->second; +} + +any Api::Usertype::GuiElement::objectToProp(Gui::Prop prop, const sol::object& value) { + using namespace Gui; + + switch (prop) { + default: + throw std::invalid_argument("Unhandled rule! This is an engine error! [1]"); + + case Prop::ID: + case Prop::LAYOUT: + case Prop::DIRECTION: + case Prop::H_ALIGN: + case Prop::V_ALIGN: + case Prop::CURSOR: + case Prop::OVERFLOW: + case Prop::TEXT_COLOR: + case Prop::BACKGROUND: + case Prop::BACKGROUND_HOVER: + case Prop::CONTENT: + return value.as(); + + case Prop::POS: + case Prop::SIZE: + case Prop::GAP: + return parseLengthTableVal<2>(value); + + case Prop::MARGIN: + case Prop::PADDING: + return parseLengthTableVal<4>(value); + + case Prop::TEXT_SIZE: + return parseObjectToExpr(value); + } +} + +sol::object Api::Usertype::GuiElement::propToObject(Gui::Prop prop, any value, sol::state_view s) { + using namespace Gui; + + switch (prop) { + default: + throw std::invalid_argument("Unhandled rule! This is an engine error! [1]"); + + case Prop::LAYOUT: + case Prop::DIRECTION: + case Prop::H_ALIGN: + case Prop::V_ALIGN: + case Prop::CURSOR: + case Prop::OVERFLOW: +// case Prop::TEXT_COLOR: + case Prop::BACKGROUND: + case Prop::BACKGROUND_HOVER: + case Prop::CONTENT: + return sol::make_object(s, std::any_cast(value)); + + case Prop::POS: + case Prop::SIZE: + case Prop::GAP: + +// return sol::make_object(s, s.create_table_with( +// +// )); +// return sol::make_object(s, std::any_cast(value)); + + case Prop::MARGIN: + case Prop::PADDING: +// return parseLengthTableVal<4>(value); + + case Prop::TEXT_SIZE: + break; + throw std::invalid_argument("Unhandled rule! This is an engine error! [1]"); +// return parseObjectToExpr(value); + } +} + +sptr Api::Usertype::GuiElement::create(const string& type, sol::table data, Gui::Root& root) { + Gui::Props props {}; + + for (let& style : data) { + if (!style.first.is()) continue; + let rule = GuiElement::nameToProp(style.first.as()); + let value = GuiElement::objectToProp(rule, style.second); + props.props[rule] = value; + } + + 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; +} + +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); + }), + "prepend", [&](sol::this_state s, Gui::Element& self, sol::object child) { + if (child.is>()) self.prepend(child.as>()); + else if (child.is()) { + sol::protected_function fn = child.as(); + sol::table tbl = sol::state_view(s)["zepha"]["__builtin"]["gui_env"]; + sol::environment env(s, sol::create, tbl); + sol::set_environment(env, fn); + self.prepend(static_cast(fn()).as>()); + } + else throw std::invalid_argument( + "Cannot append() an item that is not an element or a function that returns one."); + }, + "append", [&](sol::this_state s, Gui::Element& self, sol::object child) { + if (child.is>()) self.append(child.as>()); + else if (child.is()) { + let fn = child.as(); + sol::table tbl = sol::state_view(s)["zepha"]["__builtin"]["gui_env"]; + sol::environment env(s, sol::create, tbl); + sol::set_environment(env, fn); + self.append(static_cast(fn()).as>()); + } + else throw std::invalid_argument( + "append() parameter must be an element or a function that returns one."); + }, + "get", [&](sol::this_state s, Gui::Element& self, sol::object query) -> sol::object { + let found = query.is() ? self.get(query.as() - 1) : self.get(query.as()); + if (!found) return sol::nil; + return sol::make_object(s, found); + }, + "remove", [&](sol::this_state s, Gui::Element& self, sol::object query) { + if (query == sol::nil) self.remove(); + else if (query.is()) { + let child = self.get(query.as()); + if (child) child->remove(); + } + else if (query.is()) { + let child = self.get(query.as()); + if (child) child->remove(); + } + else if (query.is>()) { + query.as>()->remove(); + } + else throw std::invalid_argument( + "remove() parameter must be nil, a number, an string, or a Gui element."); + }, + "clear", &Gui::Element::clear, + sol::meta_function::new_index, [&](Gui::Element& self, const string& ruleStr, sol::object rawValue) { + let rule = GuiElement::nameToProp(ruleStr); + let value = GuiElement::objectToProp(rule, rawValue); + self.setProp(rule, value); + self.updateElement(); + }, + sol::meta_function::index, [&](sol::this_state s, Gui::Element& self, const string& ruleStr) { + let rule = GuiElement::nameToProp(ruleStr); + let value = self.getProps().get(rule); + if (!value) return sol::make_object(s, sol::nil); + return GuiElement::propToObject(rule, *value, s); + } + ); +} \ No newline at end of file diff --git a/src/lua/usertype/LuaGuiElement.h b/src/lua/usertype/GuiElement.h similarity index 91% rename from src/lua/usertype/LuaGuiElement.h rename to src/lua/usertype/GuiElement.h index f17220e5..9ff200fc 100644 --- a/src/lua/usertype/LuaGuiElement.h +++ b/src/lua/usertype/GuiElement.h @@ -8,13 +8,13 @@ namespace Gui { class Style; class Root; class Element; - enum class StyleRule; + enum class Prop; } namespace Api::Usertype::GuiElement { - Gui::StyleRule ruleFromStr(const string& str); - any parseRuleValue(Gui::StyleRule rule, const sol::object& value); - sol::object styleAnyToObject(Gui::StyleRule rule, optional value, sol::this_state s); + Gui::Prop nameToProp(const string& str); + any objectToProp(Gui::Prop prop, const sol::object& value); + sol::object propToObject(Gui::Prop prop, any value, sol::state_view s); std::shared_ptr create(const string& type, sol::table data, Gui::Root& root); diff --git a/src/lua/usertype/LuaGuiElement.cpp b/src/lua/usertype/LuaGuiElement.cpp deleted file mode 100644 index 95b145c2..00000000 --- a/src/lua/usertype/LuaGuiElement.cpp +++ /dev/null @@ -1,333 +0,0 @@ -#include "LuaGuiElement.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" - -static const Gui::Expression parseObjectToExpr(sol::object value) { - if (!value.valid()) return Gui::Expression(""); - 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 {}; - - if (value.is()) { - const let& t = value.as(); - - vec exprs {}; - exprs.reserve(t.size()); - for (usize i = 1; i <= t.size(); i++) - exprs.emplace_back(parseObjectToExpr(t.get(i))); - - 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; -} - -Gui::StyleRule Api::Usertype::GuiElement::ruleFromStr(const string& str) { - using namespace Gui; - - const let ruleIt = Style::RULE_STRINGS_TO_ENUMS.find(str); - if (ruleIt == Style::RULE_STRINGS_TO_ENUMS.end()) - throw std::invalid_argument("Style rule '" + str + "' doesn't exist."); - return ruleIt->second; -} - -any Api::Usertype::GuiElement::parseRuleValue(Gui::StyleRule rule, const sol::object& value) { - using namespace Gui; - - switch (rule) { - default: - throw std::invalid_argument("Unhandled rule! This is an engine error! [1]"); - - 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: - return value.as(); - - case StyleRule::POS: - case StyleRule::SIZE: - case StyleRule::GAP: - return parseLengthTableVal<2>(value); - - case StyleRule::MARGIN: - case StyleRule::PADDING: - return parseLengthTableVal<4>(value); - - case StyleRule::TEXT_SIZE: - return parseObjectToExpr(value); - } -} - -sol::object Api::Usertype::GuiElement::styleAnyToObject(Gui::StyleRule rule, optional value, sol::this_state s) { - using namespace Gui; - - switch (rule) { - default: - throw std::invalid_argument("Unhandled rule! This is an engine error! [1]"); - - 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: - return sol::make_object(s, std::any_cast(value)); - - case StyleRule::POS: - case StyleRule::SIZE: - case StyleRule::GAP: -// return sol::make_object(s, std::any_cast(value)); - - case StyleRule::MARGIN: - case StyleRule::PADDING: -// return parseLengthTableVal<4>(value); - - case StyleRule::TEXT_SIZE: - break; -// return parseObjectToExpr(value); - } -} - -sptr 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; - let rule = GuiElement::ruleFromStr(style.first.as()); - let value = GuiElement::parseRuleValue(rule, style.second); - props.styles.rules[rule] = value; - } - - 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; -} - -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); - }), - "append", [&](Gui::Element& self, sptr child) { - self.append(child); - }, - "get", [&](sol::this_state s, Gui::Element& self, sol::object query) -> sol::object { - if (query.is()) { - let found = self.get(query.as() - 1); - if (!found) return sol::nil; - return sol::make_object(s, found); - } - else throw std::runtime_error("ID get is unimplemented."); - }, - sol::meta_function::new_index, [&](Gui::Element& self, const string& ruleStr, sol::object rawValue) { - let rule = GuiElement::ruleFromStr(ruleStr); - let value = GuiElement::parseRuleValue(rule, rawValue); - self.setStyle(rule, value); - self.updateElement(); - } - ); -} - -// -//// 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; -// } -// } -// -// 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/world/player/LocalPlayer.cpp b/src/world/player/LocalPlayer.cpp index 49fb4517..fcd069d5 100644 --- a/src/world/player/LocalPlayer.cpp +++ b/src/world/player/LocalPlayer.cpp @@ -21,15 +21,15 @@ LocalPlayer::LocalPlayer(SubgamePtr game, LocalWorld& world, DimensionPtr dim, R renderer(renderer) { handItemModel.parent = &handModel; - hud = root.body->append({ .styles {{ - { Gui::StyleRule::POS, array { Gui::Expression("0"), Gui::Expression("0") }}, - { Gui::StyleRule::SIZE, array { Gui::Expression("100cw"), Gui::Expression("100ch") }} - }}}); + hud = root.body->append({{ + { Gui::Prop::POS, array { Gui::Expression("0"), Gui::Expression("0") }}, + { Gui::Prop::SIZE, array { Gui::Expression("100cw"), Gui::Expression("100ch") }} + }}); - menu = root.body->append({ .styles {{ - { Gui::StyleRule::POS, array { Gui::Expression("0"), Gui::Expression("0") }}, - { Gui::StyleRule::SIZE, array { Gui::Expression("100cw"), Gui::Expression("100ch") }} - }}}); + menu = root.body->append({{ + { Gui::Prop::POS, array { Gui::Expression("0"), Gui::Expression("0") }}, + { Gui::Prop::SIZE, array { Gui::Expression("100cw"), Gui::Expression("100ch") }} + }}); } void LocalPlayer::update(f64 delta, vec2 mouseDelta) { diff --git a/subgames/zeus/menu/script/init.lua b/subgames/zeus/menu/script/init.lua index 296a3cf6..60e407a4 100644 --- a/subgames/zeus/menu/script/init.lua +++ b/subgames/zeus/menu/script/init.lua @@ -66,13 +66,15 @@ for _ = 1, 100 do end local particle_wrap = menu:get(1) -for i, pos in ipairs(positions) do - particle_wrap:append(zepha.Gui.Box { - pos = pos, - background = 'particle_dark', - size = sizes[i] - }) -end +zepha.gui(function() + for i, pos in ipairs(positions) do + particle_wrap:append(Gui.Box { + pos = pos, + background = 'particle_dark', + size = sizes[i] + }) + end +end) local tick = 0 zepha.after(function() diff --git a/subgames/zeus/mods/auri_chat/script/gui.lua b/subgames/zeus/mods/auri_chat/script/gui.lua index 8be99ef1..89b22293 100644 --- a/subgames/zeus/mods/auri_chat/script/gui.lua +++ b/subgames/zeus/mods/auri_chat/script/gui.lua @@ -1,25 +1,24 @@ local max_messages = 8 -local chat_wrap = zepha.build_gui(function() - return Gui.Rect { - position = { 4, '100%' }, - position_anchor = { 0, '200%' }, +local chat_wrap = zepha.gui(function() + return Gui.Box { + pos = { 4, '100ch - 100sh - 100dp' }, size = { 256, 23 + max_messages * 8 }, - Gui.Rect { - key = 'chat_tabs', - position = { 0, -10 } + Gui.Box { + id = 'chat_tabs', + pos = { 0, -10 } }, - Gui.Rect { - key = 'chat_box', + Gui.Box { + id = 'chat_box', size = { 256, 2 + max_messages * 8 } }, - Gui.Rect { - key = 'chat_input', + Gui.Box { + id = 'chat_input', size = { 256, 10 }, - position = { 0, 3 + max_messages * 8 } + pos = { 0, 3 + max_messages * 8 } } } end) diff --git a/subgames/zeus/mods/auri_chat/script/init.lua b/subgames/zeus/mods/auri_chat/script/init.lua index 6f8e6e51..7064d770 100644 --- a/subgames/zeus/mods/auri_chat/script/init.lua +++ b/subgames/zeus/mods/auri_chat/script/init.lua @@ -1,5 +1,5 @@ require(_PATH .. 'api') -if zepha.client then runfile(_PATH .. 'gui') end +if zepha.client then require(_PATH .. 'gui') end if zepha.server then chat.create_channel('chat', { name = 'Chat', icon = '@auri:chat:chat_icon' }) diff --git a/subgames/zeus/mods/auri_health/script/init.lua b/subgames/zeus/mods/auri_health/script/init.lua index 70c46b00..5ccca303 100644 --- a/subgames/zeus/mods/auri_health/script/init.lua +++ b/subgames/zeus/mods/auri_health/script/init.lua @@ -1,6 +1,6 @@ -_G['health'] = {} -health.internal = {} - -require(_PATH .. 'api') -require(_PATH .. 'interface') -require(_PATH .. 'hooks') \ No newline at end of file +-- _G['health'] = {} +-- health.internal = {} +-- +-- require(_PATH .. 'api') +-- require(_PATH .. 'interface') +-- require(_PATH .. 'hooks') \ No newline at end of file diff --git a/subgames/zeus/mods/auri_health/script/interface.lua b/subgames/zeus/mods/auri_health/script/interface.lua index b23f49ef..6a33089a 100644 --- a/subgames/zeus/mods/auri_health/script/interface.lua +++ b/subgames/zeus/mods/auri_health/script/interface.lua @@ -14,7 +14,7 @@ function health.internal.update() health.internal._wrapper:remove('@health:component') health.internal._wrapper:append(function() - local elem = Gui.Rect { + local elem = Gui.Box { id = '@health:component', size = { health.internal._width, 9 }, } diff --git a/subgames/zeus/mods/auri_hot_wheel/script/init.lua b/subgames/zeus/mods/auri_hot_wheel/script/init.lua index 5303a58d..45e37110 100644 --- a/subgames/zeus/mods/auri_hot_wheel/script/init.lua +++ b/subgames/zeus/mods/auri_hot_wheel/script/init.lua @@ -1,10 +1,10 @@ -_G["hot_wheel"] = {} - -if zepha.server then - require(_PATH .. "register") -end - -if zepha.client then - require(_PATH .. "interface") - require(_PATH .. "keys") -end +-- _G["hot_wheel"] = {} +-- +-- if zepha.server then +-- require(_PATH .. "register") +-- end +-- +-- if zepha.client then +-- require(_PATH .. "interface") +-- require(_PATH .. "keys") +-- end diff --git a/subgames/zeus/mods/zeus_inventory/script/chest.lua b/subgames/zeus/mods/zeus_inventory/script/chest.lua index 8757c66c..f3059268 100644 --- a/subgames/zeus/mods/zeus_inventory/script/chest.lua +++ b/subgames/zeus/mods/zeus_inventory/script/chest.lua @@ -1,49 +1,45 @@ -local chest = zepha.build_gui(function() - return Gui.Body { +local chest = zepha.gui(function() + return Gui.Box { background = "#0003", - callbacks = { - primary = function() zepha.player:close_menu() end, - }, - - Gui.Rect { - key = "inventory", - position = { pc(50), pc(50) }, - position_anchor = { pc(50), pc(32) }, - size = { 218, 160 }, - - Gui.Rect { - key = "inventory_background", - - position = { 0, 50 }, - size = { 218, 100 }, - padding = { 20, 10, 8, 10 }, - background = "zeus:inventory:inventory", - - Gui.InventoryList { - position = { 1, 1 }, - slot_spacing = { 2, 2 }, - source = "current_player", - list = "main", - } - }, - - Gui.Rect { - key = "chest_background", - - position = { 0, -48 }, - size = { 218, 100 }, - padding = { 20, 10, 8, 10 }, - background = "zeus:inventory:chest", - - Gui.InventoryList { - position = { 1, 1 }, - slot_spacing = { 2, 2 }, - source = "current_player", - list = "main", - } - } - } +-- Gui.Rect { +-- key = "inventory", +-- position = { pc(50), pc(50) }, +-- position_anchor = { pc(50), pc(32) }, +-- size = { 218, 160 }, +-- +-- Gui.Rect { +-- key = "inventory_background", +-- +-- position = { 0, 50 }, +-- size = { 218, 100 }, +-- padding = { 20, 10, 8, 10 }, +-- background = "zeus:inventory:inventory", +-- +-- Gui.InventoryList { +-- position = { 1, 1 }, +-- slot_spacing = { 2, 2 }, +-- source = "current_player", +-- list = "main", +-- } +-- }, +-- +-- Gui.Rect { +-- key = "chest_background", +-- +-- position = { 0, -48 }, +-- size = { 218, 100 }, +-- padding = { 20, 10, 8, 10 }, +-- background = "zeus:inventory:chest", +-- +-- Gui.InventoryList { +-- position = { 1, 1 }, +-- slot_spacing = { 2, 2 }, +-- source = "current_player", +-- list = "main", +-- } +-- } +-- } } end) diff --git a/subgames/zeus/mods/zeus_inventory/script/menu.lua b/subgames/zeus/mods/zeus_inventory/script/menu.lua index bb638fdc..f45bdfe5 100644 --- a/subgames/zeus/mods/zeus_inventory/script/menu.lua +++ b/subgames/zeus/mods/zeus_inventory/script/menu.lua @@ -1,127 +1,135 @@ -local menu = zepha.build_gui(function() - return Gui.Body { +local menu = zepha.gui(function() + return Gui.Box { background = "#0003", - callbacks = { - primary = function() zepha.player:close_menu() end, - }, + Gui.Box { + id = "inventory", - Gui.Rect { - key = "inventory", - position = { pc(50), pc(50) }, - position_anchor = { pc(50), pc(50) }, size = { 342, 187 }, + pos = { "50cw - 50sw", "50ch - 50sh" }, - Gui.Rect { - key = "backpack", + Gui.Box { + id = "backpack", - position = { 1, 0 }, + pos = { 1, 0 }, size = { 106, 187 }, padding = { 19, 9, 8, 9 }, - background = "zeus:inventory:backpack", - Gui.InventoryList { - position = { 0, 0 }, - slot_spacing = { 2, 2 }, - source = "current_player", - list = "main", - }, - Gui.InventoryList { - position = { 0, 18*3 }, - slot_spacing = { 2, 2 }, - source = "current_player", - list = "hot_wheel_1", - }, - Gui.InventoryList { - position = { 0, 18*4 }, - slot_spacing = { 2, 2 }, - source = "current_player", - list = "hot_wheel_2", - }, - Gui.InventoryList { - position = { 0, 18*5 }, - slot_spacing = { 2, 2 }, - source = "current_player", - list = "hot_wheel_3", - }, - Gui.InventoryList { - position = { 0, 18*6 }, - slot_spacing = { 2, 2 }, - source = "current_player", - list = "hot_wheel_4", - }, - Gui.InventoryList { - position = { 0, 18*7 }, - slot_spacing = { 2, 2 }, - source = "current_player", - list = "hot_wheel_5", - }, - Gui.InventoryList { - position = { 0, 18*8 }, - slot_spacing = { 2, 2 }, - source = "current_player", - list = "hot_wheel_6", - } + background = "zeus:inventory:backpack" + +-- Gui.InventoryList { +-- gap = { 2, 2 }, +-- pos = { 0, 0 }, +-- +-- list = "main", +-- source = "current_player" +-- }, +-- Gui.InventoryList { +-- gap = { 2, 2 }, +-- pos = { 0, 18 * 3 }, +-- +-- list = "hot_wheel_1", +-- source = "current_player" +-- }, +-- Gui.InventoryList { +-- gap = { 2, 2 }, +-- pos = { 0, 18 * 4 }, +-- +-- list = "hot_wheel_2", +-- source = "current_player" +-- }, +-- Gui.InventoryList { +-- gap = { 2, 2 }, +-- pos = { 0, 18 * 5 }, +-- +-- list = "hot_wheel_3", +-- source = "current_player" +-- }, +-- Gui.InventoryList { +-- gap = { 2, 2 }, +-- pos = { 0, 18 * 6 }, +-- +-- list = "hot_wheel_4", +-- source = "current_player" +-- }, +-- Gui.InventoryList { +-- gap = { 2, 2 }, +-- pos = { 0, 18 * 7 }, +-- +-- list = "hot_wheel_5", +-- source = "current_player" +-- }, +-- Gui.InventoryList { +-- gap = { 2, 2 }, +-- pos = { 0, 18*8 }, +-- +-- list = "hot_wheel_6", +-- source = "current_player" +-- } }, - Gui.Rect { - key = "player_frame", - position = { 105, 0 }, + Gui.Box { + id = "player_frame", + + pos = { 105, 0 }, size = { 106, 187 }, + background = "zeus:inventory:player_frame", - Gui.Model { - position = { 52, 150 }, - scale = { 64, 64 }, - - type = "model", - source = "zeus:default:player", - texture = "zeus:default:player", - anim_range = { 0, 100 } - } +-- Gui.Model { +-- pos = { 52, 150 }, +-- size = { 64, 64 }, +-- +-- type = "model", +-- anim_range = { 0, 100 }, +-- source = "zeus:default:player", +-- texture = "zeus:default:player" +-- } }, - Gui.Rect { - key = "equipment", + Gui.Box { + id = "equipment", - position = { 209, 1 }, + pos = { 209, 1 }, size = { 132, 80 }, padding = { 18, 8, 8, 8 }, background = "zeus:inventory:equipment", - Gui.Rect { - key = "player_clamp", + Gui.Box { + id = "player_clamp", - position = { 41, 1 }, + pos = { 41, 1 }, size = { 34, 52 }, overflow = "hidden" } }, - Gui.Rect { - key = "dynamic", + Gui.Box { + id = "dynamic", - position = { 209, 80 }, + pos = { 209, 80 }, size = { 132, 107 }, padding = { 8, 8, 8, 8 }, - background = "zeus:inventory:dynamic", + background = "zeus:inventory:dynamic" - Gui.InventoryList { - position = { 1, 1 }, - slot_spacing = { 2, 2 }, - source = "current_player", - list = "mod", - }, - - Gui.InventoryList { - position = { 41, 32 }, - slot_spacing = { 2, 2 }, - source = "current_player", - list = "craft", - }, - Gui.InventoryList { - position = { 81, 41 }, - slot_spacing = { 2, 2 }, - source = "current_player", - list = "craft_result", - } +-- Gui.InventoryList { +-- gap = { 2, 2 }, +-- pos = { 1, 1 }, +-- +-- list = "mod", +-- source = "current_player", +-- }, +-- Gui.InventoryList { +-- gap = { 2, 2 }, +-- pos = { 41, 32 }, +-- +-- list = "craft", +-- source = "current_player" +-- }, +-- Gui.InventoryList { +-- gap = { 2, 2 }, +-- pos = { 81, 41 }, +-- +-- list = "craft_result", +-- source = "current_player" +-- } } } }