SDOM - Simple SDL Document Object Model
A lightweight, extensible Document Object Model for SDL-based applications.
Loading...
Searching...
No Matches
SDOM_IButtonObject.hpp
Go to the documentation of this file.
1// SDOM_IButtonObject.hpp
2#pragma once
3
4#include <string>
5#include <unordered_map>
6#include <optional>
8
9namespace SDOM
10{
11 // Logical toggle state (canonical single source for checkbox/radio/tristate)
12 enum class ButtonState : int
13 {
14 Inactive = 0, // aliases: Released / Unchecked / Clear / Up / Off
15 Active, // aliases: Pressed / Checked / Set / Down / On
16 Mixed, // aliases: Indeterminate / Maybe / Option
17 Disabled, // aliases: Faded / Grayed
18 // Inactive Aliases:
22 Up = Inactive,
23 Off = Inactive,
24 // Active Aliases:
25 Pressed = Active,
26 Checked = Active,
27 Set = Active,
28 Down = Active,
29 On = Active,
30 // Mixed Aliases:
32 Maybe = Mixed,
33 Option = Mixed,
34 // Disabled Aliases:
36 Gray = Disabled,
38 Grey = Disabled,
40 // Last Entry
42 }; // END: enum class ButtonState
43
44 inline static const std::vector<std::pair<int, std::string>> button_state_pairs = {
45 { static_cast<int>(ButtonState::Inactive), "inactive" },
46 { static_cast<int>(ButtonState::Active), "active" },
47 { static_cast<int>(ButtonState::Mixed), "mixed" },
48 { static_cast<int>(ButtonState::Disabled), "disabled" },
49 // Inactive Aliases:
50 { static_cast<int>(ButtonState::Released), "released" },
51 { static_cast<int>(ButtonState::Unchecked), "unchecked" },
52 { static_cast<int>(ButtonState::Clear), "clear" },
53 { static_cast<int>(ButtonState::Up), "up" },
54 { static_cast<int>(ButtonState::Off), "off" },
55 // Active Aliases:
56 { static_cast<int>(ButtonState::Pressed), "pressed" },
57 { static_cast<int>(ButtonState::Checked), "checked" },
58 { static_cast<int>(ButtonState::Set), "set" },
59 { static_cast<int>(ButtonState::Down), "down" },
60 { static_cast<int>(ButtonState::On), "on" },
61 // Mixed Aliases:
62 { static_cast<int>(ButtonState::Indeterminate), "indeterminate" },
63 { static_cast<int>(ButtonState::Maybe), "maybe" },
64 { static_cast<int>(ButtonState::Option), "option" },
65 // Disabled Aliases:
66 { static_cast<int>(ButtonState::Faded), "faded" },
67 { static_cast<int>(ButtonState::Gray), "gray" },
68 { static_cast<int>(ButtonState::Grayed), "grayed" },
69 { static_cast<int>(ButtonState::Grey), "grey" },
70 { static_cast<int>(ButtonState::Greyed), "greyed" },
71 // Last Entry
72 { static_cast<int>(ButtonState::ButtonState_MAX), "button_state_max" }
73 };
74
75 // canonical int -> name (first occurrence wins)
76 inline static const std::unordered_map<int, std::string> button_state_to_string = []{
77 std::unordered_map<int,std::string> m;
78 for (auto &p : button_state_pairs) {
79 if (m.find(p.first) == m.end()) m.emplace(p.first, p.second);
80 }
81 return m;
82 }();
83
84 // reverse mapping including all aliases (lowercased keys)
85 #include <algorithm>
86 #include <cctype>
87 inline static const std::unordered_map<std::string, int> string_to_button_state = []{
88 std::unordered_map<std::string,int> m;
89 for (auto &p : button_state_pairs) {
90 std::string key = p.second;
91 std::transform(key.begin(), key.end(), key.begin(), [](unsigned char c){
92 return static_cast<char>(std::tolower(c));
93 });
94 m.emplace(std::move(key), p.first);
95 }
96 return m;
97 }();
98
99 // Helper functions (ensure they use lowered names)
100 inline static std::optional<std::string> button_state_name_from_index(ButtonState idx)
101 {
102 auto it = button_state_to_string.find(static_cast<int>(idx));
103 if (it == button_state_to_string.end()) return std::nullopt;
104 std::string name = it->second;
105 std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c){
106 return static_cast<char>(std::tolower(c));
107 });
108 return name;
109 }
110
111 inline static std::optional<ButtonState> button_state_from_name(const std::string &name)
112 {
113 std::string key = name;
114 std::transform(key.begin(), key.end(), key.begin(), [](unsigned char c){
115 return static_cast<char>(std::tolower(c));
116 });
117 auto it = string_to_button_state.find(key);
118 if (it == string_to_button_state.end()) return std::nullopt;
119 return static_cast<ButtonState>(it->second);
120 }
121
122
123
125 {
126 public:
127 // --- Construction / Destruction --- //
129 virtual ~IButtonObject() = default;
130
131 // --- State Accessors --- //
132 virtual ButtonState getState() const { return buttonState_; }
133 virtual void setState(ButtonState state) { onStateChanged(buttonState_, state); buttonState_ = state; }
134
135 // --- Additional State Info --- //
136 bool isMouseHovered() const { return mouse_hovered_; }
137 void setMouseHovered(bool v) { mouse_hovered_ = v; }
138 bool isKeyFocused() const { return key_focused_; }
139 void setKeyFocused(bool v) { key_focused_ = v; }
140
141 protected:
142 // --- Data Members --- //
144 bool mouse_hovered_ = false;
145 bool key_focused_ = false;
146
147 // --- Protected Virtual Hooks --- //
148 virtual void onStateChanged(ButtonState oldState, ButtonState newState) {}
149 virtual IconIndex iconIndexForState(ButtonState state) const { return IconIndex(); }
150
151 // --- Lua Registration --- //
152 static void registerLuaBindings(sol::state_view lua)
153 {
154 // Idempotent / reentrant registration per Lua state.
155 // Use a private sentinel in the Lua globals to avoid duplicate setup.
156 if (lua["_SDOM_IButtonObject_registered"].valid() && lua["_SDOM_IButtonObject_registered"].get_or(false))
157 return;
158
159 // Augment the single shared DisplayHandle handle usertype
160 sol::table handle = SDOM::DisplayHandle::ensure_handle_table(lua);
161
162 // Create / populate a global ButtonState table (canonical names + aliases)
163 sol::table bs = lua["ButtonState"].valid() ? lua["ButtonState"] : lua.create_table();
164
165 auto set_if_absent = [&](sol::table &t, const char* key, int val){
166 if (!t[key].valid()) t[key] = val;
167 };
168
169 set_if_absent(bs, "inactive", static_cast<int>(ButtonState::Inactive));
170 set_if_absent(bs, "active", static_cast<int>(ButtonState::Active));
171 set_if_absent(bs, "mixed", static_cast<int>(ButtonState::Mixed));
172 set_if_absent(bs, "disabled", static_cast<int>(ButtonState::Disabled));
173
174 // aliases (convenience)
175 set_if_absent(bs, "released", static_cast<int>(ButtonState::Released));
176 set_if_absent(bs, "unchecked", static_cast<int>(ButtonState::Unchecked));
177 set_if_absent(bs, "clear", static_cast<int>(ButtonState::Clear));
178 set_if_absent(bs, "up", static_cast<int>(ButtonState::Up));
179 set_if_absent(bs, "off", static_cast<int>(ButtonState::Off));
180
181 set_if_absent(bs, "pressed", static_cast<int>(ButtonState::Pressed));
182 set_if_absent(bs, "checked", static_cast<int>(ButtonState::Checked));
183 set_if_absent(bs, "set", static_cast<int>(ButtonState::Set));
184 set_if_absent(bs, "down", static_cast<int>(ButtonState::Down));
185 set_if_absent(bs, "on", static_cast<int>(ButtonState::On));
186
187 set_if_absent(bs, "indeterminate", static_cast<int>(ButtonState::Indeterminate));
188 set_if_absent(bs, "maybe", static_cast<int>(ButtonState::Maybe));
189 set_if_absent(bs, "option", static_cast<int>(ButtonState::Option));
190
191 set_if_absent(bs, "faded", static_cast<int>(ButtonState::Faded));
192 set_if_absent(bs, "gray", static_cast<int>(ButtonState::Gray));
193 set_if_absent(bs, "grayed", static_cast<int>(ButtonState::Grayed));
194 set_if_absent(bs, "grey", static_cast<int>(ButtonState::Grey));
195 set_if_absent(bs, "greyed", static_cast<int>(ButtonState::Greyed));
196
197 lua["ButtonState"] = bs;
198
199 // Convenience conversion helpers exposed to Lua (register only if absent)
200 if (!lua["button_state_from_name"].valid())
201 {
202 lua.set_function("button_state_from_name", [](const std::string &name) -> sol::optional<int> {
203 auto opt = button_state_from_name(name);
204 if (!opt) return sol::nullopt;
205 return static_cast<int>(*opt);
206 });
207 }
208
209 if (!lua["button_state_name_from_index"].valid())
210 {
211 lua.set_function("button_state_name_from_index", [](int idx) -> sol::optional<std::string> {
212 auto opt = button_state_name_from_index(static_cast<ButtonState>(idx));
213 if (!opt) return sol::nullopt;
214 return *opt;
215 });
216 }
217
218 // DisplayHandle augmentation: attach handle-level helpers only if absent.
219 auto set_handle_if_absent = [&](const char* name, sol::object value) {
220 if (!handle[name].valid())
221 handle[name] = value;
222 };
223
224 set_handle_if_absent("getState", sol::make_object(lua, [](DisplayHandle h) -> sol::optional<int> {
225 if (!h.isValid()) return sol::nullopt;
226 IButtonObject* btn = h.as<IButtonObject>();
227 if (!btn) return sol::nullopt;
228 return static_cast<int>(btn->getState());
229 }));
230
231 set_handle_if_absent("setState", sol::make_object(lua, [](DisplayHandle h, int state) {
232 if (!h.isValid()) return;
233 IButtonObject* btn = h.as<IButtonObject>();
234 if (!btn) return;
235 btn->setState(static_cast<ButtonState>(state));
236 }));
237
238 set_handle_if_absent("isMouseHovered", sol::make_object(lua, [](DisplayHandle h) -> bool {
239 return h.isValid() && h.as<IButtonObject>() && h.as<IButtonObject>()->isMouseHovered();
240 }));
241
242 set_handle_if_absent("setMouseHovered", sol::make_object(lua, [](DisplayHandle h, bool v) {
243 if (!h.isValid()) return;
244 IButtonObject* btn = h.as<IButtonObject>();
245 if (btn) btn->setMouseHovered(v);
246 }));
247
248 set_handle_if_absent("isKeyFocused", sol::make_object(lua, [](DisplayHandle h) -> bool {
249 return h.isValid() && h.as<IButtonObject>() && h.as<IButtonObject>()->isKeyFocused();
250 }));
251
252 set_handle_if_absent("setKeyFocused", sol::make_object(lua, [](DisplayHandle h, bool v) {
253 if (!h.isValid()) return;
254 IButtonObject* btn = h.as<IButtonObject>();
255 if (btn) btn->setKeyFocused(v);
256 }));
257
258 // Mark registration complete for this lua state
259 lua["_SDOM_IButtonObject_registered"] = true;
260
261 // DisplayHandle augmentation point: derived types may add more handle helpers
262 (void)handle;
263
264 } // END: registerLuaBindings
265
266 }; // END: class IButtonObject
267
268} // END: namespace SDOM
Definition SDOM_DisplayHandle.hpp:24
static sol::table ensure_handle_table(sol::state_view lua)
Definition SDOM_DisplayHandle.cpp:61
T * as() const
Definition SDOM_DisplayHandle.hpp:67
bool isValid() const
Definition SDOM_DisplayHandle.hpp:120
Definition SDOM_IButtonObject.hpp:125
ButtonState buttonState_
Definition SDOM_IButtonObject.hpp:143
void setKeyFocused(bool v)
Definition SDOM_IButtonObject.hpp:139
virtual ButtonState getState() const
Definition SDOM_IButtonObject.hpp:132
void setMouseHovered(bool v)
Definition SDOM_IButtonObject.hpp:137
virtual void setState(ButtonState state)
Definition SDOM_IButtonObject.hpp:133
bool key_focused_
Definition SDOM_IButtonObject.hpp:145
virtual IconIndex iconIndexForState(ButtonState state) const
Definition SDOM_IButtonObject.hpp:149
IButtonObject()
Definition SDOM_IButtonObject.hpp:128
virtual void onStateChanged(ButtonState oldState, ButtonState newState)
Definition SDOM_IButtonObject.hpp:148
virtual ~IButtonObject()=default
bool mouse_hovered_
Definition SDOM_IButtonObject.hpp:144
static void registerLuaBindings(sol::state_view lua)
Definition SDOM_IButtonObject.hpp:152
bool isMouseHovered() const
Definition SDOM_IButtonObject.hpp:136
bool isKeyFocused() const
Definition SDOM_IButtonObject.hpp:138
Contains all core classes and utilities for the SDOM library.
Definition lua_BindHelpers.hpp:7
static const std::unordered_map< int, std::string > button_state_to_string
Definition SDOM_IButtonObject.hpp:76
IconIndex
Definition SDOM_IconIndex.hpp:12
static std::optional< ButtonState > button_state_from_name(const std::string &name)
Definition SDOM_IButtonObject.hpp:111
static std::optional< std::string > button_state_name_from_index(ButtonState idx)
Definition SDOM_IButtonObject.hpp:100
static void set_if_absent(sol::table &handle, const char *name, auto &&fn)
Definition SDOM_AssetHandle.cpp:86
static const std::vector< std::pair< int, std::string > > button_state_pairs
Definition SDOM_IButtonObject.hpp:44
static const std::unordered_map< std::string, int > string_to_button_state
Definition SDOM_IButtonObject.hpp:87
ButtonState
Definition SDOM_IButtonObject.hpp:13