More Lua GuiElement functionality.
parent
1c58797480
commit
9aec996b74
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<vec4, ValueType::COLOR>(bgRule);
|
||||
const let bgColor = getStyle<vec4, Type::COLOR>(bgRule);
|
||||
const string bgImage = getStyle<string>(bgRule, "");
|
||||
|
||||
let mesh = std::make_unique<EntityMesh>();
|
||||
|
@ -48,7 +48,7 @@ void Gui::BoxElement::updateElement() {
|
|||
entity.setModel(model);
|
||||
}
|
||||
|
||||
let margin = getStyle<ivec4, ValueType::LENGTH>(StyleRule::MARGIN, {});
|
||||
let margin = getStyle<ivec4, Type::LENGTH>(Prop::MARGIN, {});
|
||||
|
||||
entity.setScale(vec3(getComputedSize(), 0));
|
||||
entity.setPos(vec3(getComputedScreenPos() + ivec2 { margin.x, margin.y }, 0));
|
||||
|
|
|
@ -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<any> 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> Gui::Element::get(u32 ind) {
|
||||
|
@ -26,10 +26,33 @@ sptr<Gui::Element> Gui::Element::get(u32 ind) {
|
|||
return children[ind];
|
||||
}
|
||||
|
||||
sptr<Gui::Element> Gui::Element::get(const string& id) {
|
||||
for (let& child : children) {
|
||||
if (child->props.get<string>(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<void(i32, bool)>& cb) {
|
||||
clickCb = cb;
|
||||
}
|
||||
|
@ -42,7 +65,7 @@ Gui::ExpressionInfo Gui::Element::getExpr() const {
|
|||
}
|
||||
|
||||
ivec2 Gui::Element::getComputedSize() const {
|
||||
let size = getStyleWithExpr<vec2, ValueType::LENGTH>(StyleRule::SIZE, vec2(nanf("")),
|
||||
let size = getStyleWithExpr<vec2, Type::LENGTH>(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<ivec4, ValueType::LENGTH>(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<ivec4, ValueType::LENGTH>(StyleRule::PADDING, {});
|
||||
let padding = getStyle<ivec4, Type::LENGTH>(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<ivec2, ValueType::LENGTH>(StyleRule::SIZE, ivec2(-1));
|
||||
return getStyle<ivec2, Type::LENGTH>(Prop::SIZE, ivec2(-1));
|
||||
}
|
||||
|
||||
ivec2 Gui::Element::getComputedPos() const {
|
||||
return getStyle<ivec2, ValueType::LENGTH>(StyleRule::POS, layoutPosition);
|
||||
return getStyle<ivec2, Type::LENGTH>(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<string>(StyleRule::CURSOR);
|
||||
let cursor = getStyle<string>(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<string>(StyleRule::LAYOUT, "");
|
||||
const string& layout = getStyle<string>(Prop::LAYOUT, "");
|
||||
|
||||
switch (Util::hash(layout.data())) {
|
||||
default:
|
||||
case Util::hash("flex"): {
|
||||
const string& direction = getStyle<string>(StyleRule::DIRECTION, "");
|
||||
const string& direction = getStyle<string>(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<string>(StyleRule::H_ALIGN, "");
|
||||
const string& vAlignRaw = getStyle<string>(StyleRule::V_ALIGN, "");
|
||||
const string& hAlignRaw = getStyle<string>(Prop::H_ALIGN, "");
|
||||
const string& vAlignRaw = getStyle<string>(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<ivec2, ValueType::LENGTH>(StyleRule::GAP, ivec2(0))[primary];
|
||||
const ivec4& padding = getStyle<ivec4, ValueType::LENGTH>(StyleRule::PADDING, ivec4 {});
|
||||
const i32 gap = getStyle<ivec2, Type::LENGTH>(Prop::GAP, ivec2(0))[primary];
|
||||
const ivec4& padding = getStyle<ivec4, Type::LENGTH>(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<ivec4, ValueType::LENGTH>(StyleRule::MARGIN, {});
|
||||
let childMargin = child->getStyle<ivec4, Type::LENGTH>(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<ivec4, ValueType::LENGTH>(StyleRule::MARGIN, {});
|
||||
let childMargin = child->getStyle<ivec4, Type::LENGTH>(Prop::MARGIN, {});
|
||||
|
||||
child->layoutSize[primary] =
|
||||
(childExplicitSize[primary] == -1 && align[primary] == 2) ? implicitElemSize : 0;
|
||||
|
@ -227,4 +244,4 @@ void Gui::Element::layoutChildren() {
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,10 +3,10 @@
|
|||
#include <functional>
|
||||
|
||||
#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<string> classes {};
|
||||
Style styles {};
|
||||
};
|
||||
|
||||
Element(Root& root, vec<StyleSheet>& 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<any> 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<Element> get(u32 ind);
|
||||
|
||||
sptr<Element> get(const string& id);
|
||||
|
||||
template<typename E, std::enable_if_t<std::is_base_of_v<Element, E>, bool> = true>
|
||||
sptr<E> get(u32 ind) {
|
||||
return std::dynamic_pointer_cast<E>(get(ind));
|
||||
|
@ -92,14 +89,13 @@ namespace Gui {
|
|||
|
||||
void clear();
|
||||
|
||||
void remove();
|
||||
|
||||
void onClick(const std::function<void(i32, bool)>& 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<any> getStyle(StyleRule rule) const {
|
||||
const optional<any> opt = props.styles.get(rule);
|
||||
const optional<any> getStyle(Prop rule) const {
|
||||
const optional<any> opt = props.get(rule);
|
||||
if (opt) return *opt;
|
||||
const let& classes = props.get<vec<string>>(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<any> 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<typename V, ValueType T = ValueType::LITERAL,
|
||||
std::enable_if_t<T != ValueType::LENGTH, bool> = true>
|
||||
template<typename V, Type T = Type::LITERAL, std::enable_if_t<T != Type::LENGTH, bool> = true>
|
||||
|
||||
const optional<V> getStyle(StyleRule rule) const {
|
||||
const optional<V> opt = props.styles.get<V, T>(rule);
|
||||
const optional<V> getStyle(Prop rule) const {
|
||||
const optional<V> opt = props.get<V, T>(rule);
|
||||
if (opt) return *opt;
|
||||
const let& classes = props.get<vec<string>>(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<V> opt = styles->second.get<V, T>(rule);
|
||||
|
@ -146,15 +145,16 @@ namespace Gui {
|
|||
}
|
||||
|
||||
/** Gets a LENGTH value from the element's styles or the root's stylesheets. */
|
||||
template<typename V, ValueType T = ValueType::LITERAL,
|
||||
std::enable_if_t<T == ValueType::LENGTH, bool> = true>
|
||||
template<typename V, Type T = Type::LITERAL, std::enable_if_t<T == Type::LENGTH, bool> = true>
|
||||
|
||||
const optional<V> getStyle(StyleRule rule) const {
|
||||
const optional<V> getStyle(Prop rule) const {
|
||||
ExpressionInfo info = getExpr();
|
||||
const optional<V> opt = props.styles.get<V, T>(rule, info);
|
||||
const optional<V> opt = props.get<V, T>(rule, info);
|
||||
if (opt) return *opt;
|
||||
const let& classes = props.get<vec<string>>(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<V> opt = styles->second.get<V, T>(rule, info);
|
||||
|
@ -165,14 +165,15 @@ namespace Gui {
|
|||
}
|
||||
|
||||
/** Gets a LENGTH value from the element's styles or the root's stylesheets. */
|
||||
template<typename V, ValueType T = ValueType::LITERAL,
|
||||
std::enable_if_t<T == ValueType::LENGTH, bool> = true>
|
||||
template<typename V, Type T = Type::LITERAL, std::enable_if_t<T == Type::LENGTH, bool> = true>
|
||||
|
||||
const optional<V> getStyleWithExpr(StyleRule rule, const ExpressionInfo& expr) const {
|
||||
const optional<V> opt = props.styles.get<V, T>(rule, expr);
|
||||
const optional<V> getStyleWithExpr(Prop rule, const ExpressionInfo& expr) const {
|
||||
const optional<V> opt = props.get<V, T>(rule, expr);
|
||||
if (opt) return *opt;
|
||||
const let& classes = props.get<vec<string>>(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<V> opt = styles->second.get<V, T>(rule, expr);
|
||||
|
@ -183,19 +184,18 @@ namespace Gui {
|
|||
}
|
||||
|
||||
/** Gets a style value from the element's styles or the root's stylesheets. */
|
||||
template<typename V, ValueType T = ValueType::LITERAL>
|
||||
template<typename V, Type T = Type::LITERAL>
|
||||
|
||||
const V getStyle(StyleRule rule, V def) const {
|
||||
const V getStyle(Prop rule, V def) const {
|
||||
const optional<V> opt = getStyle<V, T>(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<typename V, ValueType T = ValueType::LITERAL,
|
||||
std::enable_if_t<T == ValueType::LENGTH, bool> = true>
|
||||
template<typename V, Type T = Type::LITERAL, std::enable_if_t<T == Type::LENGTH, bool> = 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<V> opt = getStyleWithExpr<V, T>(rule, info);
|
||||
if (opt) return *opt;
|
||||
return def;
|
||||
|
|
|
@ -10,17 +10,15 @@ Gui::Root::Root(Window& window, TextureAtlas& atlas) :
|
|||
body(make_shared<BoxElement>(*this, stylesheets)) {
|
||||
const ivec2 size = window.getSize();
|
||||
|
||||
body->setProps({
|
||||
.id = "body",
|
||||
.styles = {{
|
||||
{ StyleRule::SIZE, array<Expression, 2> {
|
||||
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, 2> { 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, 2> {
|
||||
Expression(std::to_string(size.x)), Expression(std::to_string(size.y)) });
|
||||
body->setProp(Prop::SIZE, array<Expr, 2> {
|
||||
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<string, Style>& sheet) {
|
||||
void Gui::Root::addStylesheet(const StyleSheet& sheet) {
|
||||
stylesheets.emplace_back(sheet);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace Gui {
|
|||
|
||||
template<typename E, std::enable_if_t<std::is_base_of_v<Element, E>, bool> = true>
|
||||
|
||||
sptr<E> create(const Element::Props& props = {}, const vec<sptr<Element>>& children = {}) {
|
||||
sptr<E> create(const Props& props = {}, const vec<sptr<Element>>& children = {}) {
|
||||
let elem = make_shared<E>(*this, stylesheets);
|
||||
elem->setProps(props);
|
||||
|
||||
|
@ -39,7 +39,7 @@ namespace Gui {
|
|||
* styles for elements with specific classes.
|
||||
*/
|
||||
|
||||
void addStylesheet(const std::unordered_map<string, Style>& sheet);
|
||||
void addStylesheet(const StyleSheet& sheet);
|
||||
|
||||
/** Processes mouse events. */
|
||||
void update();
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
#include "Style.h"
|
||||
|
||||
const std::unordered_map<string, Gui::StyleRule> 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<string, Gui::Prop> 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 }
|
||||
};
|
|
@ -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<StyleRule, any>& rules): rules(rules) {}
|
||||
Props() = default;
|
||||
Props(const std::unordered_map<Prop, any>& 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<any> get(StyleRule rule) const {
|
||||
const let it = rules.find(rule);
|
||||
if (it == rules.end()) return std::nullopt;
|
||||
const optional<any> get(Prop prop) const {
|
||||
const let it = props.find(prop);
|
||||
if (it == props.end()) return std::nullopt;
|
||||
return optional<any>(it->second);
|
||||
}
|
||||
|
||||
|
@ -54,14 +57,14 @@ namespace Gui {
|
|||
* or an empty optional if the rule is not defined, or not the type V.
|
||||
*/
|
||||
|
||||
template<typename V, ValueType T = ValueType::LITERAL, std::enable_if_t<
|
||||
template<typename V, Type T = Type::LITERAL, std::enable_if_t<
|
||||
!(std::is_integral_v<V> ||
|
||||
std::is_floating_point_v<V> ||
|
||||
std::is_same_v<V, string>) &&
|
||||
T == ValueType::LITERAL, bool> = true>
|
||||
T == Type::LITERAL, bool> = true>
|
||||
|
||||
const optional<V> get(StyleRule rule) const {
|
||||
const optional<any> raw = get(rule);
|
||||
const optional<V> get(Prop prop) const {
|
||||
const optional<any> raw = get(prop);
|
||||
if (!raw || raw->type() != typeid(V)) return std::nullopt;
|
||||
return any_cast<V>(*raw);
|
||||
}
|
||||
|
@ -70,15 +73,14 @@ namespace Gui {
|
|||
* get<O, T> specialization for string-like values.
|
||||
*/
|
||||
|
||||
template<typename S, ValueType T = ValueType::LITERAL, std::enable_if_t<
|
||||
template<typename S, Type T = Type::LITERAL, std::enable_if_t<
|
||||
std::is_same_v<S, string> &&
|
||||
T == ValueType::LITERAL, bool> = true>
|
||||
T == Type::LITERAL, bool> = true>
|
||||
|
||||
const optional<S> get(StyleRule rule) const {
|
||||
const optional<any> raw = get(rule);
|
||||
const optional<S> get(Prop prop) const {
|
||||
const optional<any> raw = get(prop);
|
||||
if (!raw) return std::nullopt;
|
||||
if (raw->type() == typeid(string)) return any_cast<string>(*raw);
|
||||
// if (raw->type() == typeid(const char*)) return any_cast<const char*>(*raw);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -86,26 +88,15 @@ namespace Gui {
|
|||
* get<O, T> specialization for numeric values.
|
||||
*/
|
||||
|
||||
template<typename N, ValueType T = ValueType::LITERAL, std::enable_if_t<
|
||||
template<typename N, Type T = Type::LITERAL, std::enable_if_t<
|
||||
(std::is_integral_v<N> ||
|
||||
std::is_floating_point_v<N>) &&
|
||||
T == ValueType::LITERAL, bool> = true>
|
||||
T == Type::LITERAL, bool> = true>
|
||||
|
||||
const optional<N> get(StyleRule rule) const {
|
||||
const optional<any> raw = get(rule);
|
||||
const optional<N> get(Prop prop) const {
|
||||
const optional<any> raw = get(prop);
|
||||
if (!raw) return std::nullopt;
|
||||
if (raw->type() == typeid(N)) return any_cast<N>(*raw);
|
||||
// if (raw->type() == typeid(i8)) return static_cast<N>(any_cast<i8>(*raw));
|
||||
// if (raw->type() == typeid(i16)) return static_cast<N>(any_cast<i16>(*raw));
|
||||
// if (raw->type() == typeid(i32)) return static_cast<N>(any_cast<i32>(*raw));
|
||||
// if (raw->type() == typeid(i64)) return static_cast<N>(any_cast<i64>(*raw));
|
||||
// if (raw->type() == typeid(f32)) return static_cast<N>(any_cast<f32>(*raw));
|
||||
// if (raw->type() == typeid(f64)) return static_cast<N>(any_cast<f64>(*raw));
|
||||
// if (raw->type() == typeid(u8)) return static_cast<N>(any_cast<u8>(*raw));
|
||||
// if (raw->type() == typeid(u16)) return static_cast<N>(any_cast<u16>(*raw));
|
||||
// if (raw->type() == typeid(u32)) return static_cast<N>(any_cast<u32>(*raw));
|
||||
// if (raw->type() == typeid(u64)) return static_cast<N>(any_cast<u64>(*raw));
|
||||
// if (raw->type() == typeid(usize)) return static_cast<N>(any_cast<usize>(*raw));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -114,23 +105,18 @@ namespace Gui {
|
|||
* which is interpreted as a vec4 color from several different formats.
|
||||
*/
|
||||
|
||||
template<typename V, ValueType C, std::enable_if_t<
|
||||
template<typename V, Type C, std::enable_if_t<
|
||||
std::is_same_v<V, vec4> &&
|
||||
C == ValueType::COLOR, bool> = true>
|
||||
C == Type::COLOR, bool> = true>
|
||||
|
||||
const optional<V> get(StyleRule rule, optional<V> def = std::nullopt) const {
|
||||
const optional<any> raw = get(rule);
|
||||
const optional<V> get(Prop prop, optional<V> def = std::nullopt) const {
|
||||
const optional<any> 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<vec4>(*raw);
|
||||
try {
|
||||
if (raw->type() == typeid(string)) return Util::hexToColorVec(any_cast<string>(*raw));
|
||||
// if (raw->type() == typeid(const char*)) return Util::hexToColorVec(string(any_cast<const char*>(*raw)));
|
||||
}
|
||||
catch (std::exception) {
|
||||
return std::nullopt;
|
||||
}
|
||||
try { if (raw->type() == typeid(string)) return Util::hexToColorVec(any_cast<string>(*raw)); }
|
||||
catch (std::exception) { return std::nullopt; }
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -139,12 +125,12 @@ namespace Gui {
|
|||
* which is interpreted as a length.
|
||||
*/
|
||||
|
||||
template<typename N, ValueType L, std::enable_if_t<
|
||||
template<typename N, Type L, std::enable_if_t<
|
||||
(std::is_integral_v<N> || std::is_floating_point_v<N>) &&
|
||||
L == ValueType::LENGTH, bool> = true>
|
||||
L == Type::LENGTH, bool> = true>
|
||||
|
||||
optional<N> get(StyleRule rule, const ExpressionInfo& info) const {
|
||||
let raw = get<Gui::Expression>(rule);
|
||||
optional<N> get(Prop prop, const ExpressionInfo& info) const {
|
||||
let raw = get<Gui::Expression>(prop);
|
||||
if (!raw) return std::nullopt;
|
||||
return raw->eval(info);
|
||||
}
|
||||
|
@ -154,13 +140,13 @@ namespace Gui {
|
|||
* which is interpreted as a length.
|
||||
*/
|
||||
|
||||
template<typename VN, ValueType L, std::enable_if_t<
|
||||
template<typename VN, Type L, std::enable_if_t<
|
||||
(std::is_integral_v<typename VN::value_type> || std::is_floating_point_v<typename VN::value_type>) &&
|
||||
std::is_same_v<VN, glm::vec<VN::length(), typename VN::value_type>> &&
|
||||
L == ValueType::LENGTH, bool> = true>
|
||||
L == Type::LENGTH, bool> = true>
|
||||
|
||||
optional<VN> get(StyleRule rule, const ExpressionInfo& info) const {
|
||||
let raw = get<array<Gui::Expression, VN::length()>>(rule);
|
||||
optional<VN> get(Prop prop, const ExpressionInfo& info) const {
|
||||
let raw = get<array<Gui::Expression, VN::length()>>(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<typename V, ValueType T = ValueType::LITERAL>
|
||||
template<typename V, Type T = Type::LITERAL>
|
||||
|
||||
const V get(StyleRule rule, V def) const {
|
||||
const optional<V> raw = get<V, T>(rule);
|
||||
const V get(Prop prop, V def) const {
|
||||
const optional<V> raw = get<V, T>(prop);
|
||||
if (!raw) return def;
|
||||
return *raw;
|
||||
}
|
||||
|
||||
std::unordered_map<StyleRule, any> rules {};
|
||||
std::unordered_map<Prop, any> props {};
|
||||
|
||||
const static std::unordered_map<string, StyleRule> RULE_STRINGS_TO_ENUMS;
|
||||
const static std::unordered_map<string, Prop> PROP_NAMES_TO_ENUM;
|
||||
};
|
||||
|
||||
typedef std::unordered_map<string, Style> StyleSheet;
|
||||
typedef std::unordered_map<string, Props> StyleSheet;
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
#include "client/graph/mesh/EntityMesh.h"
|
||||
|
||||
void Gui::TextElement::updateElement() {
|
||||
const string text = getStyle<string>(StyleRule::CONTENT, "");
|
||||
const string text = getStyle<string>(Prop::CONTENT, "");
|
||||
|
||||
if (!font) font = std::make_unique<Font>(root.atlas, root.atlas["font"]);
|
||||
|
||||
|
@ -15,8 +15,8 @@ void Gui::TextElement::updateElement() {
|
|||
if (hash != newHash) {
|
||||
hash = newHash;
|
||||
|
||||
vec4 textColor = getStyle<vec4, ValueType::COLOR>(StyleRule::TEXT_COLOR, vec4(1));
|
||||
vec4 backgroundColor = getStyle<vec4, ValueType::COLOR>(StyleRule::BACKGROUND, vec4(0));
|
||||
vec4 textColor = getStyle<vec4, Type::COLOR>(Prop::TEXT_COLOR, vec4(1));
|
||||
vec4 backgroundColor = getStyle<vec4, Type::COLOR>(Prop::BACKGROUND, vec4(0));
|
||||
|
||||
u32 ind = 0;
|
||||
u32 width = 0;
|
||||
|
@ -190,8 +190,8 @@ void Gui::TextElement::updateElement() {
|
|||
|
||||
}
|
||||
|
||||
let scale = getStyle<f32, ValueType::LENGTH>(StyleRule::TEXT_SIZE, 3.f);
|
||||
let margin = getStyle<ivec4, ValueType::LENGTH>(StyleRule::MARGIN, {});
|
||||
let scale = getStyle<f32, Type::LENGTH>(Prop::TEXT_SIZE, 3.f);
|
||||
let margin = getStyle<ivec4, Type::LENGTH>(Prop::MARGIN, {});
|
||||
|
||||
entity.setScale(vec3(scale, scale, 0));
|
||||
entity.setPos(vec3(getComputedScreenPos() + ivec2 { margin.x, margin.y }, 0));
|
||||
|
|
|
@ -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<Gui::Element> sandboxRoot) :
|
||||
LuaParser(*client.game),
|
||||
|
@ -152,14 +152,12 @@ void MenuSandbox::showError(const string& err) {
|
|||
|
||||
using Expr = Gui::Expression;
|
||||
sandboxRoot->clear();
|
||||
sandboxRoot->append<Gui::TextElement>({
|
||||
.styles = {{
|
||||
{ Gui::StyleRule::CONTENT, errPrefixText + err },
|
||||
{ Gui::StyleRule::TEXT_SIZE, Expr("2px") },
|
||||
{ Gui::StyleRule::SIZE, array<Expr, 2> { Expr("100dp"), Expr("-1") } },
|
||||
{ Gui::StyleRule::MARGIN, array<Expr, 4> { Expr("4dp"), Expr("4dp"), Expr("4dp"), Expr("4dp") } }
|
||||
}}
|
||||
});
|
||||
sandboxRoot->append<Gui::TextElement>({{
|
||||
{ Gui::Prop::CONTENT, errPrefixText + err },
|
||||
{ Gui::Prop::TEXT_SIZE, Expr("2px") },
|
||||
{ Gui::Prop::SIZE, array<Expr, 2> { Expr("100dp"), Expr("-1") } },
|
||||
{ Gui::Prop::MARGIN, array<Expr, 4> { Expr("4dp"), Expr("4dp"), Expr("4dp"), Expr("4dp") } }
|
||||
}});
|
||||
}
|
||||
|
||||
sol::protected_function_result MenuSandbox::errorCallback(sol::protected_function_result r) {
|
||||
|
|
|
@ -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<Gui::TextElement>({
|
||||
.styles = {{
|
||||
{ Gui::StyleRule::TEXT_SIZE, Expr("2px") },
|
||||
{ Gui::StyleRule::SIZE, array<Expr, 2> { Expr("100dp"), Expr("-1") } },
|
||||
{ Gui::StyleRule::CONTENT, string("`c1Connecting to `b`c0" + addr.toString() + "`r`c1...") },
|
||||
{ Gui::StyleRule::MARGIN, array<Expr, 4> { Expr("4dp"), Expr("4dp"), Expr("4dp"), Expr("4dp") } }
|
||||
}}
|
||||
});
|
||||
status = root.body->append<Gui::TextElement>({{
|
||||
{ Gui::Prop::TEXT_SIZE, Expr("2px") },
|
||||
{ Gui::Prop::SIZE, array<Expr, 2> { Expr("100dp"), Expr("-1") } },
|
||||
{ Gui::Prop::CONTENT, string("`c1Connecting to `b`c0" + addr.toString() + "`r`c1...") },
|
||||
{ Gui::Prop::MARGIN, array<Expr, 4> { 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<string>(Gui::StyleRule::CONTENT, "")
|
||||
+ "Received server properties.\n");
|
||||
status->setProp(Gui::Prop::CONTENT, status->getStyle<string>(Gui::Prop::CONTENT, "")
|
||||
+ "Received server properties.\n");
|
||||
|
||||
const u32 seed = p.d.read<u32>();
|
||||
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<string>(Gui::StyleRule::CONTENT, "")
|
||||
+ "Received block & biome index-identifier table.\nDownloading mods... ");
|
||||
status->setProp(Gui::Prop::CONTENT, status->getStyle<string>(Gui::Prop::CONTENT, "")
|
||||
+
|
||||
"Received block & biome index-identifier table.\nDownloading mods... ");
|
||||
|
||||
client.game->getBiomes().setIdentifiers(p.d.read<vec<string>>());
|
||||
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<string>(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<string>(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<vec<string>>());
|
||||
|
||||
status->setStyle(Gui::StyleRule::CONTENT, status->getStyle<string>(Gui::StyleRule::CONTENT, "")
|
||||
+ ".\n`c7Done`c1 downloading mods. Received the mods order.\nReceiving media");
|
||||
status->setProp(Gui::Prop::CONTENT, status->getStyle<string>(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<string>();
|
||||
status->setStyle(Gui::StyleRule::CONTENT,
|
||||
status->getStyle<string>(Gui::StyleRule::CONTENT, "") + ".");
|
||||
status->setProp(Gui::Prop::CONTENT,
|
||||
status->getStyle<string>(Gui::Prop::CONTENT, "") + ".");
|
||||
|
||||
if (t == AssetType::TEXTURE) {
|
||||
u16 width = p.d.read<u16>();
|
||||
|
@ -152,8 +153,8 @@ void ConnectScene::update() {
|
|||
}
|
||||
}
|
||||
else if (p.type == Packet::Type::MEDIA_DONE) {
|
||||
status->setStyle(Gui::StyleRule::CONTENT, status->getStyle<string>(Gui::StyleRule::CONTENT, "")
|
||||
+ " `c7Done.`c1\nLoading complete. `c0`bJoining world...\n");
|
||||
status->setProp(Gui::Prop::CONTENT, status->getStyle<string>(Gui::Prop::CONTENT, "")
|
||||
+ " `c7Done.`c1\nLoading complete. `c0`bJoining world...\n");
|
||||
|
||||
state = State::DONE;
|
||||
let gameScene = make_unique<GameScene>(client);
|
||||
|
@ -179,8 +180,8 @@ void ConnectScene::handleConnecting() {
|
|||
|
||||
case ServerConnection::State::FAILED_CONNECT:
|
||||
state = State::FAILED_CONNECT;
|
||||
status->setStyle(Gui::StyleRule::CONTENT,
|
||||
status->getStyle<string>(Gui::StyleRule::CONTENT, "") + " `cfFailed to init :(\n");
|
||||
status->setProp(Gui::Prop::CONTENT,
|
||||
status->getStyle<string>(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<string>(Gui::StyleRule::CONTENT, "") + ".");
|
||||
status->setProp(Gui::Prop::CONTENT, status->getStyle<string>(Gui::Prop::CONTENT, "") + ".");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ServerConnection::State::CONNECTED: {
|
||||
state = State::PROPERTIES;
|
||||
status->setStyle(Gui::StyleRule::CONTENT,
|
||||
status->getStyle<string>(Gui::StyleRule::CONTENT, "") + " `c7Connected!~`c1\n");
|
||||
status->setProp(Gui::Prop::CONTENT,
|
||||
status->getStyle<string>(Gui::Prop::CONTENT, "") + " `c7Connected!~`c1\n");
|
||||
|
||||
Packet resp(Packet::Type::SERVER_INFO);
|
||||
resp.sendTo(connection.getPeer(), Packet::Channel::CONNECT);
|
||||
|
|
|
@ -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<Gui::TextElement>({
|
||||
.styles = {{
|
||||
{ Gui::StyleRule::TEXT_SIZE, Expr("2px") },
|
||||
{ Gui::StyleRule::SIZE, array<Expr, 2> { Expr("100dp"), Expr("-1") } },
|
||||
{ Gui::StyleRule::CONTENT, string("`cfEncountered a fatal mod error ;-;\n\n`r") + err },
|
||||
{ Gui::StyleRule::MARGIN, array<Expr, 4> { Expr("4dp"), Expr("4dp"), Expr("4dp"), Expr("4dp") } }
|
||||
}}
|
||||
});
|
||||
root.body->append<Gui::TextElement>({{
|
||||
{ Gui::Prop::TEXT_SIZE, Expr("2px") },
|
||||
{ Gui::Prop::SIZE, array<Expr, 2> { Expr("100dp"), Expr("-1") } },
|
||||
{ Gui::Prop::CONTENT, string("`cfEncountered a fatal mod error ;-;\n\n`r") + err },
|
||||
{ Gui::Prop::MARGIN, array<Expr, 4> { Expr("4dp"), Expr("4dp"), Expr("4dp"), Expr("4dp") } }
|
||||
}});
|
||||
|
||||
root.body->onClick([&](i32 button, bool down) {
|
||||
if (button != GLFW_MOUSE_BUTTON_1 || !down) return;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
MainMenuScene::MainMenuScene(Client& client) : Scene(client),
|
||||
root(client.renderer.window, client.game->textures),
|
||||
sandboxElem(root.create<Gui::BoxElement>({ .classes = { "sandbox" }})),
|
||||
sandboxElem(root.create<Gui::BoxElement>()),
|
||||
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, 2> { Expr(""), Expr("18dp") } }
|
||||
{ Gui::Prop::SIZE, array<Expr, 2> { Expr(""), Expr("18dp") } }
|
||||
}}},
|
||||
{ "navigationWrap", {{
|
||||
{ Gui::StyleRule::DIRECTION, string("row") },
|
||||
{ Gui::StyleRule::POS, array<Expr, 2> { Expr("0"), Expr("0") } }
|
||||
{ Gui::Prop::DIRECTION, string("row") },
|
||||
{ Gui::Prop::POS, array<Expr, 2> { Expr("0"), Expr("0") } }
|
||||
}}},
|
||||
{ "navigationBackground", {{
|
||||
{ Gui::StyleRule::SIZE, array<Expr, 2> { Expr("64dp"), Expr("18dp") } },
|
||||
{ Gui::StyleRule::BACKGROUND, string("menu_bar_bg") }
|
||||
{ Gui::Prop::SIZE, array<Expr, 2> { Expr("64dp"), Expr("18dp") } },
|
||||
{ Gui::Prop::BACKGROUND, string("menu_bar_bg") }
|
||||
}}},
|
||||
{ "navigationButton", {{
|
||||
{ Gui::StyleRule::SIZE, array<Expr, 2> { Expr("16dp"), Expr("16dp") } },
|
||||
{ Gui::StyleRule::CURSOR, string("pointer") }
|
||||
{ Gui::Prop::SIZE, array<Expr, 2> { Expr("16dp"), Expr("16dp") } },
|
||||
{ Gui::Prop::CURSOR, string("pointer") }
|
||||
}}}
|
||||
});
|
||||
|
||||
root.body->append(sandboxElem);
|
||||
let navigation = root.body->append<Gui::BoxElement>({ .classes = { "navigation" } });
|
||||
let navigationBG = navigation->append<Gui::BoxElement>({ .classes = { "navigationWrap" } });
|
||||
let navigation = root.body->append<Gui::BoxElement>({{{ Gui::Prop::CLASS, vec<string> { "navigation" } }}});
|
||||
let navigationBG = navigation->append<Gui::BoxElement>({{{ Gui::Prop::CLASS, vec<string> { "navigationWrap" } }}});
|
||||
|
||||
for (usize i = 0; i < 2000 / Gui::PX_SCALE / 64; i++)
|
||||
navigationBG->append<Gui::BoxElement>({ .classes = { "navigationBackground" } });
|
||||
navigationBG->append<Gui::BoxElement>({{{ Gui::Prop::CLASS, vec<string> { "navigationBackground" } }}});
|
||||
|
||||
let navigationList = navigation->append<Gui::BoxElement>({
|
||||
.classes = { "navigationWrap" },
|
||||
.styles = {{
|
||||
{ Gui::StyleRule::PADDING, array<Expr, 4> { Expr("1dp"), Expr("1dp"), Expr("1dp"), Expr("1dp") } },
|
||||
{ Gui::StyleRule::GAP, array<Expr, 2> { Expr("1dp"), Expr("1dp") } }
|
||||
}}
|
||||
});
|
||||
let navigationList = navigation->append<Gui::BoxElement>({{
|
||||
{ Gui::Prop::CLASS, vec<string> { "navigationWrap" } },
|
||||
{ Gui::Prop::GAP, array<Expr, 2> { Expr("1dp"), Expr("1dp") } },
|
||||
{ Gui::Prop::PADDING, array<Expr, 4> { Expr("1dp"), Expr("1dp"), Expr("1dp"), Expr("1dp") } }
|
||||
}});
|
||||
|
||||
navigationList->append<Gui::BoxElement>({
|
||||
.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::BoxElement>({{
|
||||
{ Gui::Prop::CLASS, vec<string> { "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<Gui::BoxElement>({
|
||||
.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::BoxElement>({{
|
||||
{ Gui::Prop::CLASS, vec<string> { "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<ConnectScene>(client, Address { "127.0.0.1" }));
|
||||
});
|
||||
|
||||
navigationList->append<Gui::BoxElement>({
|
||||
.styles = {{
|
||||
{ Gui::StyleRule::BACKGROUND, string("#fff5") },
|
||||
{ Gui::StyleRule::SIZE, array<Expr, 2> { Expr("1dp"), Expr("10dp") } },
|
||||
{ Gui::StyleRule::MARGIN, array<Expr, 4> { Expr("2dp"), Expr("3dp"), Expr("2dp"), Expr("3dp") } }
|
||||
}}
|
||||
});
|
||||
navigationList->append<Gui::BoxElement>({{
|
||||
{ Gui::Prop::BACKGROUND, string("#fff5") },
|
||||
{ Gui::Prop::SIZE, array<Expr, 2> { Expr("1dp"), Expr("10dp") } },
|
||||
{ Gui::Prop::MARGIN, array<Expr, 4> { 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<Gui::BoxElement>({
|
||||
.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::BoxElement>({{
|
||||
{ Gui::Prop::CLASS, vec<string> { "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<Gui::BoxElement>();
|
||||
|
||||
navigationList->append<Gui::BoxElement>({
|
||||
.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::BoxElement>({{
|
||||
{ Gui::Prop::CLASS, vec<string> { "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<Gui::BoxElement>({
|
||||
.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::BoxElement>({{
|
||||
{ Gui::Prop::CLASS, vec<string> { "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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<f32>()) return Gui::Expression(std::to_string(value.as<f32>()) + "dp");
|
||||
if (value.is<string>()) return Gui::Expression(value.as<string>());
|
||||
throw std::invalid_argument("Object cannot be converted to an expression.");
|
||||
}
|
||||
|
||||
template <usize D>
|
||||
static const array<Gui::Expression, D> parseLengthTableVal(sol::object value) {
|
||||
array<Gui::Expression, D> arr {};
|
||||
|
||||
if (value.is<sol::table>()) {
|
||||
const let& t = value.as<sol::table>();
|
||||
|
||||
vec<Gui::Expression> exprs {};
|
||||
exprs.reserve(t.size());
|
||||
for (usize i = 1; i <= t.size(); i++)
|
||||
exprs.emplace_back(parseObjectToExpr(t.get<sol::object>(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<string>();
|
||||
|
||||
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<string>(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<string>(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<Gui::Element> Api::Usertype::GuiElement::create(const string& type, sol::table data, Gui::Root& root) {
|
||||
Gui::Props props {};
|
||||
|
||||
for (let& style : data) {
|
||||
if (!style.first.is<string>()) continue;
|
||||
let rule = GuiElement::nameToProp(style.first.as<string>());
|
||||
let value = GuiElement::objectToProp(rule, style.second);
|
||||
props.props[rule] = value;
|
||||
}
|
||||
|
||||
sptr<Gui::Element> elem = nullptr;
|
||||
switch (Util::hash(type.data())) {
|
||||
default: throw std::invalid_argument("Invalid element type '" + type + "'.");
|
||||
case Util::hash("Box"): elem = root.create<Gui::BoxElement>(props); break;
|
||||
case Util::hash("Text"): elem = root.create<Gui::TextElement>(props); break;
|
||||
}
|
||||
|
||||
for (usize i = 1; i <= data.size(); i++) {
|
||||
const sol::object& child = data.get<sol::object>(i);
|
||||
if (!child.is<sptr<Gui::Element>>()) continue;
|
||||
elem->append(child.as<sptr<Gui::Element>>());
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
void Api::Usertype::GuiElement::bind(sol::state& lua, sol::table& core, Gui::Root& root) {
|
||||
lua.new_usertype<Gui::Element>("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<sptr<Gui::Element>>()) self.prepend(child.as<sptr<Gui::Element>>());
|
||||
else if (child.is<sol::protected_function>()) {
|
||||
sol::protected_function fn = child.as<sol::protected_function>();
|
||||
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<sol::object>(fn()).as<sptr<Gui::Element>>());
|
||||
}
|
||||
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<sptr<Gui::Element>>()) self.append(child.as<sptr<Gui::Element>>());
|
||||
else if (child.is<sol::protected_function>()) {
|
||||
let fn = child.as<sol::protected_function>();
|
||||
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<sol::object>(fn()).as<sptr<Gui::Element>>());
|
||||
}
|
||||
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<u32>() ? self.get(query.as<u32>() - 1) : self.get(query.as<string>());
|
||||
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<u32>()) {
|
||||
let child = self.get(query.as<u32>());
|
||||
if (child) child->remove();
|
||||
}
|
||||
else if (query.is<std::string>()) {
|
||||
let child = self.get(query.as<std::string>());
|
||||
if (child) child->remove();
|
||||
}
|
||||
else if (query.is<sptr<Gui::Element>>()) {
|
||||
query.as<sptr<Gui::Element>>()->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);
|
||||
}
|
||||
);
|
||||
}
|
|
@ -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<any> 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<Gui::Element> create(const string& type, sol::table data, Gui::Root& root);
|
||||
|
|
@ -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<f32>()) return Gui::Expression(std::to_string(value.as<f32>()) + "dp");
|
||||
if (value.is<string>()) return Gui::Expression(value.as<string>());
|
||||
throw std::invalid_argument("Object cannot be converted to an expression.");
|
||||
}
|
||||
|
||||
template <usize D>
|
||||
static const array<Gui::Expression, D> parseLengthTableVal(sol::object value) {
|
||||
array<Gui::Expression, D> arr {};
|
||||
|
||||
if (value.is<sol::table>()) {
|
||||
const let& t = value.as<sol::table>();
|
||||
|
||||
vec<Gui::Expression> exprs {};
|
||||
exprs.reserve(t.size());
|
||||
for (usize i = 1; i <= t.size(); i++)
|
||||
exprs.emplace_back(parseObjectToExpr(t.get<sol::object>(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<string>();
|
||||
|
||||
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<any> 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<string>(value));
|
||||
|
||||
case StyleRule::POS:
|
||||
case StyleRule::SIZE:
|
||||
case StyleRule::GAP:
|
||||
// return sol::make_object(s, std::any_cast<string>(value));
|
||||
|
||||
case StyleRule::MARGIN:
|
||||
case StyleRule::PADDING:
|
||||
// return parseLengthTableVal<4>(value);
|
||||
|
||||
case StyleRule::TEXT_SIZE:
|
||||
break;
|
||||
// return parseObjectToExpr(value);
|
||||
}
|
||||
}
|
||||
|
||||
sptr<Gui::Element> 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<string>()) continue;
|
||||
let rule = GuiElement::ruleFromStr(style.first.as<string>());
|
||||
let value = GuiElement::parseRuleValue(rule, style.second);
|
||||
props.styles.rules[rule] = value;
|
||||
}
|
||||
|
||||
sptr<Gui::Element> elem = nullptr;
|
||||
switch (Util::hash(type.data())) {
|
||||
default: throw std::invalid_argument("Invalid element type '" + type + "'.");
|
||||
case Util::hash("Box"): elem = root.create<Gui::BoxElement>(props); break;
|
||||
case Util::hash("Text"): elem = root.create<Gui::TextElement>(props); break;
|
||||
}
|
||||
|
||||
for (usize i = 1; i <= data.size(); i++) {
|
||||
const sol::object& child = data.get<sol::object>(i);
|
||||
if (!child.is<sptr<Gui::Element>>()) continue;
|
||||
elem->append(child.as<sptr<Gui::Element>>());
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
void Api::Usertype::GuiElement::bind(sol::state& lua, sol::table& core, Gui::Root& root) {
|
||||
lua.new_usertype<Gui::Element>("GuiElement",
|
||||
sol::meta_function::construct, sol::factories([&](const string& type, sol::table data) {
|
||||
return GuiElement::create(type, data, root);
|
||||
}),
|
||||
"append", [&](Gui::Element& self, sptr<Gui::Element> child) {
|
||||
self.append(child);
|
||||
},
|
||||
"get", [&](sol::this_state s, Gui::Element& self, sol::object query) -> sol::object {
|
||||
if (query.is<u32>()) {
|
||||
let found = self.get(query.as<u32>() - 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<std::string>(s, this->key);
|
||||
// if (key == "type") return sol::make_object<std::string>(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<sol::table>()) callbacks[pair.first.as<std::string>()] = pair.second.as<sol::function>();
|
||||
// }
|
||||
// else if (key == "key") {
|
||||
// this->key = val.as<std::string>();
|
||||
// }
|
||||
// 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<float>() && key.as<float>() <= children.size()) {
|
||||
// auto begin = children.begin();
|
||||
// std::advance(begin, key.as<float>() - 1);
|
||||
// return sol::make_object<std::shared_ptr<LuaGuiElement>>(s, *begin);
|
||||
// }
|
||||
// else if (key.is<std::string>()) {
|
||||
// for (auto& child : children) {
|
||||
// if (child->key == key.as<std::string>()) return sol::make_object<std::shared_ptr<LuaGuiElement>>(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<std::shared_ptr<LuaGuiElement>>()) children.push_back(elem.as<std::shared_ptr<LuaGuiElement>>());
|
||||
// else if (elem.is<sol::protected_function>())
|
||||
// children.push_back(call(s, elem.as<sol::protected_function>()).as<std::shared_ptr<LuaGuiElement>>());
|
||||
// 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<std::shared_ptr<LuaGuiElement>>())
|
||||
// children.insert(children.begin(), elem.as<std::shared_ptr<LuaGuiElement>>());
|
||||
// else if (elem.is<sol::function>())
|
||||
// children.insert(children.begin(), call(s, elem.as<sol::function>()).as<std::shared_ptr<LuaGuiElement>>());
|
||||
// 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<std::string>(s, key));
|
||||
// else throw std::runtime_error("Tried to remove self from nil parent.");
|
||||
// }
|
||||
// else if (elem.is<std::string>()) {
|
||||
// auto child = this->get_child(s, sol::make_object<std::string>(s, elem.as<std::string>()));
|
||||
// if (child) remove(s, child);
|
||||
// }
|
||||
// else if (elem.is<std::shared_ptr<LuaGuiElement>>()) {
|
||||
// auto parent = elem.as<std::shared_ptr<LuaGuiElement>>()->parent;
|
||||
//
|
||||
// for (auto it = parent->children.cbegin(); it != parent->children.cend(); it++) {
|
||||
// if ((*it)->key == elem.as<std::shared_ptr<LuaGuiElement>>()->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<float>()) return Any::from<float>(object.as<float>());
|
||||
//// else if (object.is<bool>()) return Any::from<bool>(object.as<bool>());
|
||||
//// else if (object.is<std::string>()) return Any::from<std::string>(object.as<std::string>());
|
||||
//// else if (object.is<sol::table>()) {
|
||||
//// auto table = object.as<sol::table>();
|
||||
////
|
||||
//// if (table.size() == 2) {
|
||||
//// auto x = table.get<sol::object>(1);
|
||||
//// auto y = table.get<sol::object>(2);
|
||||
////
|
||||
//// glm::vec2 values = {};
|
||||
//// if (x.is<float>()) values.x = x.as<float>();
|
||||
//// else if (x.is<std::string>()) values.x = SerialGui::toDouble(x.as<std::string>());
|
||||
//// if (y.is<float>()) values.y = y.as<float>();
|
||||
//// else if (y.is<std::string>()) values.y = SerialGui::toDouble(y.as<std::string>());
|
||||
////
|
||||
//// return Any::from<glm::vec2>(values);
|
||||
//// }
|
||||
//// else if (table.size() == 4) {
|
||||
//// auto x = table.get<sol::object>(1);
|
||||
//// auto y = table.get<sol::object>(2);
|
||||
//// auto z = table.get<sol::object>(3);
|
||||
//// auto w = table.get<sol::object>(4);
|
||||
////
|
||||
//// glm::vec4 values = {};
|
||||
//// if (x.is<float>()) values.x = x.as<float>();
|
||||
//// else if (x.is<std::string>()) values.x = SerialGui::toDouble(x.as<std::string>());
|
||||
//// if (y.is<float>()) values.y = y.as<float>();
|
||||
//// else if (y.is<std::string>()) values.y = SerialGui::toDouble(y.as<std::string>());
|
||||
//// if (z.is<float>()) values.z = z.as<float>();
|
||||
//// else if (z.is<std::string>()) values.z = SerialGui::toDouble(z.as<std::string>());
|
||||
//// if (w.is<float>()) values.w = w.as<float>();
|
||||
//// else if (w.is<std::string>()) values.w = SerialGui::toDouble(w.as<std::string>());
|
||||
////
|
||||
//// return Any::from<glm::vec4>(values);
|
||||
//// }
|
||||
//// }
|
||||
//
|
||||
// throw std::runtime_error("Invalid type requested in getAsAny");
|
||||
//}
|
|
@ -21,15 +21,15 @@ LocalPlayer::LocalPlayer(SubgamePtr game, LocalWorld& world, DimensionPtr dim, R
|
|||
renderer(renderer) {
|
||||
handItemModel.parent = &handModel;
|
||||
|
||||
hud = root.body->append<Gui::BoxElement>({ .styles {{
|
||||
{ Gui::StyleRule::POS, array<Gui::Expression, 2> { Gui::Expression("0"), Gui::Expression("0") }},
|
||||
{ Gui::StyleRule::SIZE, array<Gui::Expression, 2> { Gui::Expression("100cw"), Gui::Expression("100ch") }}
|
||||
}}});
|
||||
hud = root.body->append<Gui::BoxElement>({{
|
||||
{ Gui::Prop::POS, array<Gui::Expression, 2> { Gui::Expression("0"), Gui::Expression("0") }},
|
||||
{ Gui::Prop::SIZE, array<Gui::Expression, 2> { Gui::Expression("100cw"), Gui::Expression("100ch") }}
|
||||
}});
|
||||
|
||||
menu = root.body->append<Gui::BoxElement>({ .styles {{
|
||||
{ Gui::StyleRule::POS, array<Gui::Expression, 2> { Gui::Expression("0"), Gui::Expression("0") }},
|
||||
{ Gui::StyleRule::SIZE, array<Gui::Expression, 2> { Gui::Expression("100cw"), Gui::Expression("100ch") }}
|
||||
}}});
|
||||
menu = root.body->append<Gui::BoxElement>({{
|
||||
{ Gui::Prop::POS, array<Gui::Expression, 2> { Gui::Expression("0"), Gui::Expression("0") }},
|
||||
{ Gui::Prop::SIZE, array<Gui::Expression, 2> { Gui::Expression("100cw"), Gui::Expression("100ch") }}
|
||||
}});
|
||||
}
|
||||
|
||||
void LocalPlayer::update(f64 delta, vec2 mouseDelta) {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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' })
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
_G['health'] = {}
|
||||
health.internal = {}
|
||||
|
||||
require(_PATH .. 'api')
|
||||
require(_PATH .. 'interface')
|
||||
require(_PATH .. 'hooks')
|
||||
-- _G['health'] = {}
|
||||
-- health.internal = {}
|
||||
--
|
||||
-- require(_PATH .. 'api')
|
||||
-- require(_PATH .. 'interface')
|
||||
-- require(_PATH .. 'hooks')
|
|
@ -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 },
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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"
|
||||
-- }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue