UI Elements with Live manipulation & garbage collection 🦀
parent
fdd5ae307f
commit
af78490c7e
|
@ -1,5 +1,6 @@
|
||||||
# Default ignored files
|
# Default ignored files
|
||||||
/workspace.xml
|
/workspace.xml
|
||||||
|
/shelf/
|
||||||
|
|
||||||
# Datasource local storage ignored files
|
# Datasource local storage ignored files
|
||||||
/dataSources.local.xml
|
/dataSources.local.xml
|
|
@ -13,8 +13,8 @@
|
||||||
GuiBuilder::GuiBuilder(TextureAtlas& textures, ModelStore& models, std::shared_ptr<GuiContainer> root) :
|
GuiBuilder::GuiBuilder(TextureAtlas& textures, ModelStore& models, std::shared_ptr<GuiContainer> root) :
|
||||||
textures(textures), models(models), root(root) {}
|
textures(textures), models(models), root(root) {}
|
||||||
|
|
||||||
void GuiBuilder::setGuiRoot(LuaGuiElement& menu) {
|
void GuiBuilder::setGuiRoot(std::shared_ptr<LuaGuiElement> menu) {
|
||||||
elements = &menu;
|
elements = menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiBuilder::build(glm::ivec2 winBounds) {
|
void GuiBuilder::build(glm::ivec2 winBounds) {
|
||||||
|
@ -34,17 +34,12 @@ void GuiBuilder::create(LuaGuiElement& element, std::shared_ptr<GuiComponent> pa
|
||||||
if (!component) throw std::runtime_error("GuiBuilder failed to create component: " + element.key);
|
if (!component) throw std::runtime_error("GuiBuilder failed to create component: " + element.key);
|
||||||
parent->add(component);
|
parent->add(component);
|
||||||
|
|
||||||
for (auto& child : element.children) create(child, component, component->getScale());
|
for (auto& child : element.children) create(*child, component, component->getScale());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<GuiComponent> GuiBuilder::createComponent(LuaGuiElement& elem, glm::ivec2 bounds) {
|
std::shared_ptr<GuiComponent> GuiBuilder::createComponent(LuaGuiElement& elem, glm::ivec2 bounds) {
|
||||||
std::shared_ptr<GuiComponent> c = nullptr;
|
std::shared_ptr<GuiComponent> c = nullptr;
|
||||||
|
|
||||||
if (elem.key == "wee") {
|
|
||||||
auto a = elem.getAsAny("position");
|
|
||||||
std::cout << a.get<glm::vec2>().x << ", " << a.get<glm::vec2>().y << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (Util::hash(elem.type.c_str())) {
|
switch (Util::hash(elem.type.c_str())) {
|
||||||
default: break;
|
default: break;
|
||||||
case Util::hash("Body"): {
|
case Util::hash("Body"): {
|
||||||
|
@ -92,7 +87,6 @@ void GuiBuilder::clearCallbacks(std::shared_ptr<GuiComponent> component) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiBuilder::elementUpdated() {
|
void GuiBuilder::elementUpdated() {
|
||||||
std::cout << "rebuilding ui " << std::endl;
|
|
||||||
build();
|
build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ public:
|
||||||
struct ComponentCallbacks { GuiComponent::callback left {}, right {}, hover {}; };
|
struct ComponentCallbacks { GuiComponent::callback left {}, right {}, hover {}; };
|
||||||
|
|
||||||
GuiBuilder(TextureAtlas& textures, ModelStore& models, std::shared_ptr<GuiContainer> root);
|
GuiBuilder(TextureAtlas& textures, ModelStore& models, std::shared_ptr<GuiContainer> root);
|
||||||
void setGuiRoot(LuaGuiElement& menu);
|
void setGuiRoot(std::shared_ptr<LuaGuiElement> menu);
|
||||||
void build(glm::ivec2 winBounds = {});
|
void build(glm::ivec2 winBounds = {});
|
||||||
void clear(bool deleteRoot = true);
|
void clear(bool deleteRoot = true);
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ protected:
|
||||||
|
|
||||||
std::shared_ptr<GuiContainer> root = nullptr;
|
std::shared_ptr<GuiContainer> root = nullptr;
|
||||||
|
|
||||||
LuaGuiElement* elements = nullptr;
|
std::shared_ptr<LuaGuiElement> elements = nullptr;
|
||||||
unsigned int keyInd = 0;
|
unsigned int keyInd = 0;
|
||||||
|
|
||||||
glm::ivec2 winBounds {};
|
glm::ivec2 winBounds {};
|
||||||
|
|
|
@ -8,16 +8,31 @@
|
||||||
|
|
||||||
#include "../../../game/hud/SerialGui.h"
|
#include "../../../game/hud/SerialGui.h"
|
||||||
|
|
||||||
LuaGuiElement::LuaGuiElement(const std::string& type, sol::table data) :
|
//LuaGuiElement::LuaGuiElement(const std::string& type, sol::table data) :
|
||||||
type(type) {
|
// type(type) {
|
||||||
|
//
|
||||||
|
// for (const auto& pair : data) {
|
||||||
|
// if (pair.first.is<float>()) {
|
||||||
|
// if (!pair.second.is<std::shared_ptr<LuaGuiElement>>()) throw std::runtime_error("Child is not a GuiElement.");
|
||||||
|
// children.push_back(pair.second.as<std::shared_ptr<LuaGuiElement>>());
|
||||||
|
// }
|
||||||
|
// else if (pair.first.is<std::string>()) set_trait(pair.first.as<std::string>(), pair.second);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
std::shared_ptr<LuaGuiElement> LuaGuiElement::create(const std::string& type, sol::table data) {
|
||||||
|
auto elem = std::make_shared<LuaGuiElement>();
|
||||||
|
elem->type = type;
|
||||||
|
|
||||||
for (const auto& pair : data) {
|
for (const auto& pair : data) {
|
||||||
if (pair.first.is<float>()) {
|
if (pair.first.is<float>()) {
|
||||||
if (!pair.second.is<LuaGuiElement>()) throw std::runtime_error("Child is not a GuiElement.");
|
if (!pair.second.is<std::shared_ptr<LuaGuiElement>>()) throw std::runtime_error("Child is not a GuiElement.");
|
||||||
children.push_back(pair.second.as<LuaGuiElement>());
|
elem->children.push_back(pair.second.as<std::shared_ptr<LuaGuiElement>>());
|
||||||
}
|
}
|
||||||
else if (pair.first.is<std::string>()) set_trait(pair.first.as<std::string>(), pair.second);
|
else if (pair.first.is<std::string>()) elem->set_trait(pair.first.as<std::string>(), pair.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
sol::object LuaGuiElement::get_trait(sol::this_state s, const std::string& key) {
|
sol::object LuaGuiElement::get_trait(sol::this_state s, const std::string& key) {
|
||||||
|
@ -37,15 +52,8 @@ sol::object LuaGuiElement::set_trait(const std::string& key, sol::object val) {
|
||||||
this->key = val.as<std::string>();
|
this->key = val.as<std::string>();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (val.is<sol::table>()) {
|
|
||||||
std::cout << key << "t: " << val.as<sol::table>().get<float>(1) << ", " << val.as<sol::table>().get<float>(2) << std::endl;
|
|
||||||
}
|
|
||||||
traits.erase(key);
|
traits.erase(key);
|
||||||
traits.emplace(key, val);
|
traits.emplace(key, val);
|
||||||
if (val.is<sol::table>()) {
|
|
||||||
sol::table v = traits.at(key).as<sol::table>();
|
|
||||||
std::cout << key << "tv: " << v.get<float>(1) << ", " << v.get<float>(2) << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateFunction) updateFunction();
|
if (updateFunction) updateFunction();
|
||||||
|
@ -60,34 +68,42 @@ sol::object LuaGuiElement::call(sol::this_state s, sol::function fun) {
|
||||||
return fun(this);
|
return fun(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
sol::object LuaGuiElement::find(sol::this_state s, const std::string& key) {
|
sol::object LuaGuiElement::get_child(sol::this_state s, sol::object key) {
|
||||||
for (auto& child : children) {
|
if (key.is<float>() && key.as<float>() <= children.size()) {
|
||||||
if (child.key == key) return sol::make_object<LuaGuiElement>(s, child);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& child : children) {
|
|
||||||
auto recurse = child.find(s, key);
|
|
||||||
if (recurse) return recurse;
|
|
||||||
}
|
|
||||||
return sol::nil;
|
return sol::nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaGuiElement::append(sol::this_state s, sol::object elem) {
|
void LuaGuiElement::append(sol::this_state s, sol::object elem) {
|
||||||
if (elem.is<LuaGuiElement>()) children.push_back(elem.as<LuaGuiElement>());
|
if (elem.is<LuaGuiElement>()) children.push_back(elem.as<std::shared_ptr<LuaGuiElement>>());
|
||||||
else if (elem.is<sol::function>()) children.push_back(call(s, elem.as<sol::function>()).as<LuaGuiElement>());
|
else if (elem.is<sol::function>()) children.push_back(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.");
|
else throw std::runtime_error("Append arg is not an element or a function to generate one.");
|
||||||
|
|
||||||
if (updateFunction) updateFunction();
|
if (updateFunction) updateFunction();
|
||||||
children.back().updateFunction = updateFunction;
|
children.back()->updateFunction = updateFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaGuiElement::prepend(sol::this_state s, sol::object elem) {
|
void LuaGuiElement::prepend(sol::this_state s, sol::object elem) {
|
||||||
if (elem.is<LuaGuiElement>()) children.insert(children.begin(), elem.as<LuaGuiElement>());
|
if (elem.is<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<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.");
|
else throw std::runtime_error("Append arg is not an element or a function to generate one.");
|
||||||
|
|
||||||
if (updateFunction) updateFunction();
|
if (updateFunction) updateFunction();
|
||||||
children.front().updateFunction = updateFunction;
|
children.front()->updateFunction = updateFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaGuiElement::remove(sol::optional<LuaGuiElement> elem) {
|
void LuaGuiElement::remove(sol::optional<LuaGuiElement> elem) {
|
||||||
|
@ -97,7 +113,7 @@ void LuaGuiElement::remove(sol::optional<LuaGuiElement> elem) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (const auto it = children.cbegin(); it != children.cend();) {
|
for (const auto it = children.cbegin(); it != children.cend();) {
|
||||||
if (it->key == elem->key) {
|
if ((*it)->key == elem->key) {
|
||||||
children.erase(it);
|
children.erase(it);
|
||||||
if (updateFunction) updateFunction();
|
if (updateFunction) updateFunction();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -11,14 +11,16 @@
|
||||||
|
|
||||||
class LuaGuiElement {
|
class LuaGuiElement {
|
||||||
public:
|
public:
|
||||||
LuaGuiElement(const std::string& type, sol::table data);
|
LuaGuiElement() = default;
|
||||||
|
|
||||||
// Lua Functions and Properties
|
// 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 get_trait(sol::this_state s, const std::string& key);
|
||||||
sol::object set_trait(const std::string& key, sol::object val);
|
sol::object set_trait(const std::string& key, sol::object val);
|
||||||
|
|
||||||
sol::object call(sol::this_state s, sol::function fun);
|
sol::object call(sol::this_state s, sol::function fun);
|
||||||
sol::object find(sol::this_state s, const std::string& key);
|
sol::object get_child(sol::this_state s, sol::object key);
|
||||||
|
|
||||||
void append(sol::this_state s, sol::object elem);
|
void append(sol::this_state s, sol::object elem);
|
||||||
void prepend(sol::this_state s, sol::object elem);
|
void prepend(sol::this_state s, sol::object elem);
|
||||||
|
@ -27,7 +29,7 @@ public:
|
||||||
std::string type {}, key {};
|
std::string type {}, key {};
|
||||||
|
|
||||||
LuaGuiElement* parent = nullptr;
|
LuaGuiElement* parent = nullptr;
|
||||||
std::list<LuaGuiElement> children {};
|
std::list<std::shared_ptr<LuaGuiElement>> children {};
|
||||||
|
|
||||||
std::unordered_map<std::string, sol::function> callbacks {};
|
std::unordered_map<std::string, sol::function> callbacks {};
|
||||||
std::unordered_map<std::string, sol::object> traits {};
|
std::unordered_map<std::string, sol::object> traits {};
|
||||||
|
@ -54,14 +56,14 @@ public:
|
||||||
namespace ClientApi {
|
namespace ClientApi {
|
||||||
static void gui_element(sol::state& lua) {
|
static void gui_element(sol::state& lua) {
|
||||||
lua.new_usertype<LuaGuiElement>("GuiElement",
|
lua.new_usertype<LuaGuiElement>("GuiElement",
|
||||||
sol::constructors<LuaGuiElement(std::string, sol::object)>(),
|
sol::meta_function::construct, sol::factories(&LuaGuiElement::create),
|
||||||
|
|
||||||
sol::meta_function::index, &LuaGuiElement::get_trait,
|
sol::meta_function::index, &LuaGuiElement::get_trait,
|
||||||
sol::meta_function::new_index, &LuaGuiElement::set_trait,
|
sol::meta_function::new_index, &LuaGuiElement::set_trait,
|
||||||
|
|
||||||
sol::meta_function::call, &LuaGuiElement::call,
|
sol::meta_function::call, &LuaGuiElement::call,
|
||||||
|
|
||||||
"find", &LuaGuiElement::find,
|
"get", &LuaGuiElement::get_child,
|
||||||
"append", &LuaGuiElement::append,
|
"append", &LuaGuiElement::append,
|
||||||
"prepend", &LuaGuiElement::prepend,
|
"prepend", &LuaGuiElement::prepend,
|
||||||
"remove", &LuaGuiElement::remove
|
"remove", &LuaGuiElement::remove
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
namespace MenuApi {
|
namespace MenuApi {
|
||||||
void set_gui(GuiBuilder& builder, glm::ivec2& win, sol::state& lua, sol::table& core) {
|
void set_gui(GuiBuilder& builder, glm::ivec2& win, sol::state& lua, sol::table& core) {
|
||||||
core.set_function("set_gui", [&](LuaGuiElement& gui) {
|
core.set_function("set_gui", [&](std::shared_ptr<LuaGuiElement> gui) {
|
||||||
builder.setGuiRoot(gui);
|
builder.setGuiRoot(gui);
|
||||||
builder.build(win);
|
builder.build(win);
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,7 +5,7 @@ local gui = zepha.build_gui(function()
|
||||||
|
|
||||||
Gui.Text {
|
Gui.Text {
|
||||||
position = { 4, 4 },
|
position = { 4, 4 },
|
||||||
content = "Minimal Subgame"
|
content = "Minimalminimalmmnal"
|
||||||
},
|
},
|
||||||
|
|
||||||
Gui.Rect {
|
Gui.Rect {
|
||||||
|
@ -22,25 +22,10 @@ local gui = zepha.build_gui(function()
|
||||||
background = "zeus_background",
|
background = "zeus_background",
|
||||||
|
|
||||||
Gui.Text {
|
Gui.Text {
|
||||||
content = "What's the fuck is going on?"
|
content = "What's the fuck it'd going on?"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
Gui.Rect {
|
|
||||||
position = { 0, 0 },
|
|
||||||
size = { 32, 32 },
|
|
||||||
background = "#f00",
|
|
||||||
key = "wee"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
zepha.set_gui(gui)
|
zepha.set_gui(gui)
|
||||||
|
|
||||||
local menu = gui:find("wee")
|
|
||||||
|
|
||||||
zepha.delay(function()
|
|
||||||
print("updating position")
|
|
||||||
menu.position = {menu.position[1] + 16, menu.position[2] + 16}
|
|
||||||
return true
|
|
||||||
end, 1)
|
|
Binary file not shown.
After Width: | Height: | Size: 597 B |
Loading…
Reference in New Issue