Lua parsing of Gui Elements!!!

master
Auri 2021-08-20 22:48:38 -07:00
parent 22bc36c9f2
commit 5bf82c4963
35 changed files with 663 additions and 498 deletions

View File

@ -5,31 +5,24 @@ setmetatable(env, {__index = _G})
-- create_element
-- Build a GUI Element with the provided constructor data, apply the metatable.
local function create_element(elem_type, data)
local elem = GuiElement.new(elem_type, data)
return elem
return GuiElement.new(elem_type, data)
end
-- register_element
-- Add an element to the Gui namespace.
local function register_element(key)
if type(key) == "table" then
for _,v in pairs(key) do register_element(v) end
for _, v in pairs(key) do register_element(v) end
return
end
env.Gui[key] = function(data) return create_element(key, data) end
end
register_element({"Body", "Rect", "Text", "Model", "Button", "InventoryList"})
-- pc
-- Formats a number to be a percent string.
env.pc = function(num)
return tostring(num) .. "%"
end
register_element({ "Box", "Text" })
-- zepha.build_gui
-- Allows you to Build UI Elements with the GUI namespace outside of a callback.
zepha.build_gui = function(fn)
zepha.gui = function(fn)
setfenv(fn, env)
return fn()
end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

View File

@ -331,6 +331,6 @@ add_library(Zepha_Core
client/gui/compound/GuiCellGraph.cpp
client/gui/compound/GuiCellGraph.h
client/gui/basic/GuiCells.cpp
client/gui/basic/GuiCells.h client/gui/Gui.h client/gui/Root.cpp client/gui/Root.h client/gui/BoxElement.cpp client/gui/BoxElement.h client/gui/Gui.cpp client/gui/Style.h client/gui/TextElement.cpp client/gui/TextElement.h client/gui/Expression.cpp client/gui/Expression.h)
client/gui/basic/GuiCells.h client/gui/Gui.h client/gui/Root.cpp client/gui/Root.h client/gui/BoxElement.cpp client/gui/BoxElement.h client/gui/Gui.cpp client/gui/Style.h client/gui/TextElement.cpp client/gui/TextElement.h client/gui/Expression.cpp client/gui/Expression.h client/gui/Style.cpp)
target_include_directories(Zepha_Core PUBLIC .)

View File

