From 7e64879f7875d4496708a4124f2d093c06c8a9b1 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Wed, 23 Jul 2025 13:30:42 -0400 Subject: [PATCH 1/6] Forgot to set the position on rectangle so just added the center helper. --- src/guecs/sfml/components.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/guecs/sfml/components.cpp b/src/guecs/sfml/components.cpp index 6dbb221..e52097f 100644 --- a/src/guecs/sfml/components.cpp +++ b/src/guecs/sfml/components.cpp @@ -97,6 +97,8 @@ namespace guecs { shape->setFillColor(color); shape->setOutlineColor(border_color); shape->setOutlineThickness(border_px); + + sfml_center_helper(shape, cell, padding); } void Rectangle::render(sf::RenderWindow& window, sf::Shader *shader_ptr) { From 4c019048d0c5232d23b174873acbba833512cf82 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Wed, 23 Jul 2025 13:49:16 -0400 Subject: [PATCH 2/6] Making Icons a thing again since it's convenient. --- demos/clicker_game.cpp | 2 +- include/guecs/sfml/components.hpp | 14 ++++++++++++++ include/guecs/ui.hpp | 1 + src/guecs/ui.cpp | 19 +++++++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/demos/clicker_game.cpp b/demos/clicker_game.cpp index 17ffbb1..c76080a 100644 --- a/demos/clicker_game.cpp +++ b/demos/clicker_game.cpp @@ -92,7 +92,7 @@ struct ClickerUI { auto id = $gui.entity(name); if(name != "clicker") { $gui.set(id, {}); - $gui.set(id, { "clicker_treat_bone" }); + $gui.set(id, { "clicker_treat_bone" }); $gui.set(id, { [&](auto, auto) { handle_button(Event::A_BUTTON); } }); diff --git a/include/guecs/sfml/components.hpp b/include/guecs/sfml/components.hpp index dc82033..74d12bc 100644 --- a/include/guecs/sfml/components.hpp +++ b/include/guecs/sfml/components.hpp @@ -36,6 +36,20 @@ namespace guecs { void render(sf::RenderWindow& window, sf::Shader *shader_ptr); }; + struct Icon : public Sprite { + template + Icon(Args... args) : Sprite(args...) + { + stretch = false; + is_icon = true; + } + + Icon() { + stretch = false; + is_icon = true; + }; + }; + struct Rectangle { int padding = THEME.PADDING; sf::Color color = THEME.FILL_COLOR; diff --git a/include/guecs/ui.hpp b/include/guecs/ui.hpp index d66b063..1b309b5 100644 --- a/include/guecs/ui.hpp +++ b/include/guecs/ui.hpp @@ -218,6 +218,7 @@ namespace guecs { sf::Shader* find_shader(Entity ent, bool is_shape); void show_sprite(const string& region, const string& sprite_name); + void show_icon(const string& region, const string& sprite_name); void show_text(const string& region, const wstring& content); void show_label(const string& region, const wstring& content); }; diff --git a/src/guecs/ui.cpp b/src/guecs/ui.cpp index 5e8d498..396a277 100644 --- a/src/guecs/ui.cpp +++ b/src/guecs/ui.cpp @@ -89,6 +89,10 @@ namespace guecs { query([&](auto, auto &cell, auto &sprite) { sprite.init(cell); }); + + query([&](auto, auto &cell, auto &icon) { + icon.init(cell); + }); } void UI::debug_layout(sf::RenderWindow& window) { @@ -134,6 +138,11 @@ namespace guecs { sprite.render(window, shader_ptr); }); + query([&](auto ent, auto& icon) { + auto shader_ptr = find_shader(ent, false); + icon.render(window, shader_ptr); + }); + query([&](auto ent, auto& text) { auto shader_ptr = find_shader(ent, false); text.render(window, shader_ptr); @@ -188,6 +197,16 @@ namespace guecs { } } + void UI::show_icon(const string& region, const string& sprite_name) { + auto ent = entity(region); + + if(auto sprite = get_if(ent)) { + sprite->update(sprite_name); + } else { + set_init(ent, {sprite_name}); + } + } + void UI::show_text(const string& region, const wstring& content) { auto ent = entity(region); From 5d0d8b16fc0716bdf96a96238c98a18559e97696 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Thu, 14 Aug 2025 12:35:25 -0400 Subject: [PATCH 3/6] Removed hover on guecs::UI::mouse and now use a generic 16 bit modifier bitset. Also finally fixed Clickable so it just a simple callback with only the modifiers. --- demos/calc.cpp | 8 ++++---- demos/clicker_game.cpp | 8 ++++---- include/guecs/ui.hpp | 21 ++++++++++++--------- meson.build | 2 +- src/guecs/ui.cpp | 31 ++++++++----------------------- 5 files changed, 29 insertions(+), 41 deletions(-) diff --git a/demos/calc.cpp b/demos/calc.cpp index c96ffea..8f38517 100644 --- a/demos/calc.cpp +++ b/demos/calc.cpp @@ -169,8 +169,8 @@ struct CalculatorUI { $gui.set(id, { label }); wchar_t op = label[0]; $gui.set(id, { - [&, op](auto, auto) { handle_button(op); } - }); + [&, op](auto) { handle_button(op); } + }); } } @@ -182,8 +182,8 @@ struct CalculatorUI { // $gui.debug_layout(window); } - void mouse(float x, float y, bool hover) { - $gui.mouse(x, y, hover); + void mouse(float x, float y, guecs::Modifiers mods) { + $gui.mouse(x, y, mods); } void handle_button(wchar_t op) { diff --git a/demos/clicker_game.cpp b/demos/clicker_game.cpp index c76080a..c5e68b6 100644 --- a/demos/clicker_game.cpp +++ b/demos/clicker_game.cpp @@ -94,7 +94,7 @@ struct ClickerUI { $gui.set(id, {}); $gui.set(id, { "clicker_treat_bone" }); $gui.set(id, { - [&](auto, auto) { handle_button(Event::A_BUTTON); } + [&](auto) { handle_button(Event::A_BUTTON); } }); } } @@ -103,7 +103,7 @@ struct ClickerUI { $gui.set($clicker, {"clicker_the_dog"}); $gui.set($clicker, {"clicker_bark"}); $gui.set($clicker, { - [&](auto, auto) { handle_button(Event::CLICKER); } + [&](auto) { handle_button(Event::CLICKER); } }); // custom components need to be initialized manually @@ -126,8 +126,8 @@ struct ClickerUI { // $gui.debug_layout(window); } - void mouse(float x, float y, bool hover) { - $gui.mouse(x, y, hover); + void mouse(float x, float y, guecs::Modifiers mods) { + $gui.mouse(x, y, mods); } void handle_button(Event ev) { diff --git a/include/guecs/ui.hpp b/include/guecs/ui.hpp index 1b309b5..2d30731 100644 --- a/include/guecs/ui.hpp +++ b/include/guecs/ui.hpp @@ -10,6 +10,7 @@ #include "guecs/theme.hpp" #include "guecs/sfml/components.hpp" #include +#include namespace guecs { using std::shared_ptr, std::wstring, std::string; @@ -24,22 +25,25 @@ namespace guecs { std::queue free_indices; }; + enum class ModBit { + hover=0, + left=1, + right=2 + }; + + using Modifiers = std::bitset<16>; + struct Clickable { /* This is actually called by UI::mouse and passed the entity ID of the * button pressed so you can interact with it in the event handler. */ - std::function action; - }; - - struct ActionData { - std::any data; + std::function action; }; struct CellName { string name; }; - class UI { public: Entity MAIN = 0; @@ -69,9 +73,8 @@ namespace guecs { void init(); void render(sf::RenderWindow& window); - bool mouse(float x, float y, bool hover); - void click_on(const string& name, bool required=false); - void click_on(Entity slot_id); + bool mouse(float x, float y, Modifiers mods); + void click_on(Entity slot_id, Modifiers mods); void debug_layout(sf::RenderWindow& window); Entity entity() { return ++entity_count; } diff --git a/meson.build b/meson.build index a9f4b00..57f07ec 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,7 @@ # HEY BUG: when you have a . spec in a LEL it doesn't work on text project('lel-guecs', 'cpp', - version: '0.5.0', + version: '0.6.0', default_options: [ 'cpp_std=c++20', 'cpp_args=-D_GLIBCXX_DEBUG=1 -D_GLIBCXX_DEBUG_PEDANTIC=1', diff --git a/src/guecs/ui.cpp b/src/guecs/ui.cpp index 396a277..2d6c4d3 100644 --- a/src/guecs/ui.cpp +++ b/src/guecs/ui.cpp @@ -149,9 +149,9 @@ namespace guecs { }); } - bool UI::mouse(float x, float y, bool hover) { + bool UI::mouse(float x, float y, Modifiers mods) { int action_count = 0; - // BUG: Is Parser::hit useful? + bool hover = mods.test(size_t(ModBit::hover)); query([&](auto ent, auto& cell) { if((x >= cell.x && x <= cell.x + cell.w) && @@ -169,11 +169,11 @@ namespace guecs { if(hover) return; - click_on(ent); + click_on(ent, mods); action_count++; } else { - do_if(ent, [hover](auto& effect) { + do_if(ent, [](auto& effect) { effect.stop(); }); @@ -220,25 +220,10 @@ namespace guecs { } } - void UI::click_on(const string& name, bool required) { - auto ent = entity(name); - - if(required) { - assert(has(ent) && - "click_on required '{}' to exist but it doesn't"); - } - - click_on(ent); - } - - void UI::click_on(Entity ent) { - if(auto clicked = get_if(ent)) { - if(auto action_data = get_if(ent)) { - clicked->action(ent, action_data->data); - } else { - clicked->action(ent, {}); - } - } + void UI::click_on(Entity gui_id, Modifiers mods) { + if(auto to_click = get_if(gui_id)) { + to_click->action(mods); + }; } wstring to_wstring(const string& str) { From 4b4992185fa2c27d5d93898001c35c08c057c0ea Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Thu, 14 Aug 2025 12:54:16 -0400 Subject: [PATCH 4/6] Needed a default of no Modifiers to click_on since that's a very common operation. Also a constant to represent that. --- include/guecs/ui.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/guecs/ui.hpp b/include/guecs/ui.hpp index 2d30731..af61965 100644 --- a/include/guecs/ui.hpp +++ b/include/guecs/ui.hpp @@ -26,13 +26,16 @@ namespace guecs { }; enum class ModBit { - hover=0, - left=1, - right=2 + NONE=0, + hover=1, + left=2, + right=3 }; using Modifiers = std::bitset<16>; + constexpr const Modifiers NO_MODS{size_t(ModBit::NONE)}; + struct Clickable { /* This is actually called by UI::mouse and passed the entity ID of the * button pressed so you can interact with it in the event handler. @@ -74,7 +77,7 @@ namespace guecs { void init(); void render(sf::RenderWindow& window); bool mouse(float x, float y, Modifiers mods); - void click_on(Entity slot_id, Modifiers mods); + void click_on(Entity slot_id, Modifiers mods=NO_MODS); void debug_layout(sf::RenderWindow& window); Entity entity() { return ++entity_count; } From 41d568ab256e34e4dabeac2518970f78639e4fdf Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Thu, 14 Aug 2025 13:01:27 -0400 Subject: [PATCH 5/6] Bring back the convenience method to click on a cell by name. --- include/guecs/ui.hpp | 1 + src/guecs/ui.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/include/guecs/ui.hpp b/include/guecs/ui.hpp index af61965..faf8327 100644 --- a/include/guecs/ui.hpp +++ b/include/guecs/ui.hpp @@ -77,6 +77,7 @@ namespace guecs { void init(); void render(sf::RenderWindow& window); bool mouse(float x, float y, Modifiers mods); + void click_on(const std::string& name, Modifiers mods=NO_MODS); void click_on(Entity slot_id, Modifiers mods=NO_MODS); void debug_layout(sf::RenderWindow& window); diff --git a/src/guecs/ui.cpp b/src/guecs/ui.cpp index 2d6c4d3..1cbaffd 100644 --- a/src/guecs/ui.cpp +++ b/src/guecs/ui.cpp @@ -220,6 +220,10 @@ namespace guecs { } } + void UI::click_on(const std::string& name, Modifiers mods) { + click_on(entity(name), mods); + } + void UI::click_on(Entity gui_id, Modifiers mods) { if(auto to_click = get_if(gui_id)) { to_click->action(mods); From 070244269e44cdf4591af410e9d5e831575c6d86 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Thu, 14 Aug 2025 13:59:36 -0400 Subject: [PATCH 6/6] class enums are just jank when trying to work with a bitset. --- include/guecs/ui.hpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/include/guecs/ui.hpp b/include/guecs/ui.hpp index faf8327..bb1f7b7 100644 --- a/include/guecs/ui.hpp +++ b/include/guecs/ui.hpp @@ -25,16 +25,18 @@ namespace guecs { std::queue free_indices; }; - enum class ModBit { - NONE=0, - hover=1, - left=2, - right=3 - }; + namespace ModBit { + enum { + NONE=0, + hover=1, + left=2, + right=3 + }; + } using Modifiers = std::bitset<16>; - constexpr const Modifiers NO_MODS{size_t(ModBit::NONE)}; + constexpr const Modifiers NO_MODS{0}; struct Clickable { /* This is actually called by UI::mouse and passed the entity ID of the