22#include < variant>
33#include < vector>
44
5+ #include < GLFW/glfw3.h>
6+
57#include < cage-core/hashString.h>
68#include < cage-core/string.h>
79#include < cage-core/texts.h>
@@ -183,6 +185,10 @@ namespace cage
183185 return maker.result ;
184186 }
185187
188+ bool guiUpdateGlobal (uintPtr ptr, const GenericInput &);
189+
190+ EventListener<bool (const GenericInput &)> assignmentListener;
191+
186192 class KeybindImpl : public Keybind
187193 {
188194 public:
@@ -226,7 +232,11 @@ namespace cage
226232 if (any (r & KeybindModesFlags::Release))
227233 active = false ;
228234 if (any (r & config.modes ))
229- return event (input);
235+ {
236+ if (event)
237+ return event (input);
238+ return false ;
239+ }
230240 }
231241 return false ;
232242 }
@@ -237,7 +247,117 @@ namespace cage
237247 std::vector<Matcher> matchers;
238248 const uint32 textId = 0 ;
239249 mutable bool active = false ; // allows tick events
250+
251+ Entity *guiEnt = nullptr ;
252+ uint32 assigningIndex = m;
253+
254+ void makeGui ()
255+ {
256+ CAGE_ASSERT (guiEnt);
257+ detail::guiDestroyChildrenRecursively (guiEnt);
258+ Holder<GuiBuilder> g = newGuiBuilder (guiEnt);
259+ auto _ = g->leftRowStretchRight ();
260+ for (uint32 i = 0 ; i < count (); i++)
261+ {
262+ auto _ = g->button ().event (Delegate<bool (const GenericInput &)>().bind <uintPtr, &guiUpdateGlobal>(uintPtr (this ) + i)).text (value (i));
263+ if (assigningIndex == i)
264+ _.accent (Vec4 (50 , 230 , 255 , 100 ) / 255 );
265+ }
266+ {
267+ auto _ = g->row (0.5 );
268+ g->button ().disabled (count () >= 3 ).event (Delegate<bool (const GenericInput &)>().bind <KeybindImpl, &KeybindImpl::guiAdd>(this )).image (HashString (" cage/texture/keybindAdd.png" )).tooltip <HashString (" cage/keybinds/add" ), " Add" >().size (Vec2 (28 ));
269+ g->button ().disabled (count () == 0 ).event (Delegate<bool (const GenericInput &)>().bind <KeybindImpl, &KeybindImpl::guiRemove>(this )).image (HashString (" cage/texture/keybindRemove.png" )).tooltip <HashString (" cage/keybinds/remove" ), " Remove" >().size (Vec2 (28 ));
270+ }
271+ {
272+ auto _ = g->rightRow (0.5 );
273+ g->button ().disabled (count () == 0 ).event (Delegate<bool (const GenericInput &)>().bind <KeybindImpl, &KeybindImpl::guiClear>(this )).image (HashString (" cage/texture/keybindClear.png" )).tooltip <HashString (" cage/keybinds/clear" ), " Clear" >().size (Vec2 (28 ));
274+ g->button ().event (Delegate<bool (const GenericInput &)>().bind <KeybindImpl, &KeybindImpl::guiReset>(this )).image (HashString (" cage/texture/keybindReset.png" )).tooltip <HashString (" cage/keybinds/reset" ), " Reset" >().size (Vec2 (28 ));
275+ }
276+ }
277+
278+ bool guiUpdate (uint32 index, const GenericInput &)
279+ {
280+ assigningIndex = index;
281+ makeGui ();
282+ assignmentListener.bind (Delegate<bool (const GenericInput &in)>().bind <KeybindImpl, &KeybindImpl::guiAssign>(this ));
283+ return true ;
284+ }
285+
286+ void cancel ()
287+ {
288+ assignmentListener.clear ();
289+ assigningIndex = m;
290+ makeGui ();
291+ }
292+
293+ bool guiAssign (const GenericInput &in)
294+ {
295+ if (in.has <input::WindowFocusLose>())
296+ {
297+ cancel ();
298+ return false ;
299+ }
300+ if (in.has <input::KeyRelease>() || in.has <input::KeyRepeat>())
301+ return false ;
302+ if (in.has <input::KeyPress>())
303+ {
304+ const input::KeyPress k = in.get <input::KeyPress>();
305+ switch (k.key )
306+ {
307+ case GLFW_KEY_LEFT_SHIFT:
308+ case GLFW_KEY_LEFT_CONTROL:
309+ case GLFW_KEY_LEFT_ALT:
310+ case GLFW_KEY_LEFT_SUPER:
311+ case GLFW_KEY_RIGHT_SHIFT:
312+ case GLFW_KEY_RIGHT_CONTROL:
313+ case GLFW_KEY_RIGHT_ALT:
314+ case GLFW_KEY_RIGHT_SUPER:
315+ return false ;
316+ }
317+ }
318+ if (in.has <input::MouseDoublePress>() || in.has <input::MouseRelease>() || in.has <input::MouseMove>() || in.has <input::MouseRelativeMove>())
319+ return false ;
320+ override (assigningIndex, in);
321+ cancel ();
322+ return true ;
323+ }
324+
325+ bool guiAdd (const GenericInput &)
326+ {
327+ add ();
328+ makeGui ();
329+ return true ;
330+ }
331+
332+ bool guiRemove (const GenericInput &)
333+ {
334+ remove (count () - 1 );
335+ makeGui ();
336+ return true ;
337+ }
338+
339+ bool guiClear (const GenericInput &)
340+ {
341+ clear ();
342+ makeGui ();
343+ return true ;
344+ }
345+
346+ bool guiReset (const GenericInput &)
347+ {
348+ reset ();
349+ makeGui ();
350+ return true ;
351+ }
240352 };
353+
354+ bool guiUpdateGlobal (uintPtr ptr, const GenericInput &in)
355+ {
356+ const uint32 index = ptr % alignof (KeybindImpl);
357+ ptr -= index;
358+ KeybindImpl *impl = (KeybindImpl *)ptr;
359+ return impl->guiUpdate (index, in);
360+ }
241361 }
242362
243363 const String &Keybind::id () const
@@ -260,7 +380,7 @@ namespace cage
260380 [](const auto &mt) -> String
261381 {
262382 if constexpr (std::is_same_v<std::decay_t <decltype (mt)>, std::monostate>)
263- return " <nothing> " ;
383+ return " ----- " ;
264384 else
265385 return mt.value ();
266386 },
@@ -273,6 +393,12 @@ namespace cage
273393 return impl->process (input);
274394 }
275395
396+ bool Keybind::active () const
397+ {
398+ const KeybindImpl *impl = (const KeybindImpl *)this ;
399+ return impl->active ;
400+ }
401+
276402 uint32 Keybind::count () const
277403 {
278404 const KeybindImpl *impl = (const KeybindImpl *)this ;
@@ -289,9 +415,14 @@ namespace cage
289415 void Keybind::add (const GenericInput &input)
290416 {
291417 KeybindImpl *impl = (KeybindImpl *)this ;
292- const auto mt = makeMatcher (impl->config , input);
293- if (!std::holds_alternative<std::monostate>(mt))
294- impl->matchers .push_back (mt);
418+ if (input)
419+ {
420+ const auto mt = makeMatcher (impl->config , input);
421+ if (!std::holds_alternative<std::monostate>(mt))
422+ impl->matchers .push_back (mt);
423+ }
424+ else
425+ impl->matchers .push_back ({});
295426 }
296427
297428 void Keybind::remove (uint32 index)
@@ -338,6 +469,7 @@ namespace cage
338469
339470 void keybindsRegisterListeners (EventDispatcher<bool (const GenericInput &)> &dispatcher)
340471 {
472+ assignmentListener.attach (dispatcher, -328655984 );
341473 for (KeybindImpl *it : global)
342474 {
343475 it->listener .clear ();
@@ -353,21 +485,17 @@ namespace cage
353485 it->process (g);
354486 }
355487
356- void keybindsGuiWidget (GuiBuilder *g, Keybind *k )
488+ void keybindsGuiWidget (GuiBuilder *g, Keybind *k_ )
357489 {
358- auto _1 = g->leftRowStretchRight ();
359- for (uint32 i = 0 ; i < k->count (); i++)
360- g->button ().text (k->value (i));
361- {
362- auto _2 = g->alignment ();
363- g->button ().image (HashString (" cage/texture/keybindAdd.png" )).tooltip <HashString (" cage/keybinds/add" ), " Add" >().size (Vec2 (28 ));
364- }
365- auto _3 = g->alignment (Vec2 (1 , 0.5 ));
366- g->button ().image (HashString (" cage/texture/keybindReset.png" )).tooltip <HashString (" cage/keybinds/reset" ), " Reset" >().size (Vec2 (28 ));
490+ KeybindImpl *k = (KeybindImpl *)k_;
491+ auto _ = g->empty ();
492+ k->guiEnt = _.entity ();
493+ k->makeGui ();
367494 }
368495
369496 void keybindsGuiTable (GuiBuilder *g, const String &filterPrefix)
370497 {
498+ std::sort (global.begin (), global.end (), [](const KeybindImpl *a, const KeybindImpl *b) -> bool { return std::pair{ a->config .displayOrder , a->config .id } < std::pair{ b->config .displayOrder , b->config .id }; });
371499 auto _ = g->verticalTable (2 );
372500 for (KeybindImpl *k : global)
373501 {
0 commit comments