@ -16,9 +16,9 @@ Font::Font(TextureAtlas& atlas, std::shared_ptr<AtlasRef> tex) :
getCharWidths(atlas);
}
unsigned int Font::getCharWidth(char c) {
u16 Font::getCharWidth(char c) {
unsigned int index = static_cast<unsigned int>(c) - 32;
if (index >= amountOfChars) throw std::runtime_error("Invalid char index.");
if (index >= C_COUNT) return charWidths[C_COUNT];
return charWidths[index];
}
@ -27,44 +27,44 @@ void Font::getCharWidths(TextureAtlas& atlas) {
charWidths[0] = 2;
for (unsigned int i = 1; i < amountOfChars; i++) {
glm::vec2 charPos = { i % 18 * charWidth, std::floor(i / 18) * charHeight };
for (u16 i = 1; i < C_COUNT + 1; i++) {
glm::vec2 charPos = { i % 18 * C_WIDTH, std::floor(i / 18) * C_HEIGHT };
unsigned int xBase = static_cast<unsigned int>(fontTex->pos.x) + static_cast<unsigned int>(charPos.x);
unsigned int yBase = static_cast<unsigned int>(fontTex->pos.y) + static_cast<unsigned int>(charPos.y);
u32 xBase = static_cast<u32>(fontTex->pos.x) + static_cast<u32>(charPos.x);
u32 yBase = static_cast<u32>(fontTex->pos.y) + static_cast<u32>(charPos.y);
unsigned short width = 0;
u16 width = 0;
for (unsigned int j = 0; j < charWidth; j++) {
for (u16 j = 0; j < C_WIDTH; j++) {
bool empty = true;
for (unsigned int k = 0; k < charHeight; k++) {
unsigned int xx = xBase + j;
unsigned int yy = yBase + k;
for (u16 k = 0; k < C_HEIGHT; k++) {
u32 xx = xBase + j;
u32 yy = yBase + k;
unsigned int offset = yy * static_cast<unsigned int>(atlasSize.x) * 4 + xx * 4 + 3;
u32 offset = yy * static_cast<u32>(atlasSize.x) * 4 + xx * 4 + 3;
if (data[offset] != 0) {
empty = false;
break;
}
}
if (!empty) width = static_cast<unsigned short>(j);
if (!empty) width = static_cast<u16>(j);
}
charWidths[i] = width;
}
}
glm::vec4 Font::getCharUVs(char c) {
unsigned int index = static_cast<unsigned int>(c) - 32;
if (index >= amountOfChars) throw std::runtime_error("Invalid char index.");
vec4 Font::getCharUVs(char c) {
u16 index = static_cast<u16>(c) - 32;
if (index >= C_COUNT) index = C_COUNT;
glm::vec2 charPos = { (index % 18) * charWidth, std::floor(index / 18) * charHeight };
glm::vec4 uv = {
vec2 charPos = { (index % 18) * C_WIDTH, std::floor(index / 18) * C_HEIGHT };
vec4 uv = {
fontTex->uv.x + (charPos.x) / atlasSize.x,
fontTex->uv.y + (charPos.y) / atlasSize.y,
fontTex->uv.x + (charPos.x + getCharWidth(c) + 1) / atlasSize.x,
fontTex->uv.y + (charPos.y + charHeight) / atlasSize.y
fontTex->uv.y + (charPos.y + C_HEIGHT) / atlasSize.y
};
return uv;

View File

@ -1,35 +1,29 @@
//
// Created by aurailus on 13/08/19.
//
#pragma once
#include <memory>
#include <glm/vec2.hpp>
#include <glm/vec4.hpp>
#include "util/Types.h"
class AtlasRef;
class TextureAtlas;
class Font {
public:
public:
Font() = default;
Font(TextureAtlas& atlas, std::shared_ptr<AtlasRef> tex);
unsigned int getCharWidth(char c);
u16 getCharWidth(char c);
glm::vec4 getCharUVs(char c);
vec4 getCharUVs(char c);
const static unsigned int amountOfChars = 95;
const static unsigned int charWidth = 7;
const static unsigned int charHeight = 9;
private:
constexpr static u16 C_COUNT = 95;
constexpr static u16 C_WIDTH = 7;
constexpr static u16 C_HEIGHT = 9;
private:
void getCharWidths(TextureAtlas& atlas);
glm::vec2 atlasSize{};
vec2 atlasSize {};
std::shared_ptr<AtlasRef> fontTex = nullptr;
std::array<unsigned short, 95> charWidths{};
sptr<AtlasRef> fontTex = nullptr;
array<u16, C_COUNT + 1> charWidths {};
};

View File

@ -24,6 +24,10 @@ ivec2 Gui::Element::getComputedSize() {
return size;
}
void Gui::Element::clear() {
children.clear();
}
ivec2 Gui::Element::getComputedOuterSize() {
let size = getComputedSize();
let margin = getStyle<ivec4, ValueType::LENGTH>(StyleRule::MARGIN, {});
@ -195,4 +199,4 @@ void Gui::Element::layoutChildren() {
break;
}
}
}
}

View File

@ -79,6 +79,8 @@ namespace Gui {
return elem;
}
void clear();
/** Returns the element's computed size. */
virtual ivec2 getComputedSize();
@ -104,6 +106,7 @@ namespace Gui {
for (const let& ss : stylesheets) {
for (const string& className : props.classes) {
const let& styles = ss.find(className);
if (styles == ss.end()) continue;
const optional<any> opt = styles->second.get(rule);
if (opt) return *opt;
}
@ -119,6 +122,7 @@ namespace Gui {
for (const let& ss : stylesheets) {
for (const string& className : props.classes) {
const let& styles = ss.find(className);
if (styles == ss.end()) continue;
const optional<V> opt = styles->second.get<V, T>(rule);
if (opt) return *opt;
}

View File

@ -1,3 +1,5 @@
#pragma once
#include <unordered_map>
#include "client/gui/Gui.h"

20
src/client/gui/Style.cpp Normal file
View File

@ -0,0 +1,20 @@
#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 }
};

View File

@ -22,7 +22,9 @@ namespace Gui {
BACKGROUND,
BACKGROUND_HOVER,
CONTENT
CONTENT,
TEXT_SIZE,
TEXT_COLOR
};
enum class ValueType {
@ -180,6 +182,8 @@ namespace Gui {
}
std::unordered_map<StyleRule, any> rules {};
const static std::unordered_map<string, StyleRule> RULE_STRINGS_TO_ENUMS;
};
typedef std::unordered_map<string, Style> StyleSheet;

View File

@ -36,7 +36,7 @@ void Gui::TextElement::updateElement() {
}
vec3 offset = {};
u32 h = Font::charHeight;
u32 h = Font::C_HEIGHT;
bool bold = false;
bool italic = false;
@ -192,9 +192,12 @@ void Gui::TextElement::updateElement() {
}
entity.setScale(PX_SCALE * (2/3.f));
// entity.setScale(vec3(getComputedSize() * static_cast<i32>(PX_SCALE), 0));
entity.setPos(vec3(getComputedScreenPos() * static_cast<i32>(PX_SCALE), 0));
let scale = getStyle<f32, ValueType::LENGTH>(StyleRule::TEXT_SIZE, 3.f);
let margin = getStyle<ivec4, ValueType::LENGTH>(StyleRule::MARGIN, {});
entity.setScale(vec3(scale, scale, 0));
entity.setPos(vec3(getComputedScreenPos() + ivec2 { margin.x, margin.y }, 0));
Element::updateElement();
}

View File

@ -1,7 +1,7 @@
#include <fstream>
#include <iostream>
#include <cute_files/cute_files.h>
#include <client/gui/TextElement.h>
#include "MenuSandbox.h"
@ -9,29 +9,25 @@
#include "client/Client.h"
#include "lua/ErrorFormatter.h"
#include "client/menu/SubgameDef.h"
#include "client/gui/basic/GuiText.h"
#include "client/gui/basic/GuiContainer.h"
// Modules
#include "lua/modules/Time.h"
#include "lua/modules/mSetGui.h"
#include "lua/modules/mStartGame.h"
#include "lua/usertype/LuaGuiElement.h"
MenuSandbox::MenuSandbox(glm::ivec2& win, Client& client, std::shared_ptr<GuiContainer> container) :
MenuSandbox::MenuSandbox(Client& client, Gui::Root& root, sptr<Gui::Element> sandboxRoot) :
LuaParser(*client.game),
win(win),
client(client)
// container(container),
// luaContainer(std::dynamic_pointer_cast<GuiContainer>(container->add(std::make_shared<GuiContainer>("__lua"))))
// builder(client.game->textures, client.game->models, luaContainer) {}
{}
client(client),
root(root),
sandboxRoot(sandboxRoot) {}
void MenuSandbox::reset() {
// container->remove("error");
// builder.clear(true);
sandboxRoot->clear();
core = {};
mod = {};
lua = sol::state{};
lua = sol::state {};
lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::math, sol::lib::table, sol::lib::debug);
loadApi();
@ -46,9 +42,10 @@ void MenuSandbox::loadApi() {
modules.emplace_back(std::make_unique<Api::Module::Time>(Api::State::CLIENT, lua, core));
Api::Usertype::GuiElement::bind(lua, core, root);
// ClientApi::gui_element(lua);
// MenuApi::set_gui(builder, win, lua, core);
MenuApi::set_gui(lua, core, sandboxRoot);
MenuApi::start_game(client, core);
bindModules();
@ -60,14 +57,15 @@ void MenuSandbox::loadApi() {
void MenuSandbox::load(const SubgameDef& subgame) {
reset();
subgameName = subgame.config.name;
try {
loadAndRunMod(subgame.subgamePath + "/../../assets/base");
loadAndRunMod(subgame.subgamePath + "/menu");
}
catch (const std::runtime_error& e) {
showError(e.what(), subgame.config.name);
}
// try {
loadAndRunMod(subgame.subgamePath + "/../../assets/base");
loadAndRunMod(subgame.subgamePath + "/menu");
// }
// catch (const std::runtime_error& e) {
// showError(e.what(), subgame.config.name);
// }
}
void MenuSandbox::windowResized() {
@ -79,7 +77,7 @@ void MenuSandbox::update(double delta) {
core["__builtin"]["update_delayed_functions"]();
}
sol::protected_function_result MenuSandbox::runFileSandboxed(const std::string& file) {
sol::protected_function_result MenuSandbox::runFileSandboxed(const string& file) {
for (LuaMod::File& f : mod.files) {
if (f.path != file) continue;
@ -94,18 +92,18 @@ sol::protected_function_result MenuSandbox::runFileSandboxed(const std::string&
throw std::runtime_error("Error opening '" + file + "', file not found.");
}
void MenuSandbox::loadAndRunMod(const std::string& modPath) {
void MenuSandbox::loadAndRunMod(const string& modPath) {
if (!cf_file_exists(modPath.data())) throw std::runtime_error("Directory not found.");
LuaMod mod;
std::string root = modPath + "/script";
string root = modPath + "/script";
std::list<std::string> dirsToScan{ root };
std::list<std::string> luaFiles{};
std::list<string> dirsToScan{ root };
std::list<string> luaFiles{};
cf_dir_t dir;
while (!dirsToScan.empty()) {
std::string dirStr = *dirsToScan.begin();
string dirStr = *dirsToScan.begin();
dirsToScan.erase(dirsToScan.begin());
if (!cf_file_exists(dirStr.data())) throw std::runtime_error("Missing 'script' directory.");
@ -131,9 +129,9 @@ void MenuSandbox::loadAndRunMod(const std::string& modPath) {
mod.modPath = modPath;
for (std::string& file : luaFiles) {
for (string& file : luaFiles) {
size_t rootPos = file.find(root);
std::string modPath = file;
string modPath = file;
if (rootPos == std::string::npos)
throw std::runtime_error("Attempted to access file \"" + file + "\", which is outside of the mod root.");
@ -142,66 +140,67 @@ void MenuSandbox::loadAndRunMod(const std::string& modPath) {
modPath.resize(modPath.size() - 4);
std::ifstream t(file);
std::string fileStr((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
string fileStr((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
LuaMod::File f{ modPath, fileStr };
LuaMod::File f { modPath, fileStr };
mod.files.push_back(f);
}
std::string texPath = modPath + "/textures";
if (cf_file_exists(texPath.data())) {
this->modAssets = client.game->textures.loadDirectory(texPath, false, true);
}
string texPath = modPath + "/textures";
if (cf_file_exists(texPath.data()))
menuAssets = client.game->textures.loadDirectory(texPath, false, true);
this->mod = mod;
runFileSandboxed("init");
}
void MenuSandbox::showError(const std::string& what, const std::string& subgame) {
const std::string errPrefixText = "Encountered an error while loading the menu for " + subgame + " ;-;";
// Font f(client.game->textures, client.game->textures["font"]);
// auto errWrap = std::make_shared<GuiContainer>("error");
// container->add(errWrap);
// auto errPrefix = std::make_shared<GuiText>("error_text");
// errPrefix->create({ 3, 3 }, {}, { 0.7, 0, 0.3, 1 }, { 1, 1, 1, 1 }, f);
// errPrefix->setText(errPrefixText);
// errPrefix->setPos({ 8, 16 });
// errWrap->add(errPrefix);
// auto errMsg = std::make_shared<GuiText>("error_text");
// errMsg->create({ 3, 3 }, {}, {}, { 1, 0.5, 0.6, 1 }, f);
// errMsg->setText(what);
// errMsg->setPos({ 8, 52 });
// errWrap->add(errMsg);
void MenuSandbox::showError(const string& err) {
const string errPrefixText = "`cfEncountered an error while loading the menu for '" + subgameName + "' ;-;\n\n`r";
using Expr = Gui::Expression;
sandboxRoot->append<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") } }
}}
});
}
sol::protected_function_result MenuSandbox::errorCallback(sol::protected_function_result r) const {
sol::error err = r;
std::string errString = err.what();
sol::protected_function_result MenuSandbox::errorCallback(sol::protected_function_result r) {
string err = static_cast<sol::error>(r).what();
try {
std::string::size_type lineNumStart = errString.find(':');
if (lineNumStart == std::string::npos) throw std::out_of_range("Improperly formatted error. [0]");
std::string::size_type lineNumEnd = errString.find(':', lineNumStart + 1);
if (lineNumEnd == std::string::npos) throw std::out_of_range("Improperly formatted error. [1]");
std::string fileName = errString.substr(0, lineNumStart);
int lineNum = std::stoi(errString.substr(lineNumStart + 1, lineNumEnd - lineNumStart - 1));
for (const LuaMod::File& file : mod.files)
if (file.path == fileName)
throw std::runtime_error(ErrorFormatter::formatError(fileName, lineNum, errString, file.file));
throw std::out_of_range("Error thrown outside of handled files. [2]");
std::cout << Log::err << err << Log::endl;
vec<string> lines;
{
string line;
std::stringstream textStream(err);
while (std::getline(textStream, line, '\n')) lines.emplace_back(line);
}
catch (const std::runtime_error& e) {
std::cout << Log::err << e.what() << std::endl;
throw;
}
catch (const std::out_of_range& e) {
std::cout << Log::err << "Failed to format error, " << e.what() << Log::endl;
throw std::runtime_error(errString);
for (const let& line : lines) {
usize lineNumStart = line.find(':');
if (lineNumStart == string::npos) continue;
usize lineNumEnd = line.find(':', lineNumStart + 1);
if (lineNumEnd == string::npos) continue;
string fileName = line.substr(0, lineNumStart);
fileName.erase(std::remove_if(fileName.begin(), fileName.end(), isspace), fileName.end());
for (const let& file : mod.files) {
if (file.path == fileName) {
let msg = ErrorFormatter::formatError(fileName,
std::stoi(line.substr(lineNumStart + 1, lineNumEnd - lineNumStart - 1)),
err, file.file);
showError(msg);
return r;
}
}
}
showError(err);
return r;
}

View File

@ -7,6 +7,8 @@
#include "lua/LuaParser.h"
#include "lua/LuaMod.h"
#include "client/gui/Root.h"
#include "client/gui/Element.h"
#include "client/gui/GuiBuilder.h"
class Client;
@ -16,8 +18,8 @@ class SubgameDef;
class GuiContainer;
class MenuSandbox : LuaParser {
public:
MenuSandbox(glm::ivec2& window, Client& client, std::shared_ptr<GuiContainer> container);
public:
MenuSandbox(Client& client, Gui::Root& root, sptr<Gui::Element> sandboxRoot);
void load(const SubgameDef& subgame);
@ -26,28 +28,27 @@ class MenuSandbox : LuaParser {
void windowResized();
using LuaParser::update;
private:
private:
void reset();
void loadApi();
void loadAndRunMod(const std::string& modPath);
void loadAndRunMod(const string& modPath);
void showError(const std::string& what, const std::string& subgame);
void showError(const string& err);
sol::protected_function_result runFileSandboxed(const std::string& file);
sol::protected_function_result runFileSandboxed(const string& file);
virtual sol::protected_function_result errorCallback(sol::protected_function_result r) const override;
virtual sol::protected_function_result errorCallback(sol::protected_function_result r) override;
LuaMod mod {};
std::vector<std::shared_ptr<AtlasRef>> modAssets{};
// GuiRoot gui;
// std::shared_ptr<GuiContainer> container = nullptr;
// std::shared_ptr<GuiContainer> luaContainer = nullptr;
// GuiBuilder builder;
string subgameName;
Client& client;
glm::ivec2& win;
Gui::Root& root;
sptr<Gui::Element> sandboxRoot;
vec<sptr<AtlasRef>> menuAssets {};
};

View File

@ -17,36 +17,34 @@
#include "client/gui/compound/GuiImageButton.h"
MainMenuScene::MainMenuScene(Client& client) : Scene(client),
root(client.renderer.window, client.game->textures) {
root(client.renderer.window, client.game->textures),
sandboxElem(root.create<Gui::BoxElement>({ .classes = { "sandbox" }})),
sandbox(client, root, sandboxElem) {
client.renderer.setClearColor(0, 0, 0);
client.renderer.window.input.setMouseLocked(false);
root.body->setStyle(Gui::StyleRule::BACKGROUND, string("#123"));
using Expr = Gui::Expression;
root.addStylesheet({
{ "sandbox", {{
{ Gui::StyleRule::H_ALIGN, string("center") },
{ Gui::StyleRule::V_ALIGN, string("center") }
}}},
{ "navigation", {{
{ Gui::StyleRule::SIZE, array<Gui::Expression, 2> { Gui::Expression("-1"), Gui::Expression("18dp") } }
{ Gui::StyleRule::SIZE, array<Expr, 2> { Expr("-1"), Expr("18dp") } }
}}},
{ "navigationWrap", {{
{ Gui::StyleRule::DIRECTION, string("row") },
{ Gui::StyleRule::POS, array<Gui::Expression, 2> { Gui::Expression("0"), Gui::Expression("0") } }
{ Gui::StyleRule::POS, array<Expr, 2> { Expr("0"), Expr("0") } }
}}},
{ "navigationBackground", {{
{ Gui::StyleRule::SIZE, array<Gui::Expression, 2> { Gui::Expression("64dp"), Gui::Expression("18dp") } },
{ Gui::StyleRule::SIZE, array<Expr, 2> { Expr("64dp"), Expr("18dp") } },
{ Gui::StyleRule::BACKGROUND, string("menu_bar_bg") }
}}},
{ "navigationButton", {{
{ Gui::StyleRule::SIZE, array<Gui::Expression, 2> { Gui::Expression("16dp"), Gui::Expression("16dp") } },
{ Gui::StyleRule::SIZE, array<Expr, 2> { Expr("16dp"), Expr("16dp") } },
{ Gui::StyleRule::CURSOR, string("pointer") }
}}}
});
let sandbox = root.body->append<Gui::BoxElement>({ .classes = { "sandbox" } });
root.body->append(sandboxElem);
let navigation = root.body->append<Gui::BoxElement>({ .classes = { "navigation" } });
let navigationBG = navigation->append<Gui::BoxElement>({ .classes = { "navigationWrap" } });
@ -56,9 +54,8 @@ MainMenuScene::MainMenuScene(Client& client) : Scene(client),
let navigationList = navigation->append<Gui::BoxElement>({
.classes = { "navigationWrap" },
.styles = {{
{ Gui::StyleRule::PADDING, array<Gui::Expression, 4>
{ Gui::Expression("1dp"), Gui::Expression("1dp"), Gui::Expression("1dp"), Gui::Expression("1dp") } },
{ Gui::StyleRule::GAP, array<Gui::Expression, 2> { Gui::Expression("1dp"), Gui::Expression("1dp") } }
{ Gui::StyleRule::PADDING, array<Expr, 4> { Expr("1dp"), Expr("1dp"), Expr("1dp"), Expr("1dp") } },
{ Gui::StyleRule::GAP, array<Expr, 2> { Expr("1dp"), Expr("1dp") } }
}}
});
@ -81,9 +78,8 @@ MainMenuScene::MainMenuScene(Client& client) : Scene(client),
navigationList->append<Gui::BoxElement>({
.styles = {{
{ Gui::StyleRule::BACKGROUND, string("#fff5") },
{ Gui::StyleRule::SIZE, array<Gui::Expression, 2> { Gui::Expression("1dp"), Gui::Expression("10dp") } },
{ Gui::StyleRule::MARGIN, array<Gui::Expression, 4>
{ Gui::Expression("2dp"), Gui::Expression("3dp"), Gui::Expression("2dp"), Gui::Expression("3dp") } }
{ Gui::StyleRule::SIZE, array<Expr, 2> { Expr("1dp"), Expr("10dp") } },
{ Gui::StyleRule::MARGIN, array<Expr, 4> { Expr("2dp"), Expr("3dp"), Expr("2dp"), Expr("3dp") } }
}}
});
@ -108,7 +104,7 @@ MainMenuScene::MainMenuScene(Client& client) : Scene(client),
if (subgames.size() > 0) {
selectedSubgame = &subgames[0];
// sandbox.load(*selectedSubgame);
sandbox.load(*selectedSubgame);
}
navigationList->append<Gui::BoxElement>();

View File

@ -28,11 +28,16 @@ private:
/** Find valid subgames in the subgames folder. */
void findSubgames();
/** The GUI root. */
Gui::Root root;
/** The GUI sandbox element root. */
sptr<Gui::Element> sandboxElem;
/** Provides the API for menu mods. */
// MenuSandbox sandbox;
Gui::Root root;
MenuSandbox sandbox;
/** A list of found subgames. */
vec<SubgameDef> subgames;

View File

@ -4,23 +4,25 @@
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>
#include "ErrorFormatter.h"
#include "../util/Log.h"
std::string
ErrorFormatter::formatError(const string& fileName, usize line, const string& stack, string file,
bool ansiColors) noexcept {
const string red = (ansiColors ? Log::red : "");
const string unbl = (ansiColors ? Log::unbl : "");
const string endl = (ansiColors ? Log::endl : "\n");
std::string ErrorFormatter::formatError(const string& fileName, usize line,
const string& stack, string file, bool ansiColors) noexcept {
const string RED = "`cf";
const string LTGRAY = "`c1";
const string GRAY = "`c2";
const string BOLD = "`b";
const string UNDL = "`u";
const string ENDL = "`r\n";
std::stringstream out{};
std::stringstream out {};
// Split the file into lines, and add them to a vector
vec<string> fileLines{};
out << BOLD << UNDL << fileName << ".lua" << ENDL << "\n";
vec<string> fileLines {};
usize pos = 0;
string token;
@ -33,14 +35,28 @@ ErrorFormatter::formatError(const string& fileName, usize line, const string& st
while (fileLines.back() == "") fileLines.pop_back();
// Format and add lines to the stringstream
for (usize i = (std::max)(static_cast<usize>(0), line - 6); i < (std::min)(fileLines.size(), line + 5); i++) {
for (usize j = 0; j < 3 - std::to_string(i + 1).length(); j++) out << " ";
out << red << (i + 1 == line ? unbl : "") << (i + 1) << (i + 1 == line ? " # " : " | ") << fileLines[i] << endl;
usize printStart = (std::max)(0, static_cast<i32>(line - LOOK_AROUND - 1));
usize printEnd = (std::min)(fileLines.size(), line + LOOK_AROUND);
if (printStart != 0) {
for (usize j = 0; j < 3 - std::to_string(printStart).length(); j++) out << " ` ` ";
out << GRAY << printStart << " | -- snip --" << ENDL;
}
// Add the stack trace at the bottom
out << endl << red << stack << endl;
for (i32 i = printStart; i < printEnd; i++) {
for (usize j = 0; j < 3 - std::to_string(i + 1).length(); j++) out << " ` ` ";
out << (i + 1 == line ? RED : LTGRAY) << (i + 1)
<< (i + 1 == line ? "" : "`cr")
<< " | " << (i + 1 == line ? BOLD : "")
<< fileLines[i] << ENDL;
}
if (printEnd != fileLines.size()) {
for (usize j = 0; j < 3 - std::to_string(printEnd + 1).length(); j++) out << " ` ` ";
out << GRAY << (printEnd + 1) << " | -- snip --" << ENDL;
}
out << "\n" << BOLD << UNDL << "Traceback" << ENDL << "\n" << RED << stack << ENDL;
return out.str();
}

View File

@ -10,4 +10,6 @@ class ErrorFormatter {
public:
static string formatError(const string& fileName, usize line,
const string& stack, string file, bool ansiColors = true) noexcept;
constexpr static i32 LOOK_AROUND = 4;
};

View File

@ -62,7 +62,7 @@ void LocalLuaParser::loadApi(WorldPtr world, PlayerPtr player) {
core["__builtin"] = lua.create_table();
// Types
ClientApi::gui_element(lua);
// ClientApi::gui_element(lua);
Api::Usertype::Target::bind(Api::State::CLIENT, lua, core);
Api::Usertype::Entity::bind(Api::State::CLIENT, lua, core);
@ -116,7 +116,7 @@ void LocalLuaParser::loadApi(WorldPtr world, PlayerPtr player) {
lua.set_function("runfile", &LocalLuaParser::runFileSandboxed, this);
}
sol::protected_function_result LocalLuaParser::errorCallback(sol::protected_function_result r) const {
sol::protected_function_result LocalLuaParser::errorCallback(sol::protected_function_result r) {
sol::error err = r;
std::string errString = err.what();

View File

@ -28,7 +28,7 @@ class LocalLuaParser : public LuaParser {
private:
void loadApi(WorldPtr world, PlayerPtr player);
virtual sol::protected_function_result errorCallback(sol::protected_function_result r) const override;
virtual sol::protected_function_result errorCallback(sol::protected_function_result r) override;
sol::protected_function_result runFileSandboxed(const std::string& file);

View File

@ -26,5 +26,5 @@ class LuaKeybindHandler {
std::array<std::vector<sol::protected_function>, 1024> callbacksDown{};
std::array<std::vector<sol::protected_function>, 1024> callbacksUp{};
const LocalLuaParser* parser;
LocalLuaParser* parser;
};

View File

@ -26,13 +26,13 @@ class LuaParser {
void bindModules();
template<typename... Args>
sol::protected_function_result safe_function(sol::protected_function f, Args... args) const {
sol::protected_function_result safe_function(sol::protected_function f, Args... args) {
auto res = f(args...);
if (!res.valid()) errorCallback(res);
return res;
}
virtual sol::protected_function_result errorCallback(sol::protected_function_result r) const = 0;
virtual sol::protected_function_result errorCallback(sol::protected_function_result r) = 0;
Subgame& game;

View File

@ -145,7 +145,7 @@ void ServerLuaParser::loadApi(WorldPtr world) {
lua.set_function("runfile", &ServerLuaParser::runFileSandboxed, this);
}
sol::protected_function_result ServerLuaParser::errorCallback(sol::protected_function_result r) const {
sol::protected_function_result ServerLuaParser::errorCallback(sol::protected_function_result r) {
sol::error err = r;
std::string errString = err.what();

View File

@ -33,7 +33,7 @@ public:
private:
void loadApi(WorldPtr world);
virtual sol::protected_function_result errorCallback(sol::protected_function_result r) const override;
virtual sol::protected_function_result errorCallback(sol::protected_function_result r) override;
sol::protected_function_result runFileSandboxed(const std::string& file);

View File

@ -1,7 +1,3 @@
//
// Created by aurailus on 2019-12-12.
//
#pragma once
#include "lua/Lua.h"
@ -10,10 +6,10 @@
class LuaGuiElement;
namespace MenuApi {
// void set_gui(GuiBuilder& builder, glm::ivec2& win, sol::state& lua, sol::table& core) {
// core.set_function("set_gui", [&](std::shared_ptr<LuaGuiElement> gui) {
// builder.setGuiRoot(gui);
// builder.build(win);
// });
// }
void set_gui(sol::state& lua, sol::table& core, sptr<Gui::Element>& root) {
core.set_function("set_gui", [&](sptr<Gui::Element> elem) {
root->clear();
root->append(elem);
});
}
}

View File

@ -12,12 +12,11 @@
#include "../../util/CovariantPtr.h"
class Subgame;
class ItemStack;
namespace Api::Usertype {
class ItemStack : SubgameUsertype {
public:
public:
ItemStack() = default;
explicit ItemStack(sol::table tbl);
@ -38,7 +37,7 @@ namespace Api::Usertype {
static void bind(State state, sol::state& lua, sol::table& core);
private:
private:
std::string name;
unsigned short count;
};

View File

@ -1,180 +1,297 @@
//
// Created by aurailus on 2020-04-12.
//
#include <iostream>
#include <glm/vec2.hpp>
#include "LuaGuiElement.h"
#include "client/gui/SerialGui.h"
#include "client/gui/Gui.h"
#include "client/gui/Root.h"
#include "client/gui/Element.h"
#include "client/gui/BoxElement.h"
#include "client/gui/TextElement.h"
std::shared_ptr<LuaGuiElement> LuaGuiElement::create(const std::string& type, sol::table data) {
auto elem = std::make_shared<LuaGuiElement>();
elem->type = type;
static const Gui::Expression parseObjectToExpr(sol::object value) {
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 {};
for (const auto& pair : data) {
if (pair.first.is<float>()) {
if (!pair.second.is<std::shared_ptr<LuaGuiElement>>()) continue;
elem->children.push_back(pair.second.as<std::shared_ptr<LuaGuiElement>>());
elem->children.back()->parent = elem.get();
}
else if (pair.first.is<std::string>()) elem->set_trait(pair.first.as<std::string>(), pair.second);
if (value.is<sol::table>()) {
const let& t = value.as<sol::table>();
vec<Gui::Expression> exprs {};
exprs.reserve(t.size());
for (let& v : t) exprs.emplace_back(parseObjectToExpr(v.second));
for (usize i = 0; i < arr.size() / exprs.size(); i++)
for (usize j = 0; j < exprs.size(); j++)
arr[j + i * exprs.size()] = exprs[j];
return arr;
}
let v = parseObjectToExpr(value);
for (usize i = 0; i < arr.size(); i++) arr[i] = v;
return arr;
throw std::invalid_argument("Invalid length table configuration.");
}
void Api::Usertype::GuiElement::parseRule(const string& ruleStr, const sol::object& value, Gui::Style& styles) {
using namespace Gui;
const let ruleIt = Style::RULE_STRINGS_TO_ENUMS.find(ruleStr);
if (ruleIt == Style::RULE_STRINGS_TO_ENUMS.end())
throw std::invalid_argument("Style rule '" + ruleStr + "' doesn't exist.");
const StyleRule rule = ruleIt->second;
switch (rule) {
default:
throw std::invalid_argument("Unhandled rule '" + ruleStr + "'! This is an engine error!");
case StyleRule::LAYOUT:
case StyleRule::DIRECTION:
case StyleRule::H_ALIGN:
case StyleRule::V_ALIGN:
case StyleRule::CURSOR:
case StyleRule::OVERFLOW:
case StyleRule::TEXT_COLOR:
case StyleRule::BACKGROUND:
case StyleRule::BACKGROUND_HOVER:
case StyleRule::CONTENT:
styles.rules[rule] = value.as<string>();
break;
case StyleRule::POS:
case StyleRule::SIZE:
case StyleRule::GAP:
styles.rules[rule] = parseLengthTableVal<2>(value);
break;
case StyleRule::MARGIN:
case StyleRule::PADDING:
styles.rules[rule] = parseLengthTableVal<4>(value);
break;
case StyleRule::TEXT_SIZE:
styles.rules[rule] = parseObjectToExpr(value);
break;
}
}
std::shared_ptr<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;
GuiElement::parseRule(style.first.as<string>(), style.second, props.styles);
}
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;
}
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);
// let elem = root.create<Gui::BoxElement>(props);
// return elem;
// auto elem = std::make_shared<LuaGuiElement>();
//
// 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>();
// elem->type = type;
//
// 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);
// for (const auto& pair : data) {
// if (pair.first.is<float>()) {
// if (!pair.second.is<std::shared_ptr<LuaGuiElement>>()) continue;
// elem->children.push_back(pair.second.as<std::shared_ptr<LuaGuiElement>>());
// elem->children.back()->parent = elem.get();
// }
// 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);
// else if (pair.first.is<std::string>()) elem->set_trait(pair.first.as<std::string>(), pair.second);
// }
//
// 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 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);
})
);
}
//
// return Any::from<glm::vec4>(values);
//// sol::meta_function::index, &LuaGuiElement::get_trait,
//// sol::meta_function::new_index, &LuaGuiElement::set_trait,
//
//// sol::meta_function::call, &LuaGuiElement::call,
//
//// "get", &LuaGuiElement::get_child,
//// "append", &LuaGuiElement::append,
//// "prepend", &LuaGuiElement::prepend,
//// "remove", &LuaGuiElement::remove,
//// "clear", &LuaGuiElement::clear
//
//sol::object LuaGuiElement::get_trait(sol::this_state s, const std::string& key) {
// if (key == "key") return sol::make_object<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;
// }
// }
throw std::runtime_error("Invalid type requested in getAsAny");
}
//
// 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");
//}

View File

@ -1,84 +1,97 @@
//
// Created by aurailus on 2020-04-12.
//
#pragma once
#include <list>
#include "lua/Lua.h"
#include "../Lua.h"
#include "../../util/Any.h"
#include "util/Types.h"
//#include "BaseUsertype.h"
//#include "../../util/CovariantPtr.h"
class LuaGuiElement {
public:
LuaGuiElement() = default;
//class Subgame;
//class ItemStack;
namespace Gui {
class Style;
class Root;
class Element;
}
namespace Api::Usertype::GuiElement {
void parseRule(const string& ruleStr, const sol::object& value, Gui::Style& styles);
// Lua Functions and Properties
static std::shared_ptr<LuaGuiElement> create(const std::string& type, sol::table data);
sol::object get_trait(sol::this_state s, const std::string& key);
sol::object set_trait(const std::string& key, sol::object val);
std::shared_ptr<Gui::Element> create(const string& type, sol::table data, Gui::Root& root);
sol::object call(sol::this_state s, sol::protected_function fun);
sol::object get_child(sol::this_state s, sol::object key);
void append(sol::this_state s, sol::object elem);
void prepend(sol::this_state s, sol::object elem);
void remove(sol::this_state s, sol::object elem);
void clear(sol::this_state s);
std::string type{}, key{};
LuaGuiElement* parent = nullptr;
std::list<std::shared_ptr<LuaGuiElement>> children{};
std::unordered_map<std::string, sol::function> callbacks{};
std::unordered_map<std::string, sol::object> traits{};
// C++ Functions and Properties
Any getAsAny(const std::string& key) const;
template<typename T>
const T& get(const std::string& key) const {
return getAsAny(key).get<T>();
}
template<typename T>
const T& get_or(const std::string& key, const T& other) const noexcept {
Any a = getAsAny(key);
if (a.empty() || !a.is<T>()) return other;
return a.get<T>();
}
template<typename T>
const bool has(const std::string& key) const noexcept {
Any a = getAsAny(key);
return !a.empty() && a.is<T>();
}
std::function<void()> updateFunction = nullptr;
};
namespace ClientApi {
static void gui_element(sol::state& lua) {
lua.new_usertype<LuaGuiElement>("GuiElement",
sol::meta_function::construct, sol::factories(&LuaGuiElement::create),
sol::meta_function::index, &LuaGuiElement::get_trait,
sol::meta_function::new_index, &LuaGuiElement::set_trait,
sol::meta_function::call, &LuaGuiElement::call,
"get", &LuaGuiElement::get_child,
"append", &LuaGuiElement::append,
"prepend", &LuaGuiElement::prepend,
"remove", &LuaGuiElement::remove,
"clear", &LuaGuiElement::clear
);
}
void bind(sol::state& lua, sol::table& core, Gui::Root& root);
}
//class LuaGuiElement {
// public:
// LuaGuiElement() = default;
//
// // Lua Functions and Properties
//
// sol::object get_trait(sol::this_state s, const std::string& key);
//
// sol::object set_trait(const std::string& key, sol::object val);
//
//
// sol::object get_child(sol::this_state s, sol::object key);
//
// void append(sol::this_state s, sol::object elem);
//
// void prepend(sol::this_state s, sol::object elem);
//
// void remove(sol::this_state s, sol::object elem);
//
// void clear(sol::this_state s);
//
// std::string type{}, key{};
//
// LuaGuiElement* parent = nullptr;
// std::list<std::shared_ptr<LuaGuiElement>> children{};
//
// std::unordered_map<std::string, sol::function> callbacks{};
// std::unordered_map<std::string, sol::object> traits{};
//
// // C++ Functions and Properties
// Any getAsAny(const std::string& key) const;
//
// template<typename T>
// const T& get(const std::string& key) const {
// return getAsAny(key).get<T>();
// }
//
// template<typename T>
// const T& get_or(const std::string& key, const T& other) const noexcept {
// Any a = getAsAny(key);
// if (a.empty() || !a.is<T>()) return other;
// return a.get<T>();
// }
//
// template<typename T>
// const bool has(const std::string& key) const noexcept {
// Any a = getAsAny(key);
// return !a.empty() && a.is<T>();
// }
//
// std::function<void()> updateFunction = nullptr;
//};
//
//namespace ClientApi {
// static void gui_element(sol::state& lua) {
// lua.new_usertype<Gui::Element>("GuiElement",
// sol::meta_function::construct, sol::factories(&LuaGuiElement::create),
//
// sol::meta_function::index, &LuaGuiElement::get_trait,
// sol::meta_function::new_index, &LuaGuiElement::set_trait,
//
// sol::meta_function::call, &LuaGuiElement::call,
//
// "get", &LuaGuiElement::get_child,
// "append", &LuaGuiElement::append,
// "prepend", &LuaGuiElement::prepend,
// "remove", &LuaGuiElement::remove,
// "clear", &LuaGuiElement::clear
// );
// }
//}

View File

@ -8,7 +8,6 @@
#include "ItemStack.h"
#include "InventoryList.h"
#include "LuaGuiElement.h"
#include "world/LocalWorld.h"
#include "world/ServerWorld.h"
#include "world/inv/Inventory.h"
@ -168,21 +167,25 @@ bool Api::Usertype::LocalPlayer::is_in_menu() {
return player.l()->isInMenu();
}
void Api::Usertype::LocalPlayer::show_menu(std::shared_ptr<LuaGuiElement> root) {
return player.l()->showMenu(root);
}
//void Api::Usertype::LocalPlayer::show_menu(std::shared_ptr<LuaGuiElement> root) {
//// return player.l()->showMenu(root);
// return;
//}
void Api::Usertype::LocalPlayer::close_menu() {
return player.l()->closeMenu();
// return player.l()->closeMenu();
return;
}
std::shared_ptr<LuaGuiElement> Api::Usertype::LocalPlayer::get_hud() {
return player.l()->getHud();
}
//std::shared_ptr<LuaGuiElement> Api::Usertype::LocalPlayer::get_hud() {
//// return player.l()->getHud();
// return nullptr;
//}
void Api::Usertype::LocalPlayer::set_hud(std::shared_ptr<LuaGuiElement> hud) {
player.l()->setHud(hud);
}
//void Api::Usertype::LocalPlayer::set_hud(std::shared_ptr<LuaGuiElement> hud) {
//// player.l()->setHud(hud);
// return;
//}
void Api::Usertype::LocalPlayer::bind(State, sol::state& lua, sol::table& core) {
lua.new_usertype<LocalPlayer>("Player",
@ -209,10 +212,10 @@ void Api::Usertype::LocalPlayer::bind(State, sol::state& lua, sol::table& core)
"get_dimension", &LocalPlayer::get_dimension,
"show_menu", &LocalPlayer::show_menu,
// "show_menu", &LocalPlayer::show_menu,
"close_menu", &LocalPlayer::close_menu,
"set_hud", &LocalPlayer::set_hud,
"get_hud", &LocalPlayer::get_hud,
// "set_hud", &LocalPlayer::set_hud,
// "get_hud", &LocalPlayer::get_hud,
"pos", sol::property(&LocalPlayer::get_pos, &LocalPlayer::set_pos),
"block_pos", sol::property(&LocalPlayer::get_block_pos, &LocalPlayer::set_pos),

View File

@ -12,7 +12,7 @@
#include "Dimension.h"
#include "world/player/LocalPlayer.h"
class LuaGuiElement;
//class LuaGuiElement;
namespace Api::Usertype {
class ServerPlayer;
@ -82,13 +82,13 @@ public:
bool is_in_menu();
void show_menu(std::shared_ptr<LuaGuiElement> root);
// void show_menu(std::shared_ptr<LuaGuiElement> root);
void close_menu();
std::shared_ptr<LuaGuiElement> get_hud();
// std::shared_ptr<LuaGuiElement> get_hud();
void set_hud(std::shared_ptr<LuaGuiElement> hud);
// void set_hud(std::shared_ptr<LuaGuiElement> hud);
static void bind(State state, sol::state& lua, sol::table& core);
};

View File

@ -100,23 +100,23 @@ bool LocalPlayer::isInMenu() {
// return gameGui.isInMenu();
}
void LocalPlayer::showMenu(sptr<LuaGuiElement> root) {
// gameGui.showMenu(root);
renderer.window.input.setMouseLocked(false);
}
//void LocalPlayer::showMenu(sptr<LuaGuiElement> root) {
//// gameGui.showMenu(root);
// renderer.window.input.setMouseLocked(false);
//}
void LocalPlayer::closeMenu() {
// gameGui.closeMenu();
renderer.window.input.setMouseLocked(true);
}
sptr<LuaGuiElement> LocalPlayer::getHud() {
// return gameGui.getHud();
}
//sptr<LuaGuiElement> LocalPlayer::getHud() {
//// return gameGui.getHud();
//}
void LocalPlayer::setHud(sptr<LuaGuiElement> hud) {
// gameGui.setHud(hud);
}
//void LocalPlayer::setHud(sptr<LuaGuiElement> hud) {
//// gameGui.setHud(hud);
//}
void LocalPlayer::setHudVisible(bool hudVisible) {
// gameGui.setVisible(hudVisible);

View File

@ -11,7 +11,6 @@
class Input;
class Deserializer;
class LuaGuiElement;
class LocalInventory;
class LocalInventoryRefs;
enum class NetPlayerField;
@ -89,7 +88,7 @@ public:
* @param root - The root GUI element to display.
*/
void showMenu(sptr<LuaGuiElement> root);
// void showMenu(sptr<LuaGuiElement> root);
/**
* Closes the currently open menu.
@ -102,7 +101,7 @@ public:
* @returns the root GUI element of the hud.
*/
sptr<LuaGuiElement> getHud();
// sptr<LuaGuiElement> getHud();
/**
* Sets the HUD to the specified GUI tree. The hud does not constitute
@ -111,7 +110,7 @@ public:
* @param hud - The root GUI element to display.
*/
void setHud(sptr<LuaGuiElement> hud);
// void setHud(sptr<LuaGuiElement> hud);
/**
* Sets the visibility state of the HUD.

View File

@ -1,7 +0,0 @@
{
"name": "minimal",
"display_name": "Minimal Subgame",
"author": "@aurailus",
"description": "Minimal subgame for development.",
"version": "0.0.1"
}

View File

@ -1,31 +1,31 @@
local gui = zepha.build_gui(function()
return Gui.Body {
-- background = "#214a21",
zepha.set_gui(zepha.gui(function()
return Gui.Box {
background = "#334",
Gui.Text {
position = { 4, 4 },
pos = { 4, 4 },
text_size = "2px",
content = "Minimalminimalmmnal"
},
Gui.Rect {
position = { 64, 64 },
Gui.Box {
pos = { 64, 64 },
size = { 128 * (16/9), 128 },
background = "zeus_background"
},
Gui.Rect {
position = { 64 + 128, 64 + 64 },
Gui.Box {
pos = { 64 + 128, 64 + 64 },
size = { 128 * (16/9), 128 },
background = "zeus_background",
Gui.Text {
pos = 4,
text_size = "4px",
content = "What's the fuck it'd going on?"
}
}
}
end)
zepha.set_gui(gui)
end))

View File

@ -1,9 +1,11 @@
zepha.set_gui(zepha.build_gui(function()
return Gui.Body {
zepha.set_gui(zepha.gui(function()
return Gui.Box {
background = "#124778",
h_align = "center",
v_align = "center",
Gui.Text {
position = { 4, 4 },
size = { 64, 4 },
content = "Parentheses"
}
}