MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Context.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "Layer.hpp"
4
6
7namespace MayaFlux::Core {
8class Window;
9}
10
11namespace MayaFlux::Vruta {
12class EventManager;
13class WindowEventSource;
14}
15
17
18template <typename T>
19struct MappedState;
20
21/**
22 * @class Context
23 * @brief Event wiring between a Layer and a window surface.
24 *
25 * Subscribes to mouse events on a window by constructing Kriya input
26 * coroutines and registering them with a Vruta::EventManager, following
27 * the same pattern as Nexus::Fabric. The EventManager and Window are
28 * injected; Context holds no engine-level singletons.
29 *
30 * Callbacks fire on the scheduler tick. They must not touch GPU resources
31 * directly. State intended for the graphics tick should be written through
32 * shared_ptr captures and read on the next graphics cycle.
33 *
34 * All registered events are cancelled on destruction via
35 * EventManager::cancel_event, keyed by names scoped to this Context.
36 *
37 * Window dimensions are read from window->get_state() at event time,
38 * so resize is handled automatically.
39 */
40class MAYAFLUX_API Context {
41public:
42 using PressFn = std::function<void(uint32_t id, glm::vec2 ndc)>;
43 using MoveFn = std::function<void(uint32_t id, glm::vec2 ndc)>;
44 using EnterFn = std::function<void(uint32_t id)>;
45 using LeaveFn = std::function<void(uint32_t id)>;
46 using ScrollFn = std::function<void(uint32_t id, glm::vec2 ndc, double dx, double dy)>;
47 using KeyFn = std::function<void(uint32_t id)>;
48
49 /**
50 * @brief Construct and immediately register event coroutines.
51 * @param layer Layer to hit-test against. Must outlive Context.
52 * @param window Window whose surface the layer lives on.
53 * @param event_manager Engine EventManager for coroutine registration.
54 * @param name Unique name scoping all registered event handlers.
55 * Must be unique across all live Contexts.
56 */
57 Context(std::shared_ptr<Layer> layer,
58 std::shared_ptr<Core::Window> window,
59 Vruta::EventManager& event_manager,
60 std::string name);
61
62 /**
63 * @brief Cancel all registered event coroutines.
64 */
65 ~Context();
66
67 Context(const Context&) = delete;
68 Context& operator=(const Context&) = delete;
69 Context(Context&&) = delete;
71
72 // =========================================================================
73 // Per-element callbacks
74 // =========================================================================
75
76 /**
77 * @brief Called when a mouse button is pressed over an element.
78 * @param id Element id to bind to.
79 * @param btn Mouse button.
80 * @param fn Callback receiving element id and NDC press position.
81 */
82 void on_press(uint32_t id, IO::MouseButtons btn, PressFn fn);
83
84 /**
85 * @brief Called when a mouse button is released over an element.
86 */
87 void on_release(uint32_t id, IO::MouseButtons btn, PressFn fn);
88
89 /**
90 * @brief Called each move event while the cursor is over an element.
91 */
92 void on_move(uint32_t id, MoveFn fn);
93
94 /**
95 * @brief Called on each mouse-move event while @p btn is held, tracking
96 * the element where the drag began even when the cursor leaves its bounds.
97 *
98 * Drag tracking begins when the element is first hit (either at initial press
99 * or first drag motion while button is held). Once tracking starts, the callback
100 * continues to fire with the current cursor position until the button is released,
101 * regardless of whether the cursor remains over the element.
102 *
103 * This matches standard UI expectations for sliders, scrollbars, resize handles,
104 * and other controls that must respond continuously during a drag gesture.
105 *
106 * Backed by Kriya::mouse_dragged, which gates on button state natively.
107 *
108 * @param id Element id to bind to.
109 * @param btn Mouse button that must be held.
110 * @param fn Callback receiving element id and current NDC cursor position
111 * (which may be outside the element's bounds during drag).
112 */
113 void on_drag(uint32_t id, IO::MouseButtons btn, MoveFn fn);
114
115 /**
116 * @brief Called once when the cursor enters an element's region.
117 */
118 void on_enter(uint32_t id, EnterFn fn);
119
120 /**
121 * @brief Called once when the cursor leaves an element's region.
122 */
123 void on_leave(uint32_t id, LeaveFn fn);
124
125 /**
126 * @brief Called on scroll while the cursor is over an element.
127 */
128 void on_scroll(uint32_t id, ScrollFn fn);
129
130 /**
131 * @brief Remove all callbacks registered for an element id.
132 */
133 void unbind(uint32_t id);
134
135 /**
136 * @brief Called when a key is pressed while the element has focus.
137 *
138 * Focus is transferred on mouse press. The callback fires only once per
139 * key press, even if the key is held.
140 *
141 * @param id Element id to bind to.
142 * @param key The key to listen for.
143 * @param fn Callback receiving element id.
144 */
145 void on_press(uint32_t id, IO::Keys key, KeyFn fn);
146
147 /**
148 * @brief Called when a key is released while the element has focus.
149 *
150 * @param id Element id to bind to.
151 * @param key The key to listen for.
152 * @param fn Callback receiving element id.
153 */
154 void on_release(uint32_t id, IO::Keys key, KeyFn fn);
155
156 /**
157 * @brief Called repeatedly while a key is held and the element has focus.
158 *
159 * Fires on initial press and continues on each repeat tick until the key
160 * is released. Useful for continuous adjustments (arrow key nudging,
161 * value increments) without requiring the user to repeatedly press.
162 *
163 * @param id Element id to bind to.
164 * @param key The key to listen for.
165 * @param fn Callback receiving element id, fired on press and each repeat.
166 */
167 void on_held(uint32_t id, IO::Keys key, KeyFn fn);
168
169 /**
170 * @brief Called once when an element gains keyboard focus (via click).
171 */
172 void on_focus_gained(uint32_t id, EnterFn fn);
173
174 /**
175 * @brief Called once when an element loses keyboard focus.
176 */
177 void on_focus_lost(uint32_t id, LeaveFn fn);
178
179 /**
180 * @brief Clear keyboard focus (no element focused).
181 */
182 void clear_focus();
183
184 /**
185 * @brief Get currently focused element, if any.
186 */
187 [[nodiscard]] std::optional<uint32_t> focused() const { return m_focused; }
188
189 /**
190 * @brief Attach key-delta handlers to a Mapped<float> element.
191 *
192 * Binds key handlers that adjust the element's state by a delta on each
193 * press/hold. The element must be focused (via mouse click) for keys to fire.
194 *
195 * @param id Element id.
196 * @param state MappedState to adjust.
197 * @param decrease Key that decreases the value.
198 * @param increase Key that increases the value.
199 * @param delta Step size per key event.
200 * @param clamp_min Minimum clamped value (default 0.0F).
201 * @param clamp_max Maximum clamped value (default 1.0F).
202 * @return *this for chaining.
203 */
204 Context& key_step(
205 uint32_t id,
206 std::shared_ptr<MappedState<float>> state,
207 IO::Keys decrease,
208 IO::Keys increase,
209 float delta,
210 float clamp_min = 0.0F,
211 float clamp_max = 1.0F);
212
213 // =========================================================================
214 // State query
215 // =========================================================================
216
217 [[nodiscard]] std::optional<uint32_t> hovered() const { return m_hovered; }
218
219 [[nodiscard]] const Vruta::WindowEventSource& event_source() const;
220
221private:
223 std::unordered_map<int, PressFn> press;
224 std::unordered_map<int, PressFn> release;
225 std::unordered_map<int, MoveFn> drag;
226 std::unordered_map<int, KeyFn> key_press;
227 std::unordered_map<int, KeyFn> key_release;
228 std::unordered_map<int, KeyFn> key_held;
229
234
237 };
238
240 bool has_press = false;
241 bool has_release = false;
242 bool has_held = false;
243 };
244 std::unordered_map<int, KeyHandlerState> m_registered_keys;
245
246 std::shared_ptr<Layer> m_layer;
247 std::shared_ptr<Core::Window> m_window;
249 std::string m_name;
250 std::optional<uint32_t> m_hovered;
251
252 std::unordered_map<uint32_t, ElementCallbacks> m_callbacks;
253
254 void register_handlers();
255 void cancel_handlers();
256
257 [[nodiscard]] glm::vec2 to_ndc(double px, double py) const noexcept;
258
259 void handle_move(double px, double py);
260 void handle_press(double px, double py, IO::MouseButtons btn);
261 void handle_release(double px, double py, IO::MouseButtons btn);
262 void handle_scroll(double dx, double dy);
263 void handle_drag(double px, double py, IO::MouseButtons btn);
264 void handle_key_press(IO::Keys key);
265 void handle_key_release(IO::Keys key);
266 void handle_key_held(IO::Keys key);
267
268 std::optional<uint32_t> m_dragging[3];
269 std::optional<uint32_t> m_focused;
270};
271
272} // namespace MayaFlux::Portal::Forma
std::function< void(uint32_t id)> KeyFn
Definition Context.hpp:47
std::unordered_map< int, KeyHandlerState > m_registered_keys
Definition Context.hpp:244
Context(const Context &)=delete
Context & operator=(Context &&)=delete
std::shared_ptr< Layer > m_layer
Definition Context.hpp:246
std::optional< uint32_t > hovered() const
Definition Context.hpp:217
std::function< void(uint32_t id, glm::vec2 ndc)> MoveFn
Definition Context.hpp:43
std::function< void(uint32_t id, glm::vec2 ndc, double dx, double dy)> ScrollFn
Definition Context.hpp:46
Vruta::EventManager & m_event_manager
Definition Context.hpp:248
std::shared_ptr< Core::Window > m_window
Definition Context.hpp:247
std::function< void(uint32_t id, glm::vec2 ndc)> PressFn
Definition Context.hpp:42
std::function< void(uint32_t id)> LeaveFn
Definition Context.hpp:45
std::unordered_map< uint32_t, ElementCallbacks > m_callbacks
Definition Context.hpp:252
std::optional< uint32_t > focused() const
Get currently focused element, if any.
Definition Context.hpp:187
std::optional< uint32_t > m_hovered
Definition Context.hpp:250
std::function< void(uint32_t id)> EnterFn
Definition Context.hpp:44
Context & operator=(const Context &)=delete
std::optional< uint32_t > m_focused
Definition Context.hpp:269
Event wiring between a Layer and a window surface.
Definition Context.hpp:40
Awaitable stream of GLFW window input events.
MouseButtons
Enumeration for mouse buttons.
Definition Keys.hpp:147
void on_scroll(const std::shared_ptr< Core::Window > &window, std::function< void(double, double)> callback, std::string name)
Schedule a mouse scroll handler.
Definition Chronie.cpp:250
std::unordered_map< int, KeyFn > key_press
Definition Context.hpp:226
std::unordered_map< int, KeyFn > key_release
Definition Context.hpp:227
std::unordered_map< int, PressFn > press
Definition Context.hpp:223
std::unordered_map< int, KeyFn > key_held
Definition Context.hpp:228
std::unordered_map< int, MoveFn > drag
Definition Context.hpp:225
std::unordered_map< int, PressFn > release
Definition Context.hpp:224
Value carrier for a Mapped primitive.
Definition Mapped.hpp:36