13 std::shared_ptr<Core::Window>
window,
16 : m_layer(
std::move(layer))
18 , m_event_manager(event_manager)
22 const auto& state =
m_window->get_state();
40 m_callbacks[id].press[
static_cast<int>(btn)] = std::move(fn);
45 m_callbacks[id].release[
static_cast<int>(btn)] = std::move(fn);
55 m_callbacks[id].drag[
static_cast<int>(btn)] = std::move(fn);
75 const int key_code =
static_cast<int>(key);
76 m_callbacks[id].key_press[key_code] = std::move(fn);
79 const std::string key_name = std::to_string(key_code);
81 std::make_shared<Vruta::Event>(
84 m_name +
"_key_press_" + key_name);
91 const int key_code =
static_cast<int>(key);
92 m_callbacks[id].key_release[key_code] = std::move(fn);
95 const std::string key_name = std::to_string(key_code);
97 std::make_shared<Vruta::Event>(
100 m_name +
"_key_release_" + key_name);
107 const int key_code =
static_cast<int>(key);
108 m_callbacks[id].key_held[key_code] = std::move(fn);
111 const std::string key_name = std::to_string(key_code);
113 std::make_shared<Vruta::Event>(
116 m_name +
"_key_held_" + key_name);
162 if (it !=
m_callbacks.end() && it->second.focus_lost)
172 if (it !=
m_callbacks.end() && it->second.focus_lost)
173 it->second.focus_lost(
id);
181 if (dragging && *dragging ==
id)
182 dragging = std::nullopt;
190 return m_window->get_event_source();
202 on_held(
id, decrease, [state, delta, clamp_min, clamp_max](uint32_t) {
203 state->write(std::clamp(state->value - delta, clamp_min, clamp_max));
206 on_held(
id, increase, [state, delta, clamp_min, clamp_max](uint32_t) {
207 state->write(std::clamp(state->value + delta, clamp_min, clamp_max));
215 on_held(
id, key, std::move(fn));
221 std::function<
void(glm::vec2)> sink,
228 [sink = std::move(sink)](uint32_t, glm::vec2 ndc) { sink(ndc); });
240 std::make_shared<Vruta::Event>(
242 [
this](
double px,
double py) {
249 std::make_shared<Vruta::Event>(
255 std::make_shared<Vruta::Event>(
258 m_name +
"_release_left");
261 std::make_shared<Vruta::Event>(
267 std::make_shared<Vruta::Event>(
270 m_name +
"_release_right");
273 std::make_shared<Vruta::Event>(
276 m_name +
"_press_middle");
279 std::make_shared<Vruta::Event>(
282 m_name +
"_release_middle");
285 std::make_shared<Vruta::Event>(
291 std::make_shared<Vruta::Event>(
293 [
this](uint32_t codepoint) {
handle_text(codepoint); })),
297 std::make_shared<Vruta::Event>(
303 std::make_shared<Vruta::Event>(
311 for (
const char* suffix : {
313 "_press_left",
"_release_left",
314 "_press_right",
"_release_right",
315 "_press_middle",
"_release_middle",
316 "_scroll",
"_text",
"_resize" }) {
324 const std::string key_name = std::to_string(key_code);
325 if (handlers.has_press)
327 if (handlers.has_release)
329 if (handlers.has_held)
340 const auto& s = m_window->get_state();
342 (
static_cast<float>(
px) /
static_cast<float>(s.current_width)) * 2.0F - 1.0F,
343 1.0F - (
static_cast<float>(
py) /
static_cast<float>(s.current_height)) * 2.0F
349 return { .
min = to_ndc(x, y +
h), .max = to_ndc(x + w, y) };
356 const auto hit =
m_layer->hit_test(ndc);
367 it->second.enter(*hit);
375 it->second.move(*hit, ndc);
383 const auto hit =
m_layer->hit_test(ndc);
385 const int btn_idx =
static_cast<int>(btn);
390 if (it !=
m_callbacks.end() && it->second.focus_lost)
398 if (it !=
m_callbacks.end() && it->second.focus_gained)
399 it->second.focus_gained(*hit);
409 if (it !=
m_callbacks.end() && it->second.press.count(btn_idx))
410 it->second.press[btn_idx](*hit, ndc);
416 const int btn_idx =
static_cast<int>(btn);
420 const auto hit =
m_layer->hit_test(ndc);
428 auto btn_it = it->second.release.find(
static_cast<int>(btn));
429 if (btn_it != it->second.release.end() && btn_it->second)
430 btn_it->second(*hit, ndc);
435 const auto& source =
m_window->get_event_source();
437 if (source.is_mouse_pressed(
static_cast<int>(btn)))
445 const int btn_idx =
static_cast<int>(btn);
448 const auto hit =
m_layer->hit_test(ndc);
456 if (it !=
m_callbacks.end() && it->second.drag.count(btn_idx))
457 it->second.drag[btn_idx](*
m_dragging[btn_idx], ndc);
470 const auto [
px,
py] =
m_window->get_event_source().get_mouse_position();
488 const int key_code =
static_cast<int>(key);
489 auto key_it = it->second.key_press.find(key_code);
490 if (key_it != it->second.key_press.end())
503 const int key_code =
static_cast<int>(key);
504 auto key_it = it->second.key_release.find(key_code);
505 if (key_it != it->second.key_release.end())
518 const int key_code =
static_cast<int>(key);
519 auto key_it = it->second.key_held.find(key_code);
520 if (key_it != it->second.key_held.end())
543 const auto& state =
m_window->get_state();
554 if (callbacks.resize)
562 const std::string close_event_name =
m_name +
"_close";
571 name = std::move(close_event_name)]() {
572 event_manager->cancel_event(
name);
std::weak_ptr< Core::Window > window
std::function< void(uint32_t id)> KeyFn
std::unordered_map< int, KeyHandlerState > m_registered_keys
Context & wire_drag(uint32_t id, std::function< void(glm::vec2)> sink, IO::MouseButtons btn=IO::MouseButtons::Left)
Register a drag handler receiving only the cursor position.
void sync_size()
Run the resize callbacks if the window's size differs from the size they last saw.
std::optional< uint32_t > m_dragging[3]
void on_resize(uint32_t id, ResizeFn fn)
Called on every window resize.
void handle_key_release(IO::Keys key)
std::function< void(uint32_t id, uint32_t codepoint)> TextFn
std::shared_ptr< Layer > m_layer
void on_scroll(uint32_t id, ScrollFn fn)
Called on scroll while the cursor is over an element.
void handle_move(double px, double py)
void on_focus_gained(uint32_t id, EnterFn fn)
Called once when an element gains keyboard focus (via click).
void handle_drags(double px, double py)
void handle_key_press(IO::Keys key)
void on_enter(uint32_t id, EnterFn fn)
Called once when the cursor enters an element's region.
std::function< void(uint32_t id, glm::vec2 ndc)> MoveFn
std::function< void(uint32_t width, uint32_t height)> ResizeFn
Context(std::shared_ptr< Layer > layer, std::shared_ptr< Core::Window > window, Vruta::EventManager &event_manager, std::string name)
Construct and immediately register event coroutines.
void handle_key_held(IO::Keys key)
void unbind(uint32_t id)
Remove all callbacks registered for an element id.
std::function< void(uint32_t id, glm::vec2 ndc, double dx, double dy)> ScrollFn
Vruta::EventManager & m_event_manager
void on_close(uint32_t id, CloseFn fn)
Register a callback invoked when the Context window closes.
std::shared_ptr< Core::Window > m_window
std::function< void(uint32_t id, glm::vec2 ndc)> PressFn
void handle_release(double px, double py, IO::MouseButtons btn)
Context & press_and_hold(uint32_t id, IO::Keys key, KeyFn fn)
Register a key handler that fires on the initial press and on every repeat, with a deterministic firs...
const Vruta::WindowEventSource & event_source() const
void handle_drag(double px, double py, IO::MouseButtons btn)
std::function< void(uint32_t id)> LeaveFn
void cancel_handlers(bool cancel_close=true)
Kinesis::AABB2D to_ndc_rect(double x, double y, double w, double h) const noexcept
Rect of pixel size (w, h) at pixel position (x, y), top-left origin, converted to NDC from the window...
void on_text(uint32_t id, TextFn fn)
Called with each resolved Unicode codepoint while the element has keyboard focus.
void on_focus_lost(uint32_t id, LeaveFn fn)
Called once when an element loses keyboard focus.
void handle_resize(uint32_t width, uint32_t height)
void on_move(uint32_t id, MoveFn fn)
Called each move event while the cursor is over an element.
glm::vec2 to_ndc(double px, double py) const noexcept
std::unordered_map< uint32_t, ElementCallbacks > m_callbacks
void on_release(uint32_t id, IO::MouseButtons btn, PressFn fn)
Called when a mouse button is released over an element.
void on_press(uint32_t id, IO::MouseButtons btn, PressFn fn)
Called when a mouse button is pressed over an element.
void on_drag(uint32_t id, IO::MouseButtons btn, MoveFn fn)
Called on each mouse-move event while btn is held, tracking the element where the drag began even whe...
std::optional< uint32_t > m_hovered
void on_leave(uint32_t id, LeaveFn fn)
Called once when the cursor leaves an element's region.
std::function< void(uint32_t id)> EnterFn
void handle_press(double px, double py, IO::MouseButtons btn)
void handle_scroll(double dx, double dy)
Context & key_step(uint32_t id, std::shared_ptr< MappedState< float > > state, IO::Keys decrease, IO::Keys increase, float delta, float clamp_min=0.0F, float clamp_max=1.0F)
Attach key-delta handlers to a Mapped<float> element.
std::function< void()> CloseFn
void on_held(uint32_t id, IO::Keys key, KeyFn fn)
Called repeatedly while a key is held and the element has focus.
void handle_text(uint32_t codepoint)
void clear_focus()
Clear keyboard focus (no element focused).
~Context()
Cancel all registered event coroutines.
void detach_window(bool cancel_close=true)
std::optional< uint32_t > m_focused
Event wiring between a Layer and a window surface.
void add_event(const std::shared_ptr< Event > &event, const std::string &name="")
Add a event to the manager.
bool cancel_event(const std::shared_ptr< Event > &event)
Cancels and removes a event from the manager.
void defer(std::function< void()> action)
Run an action after the active outermost window-event dispatch.
Awaitable stream of window input events.
MouseButtons
Enumeration for mouse buttons.
Vruta::Event key_released(std::shared_ptr< Core::Window > window, IO::Keys key, std::function< void()> callback)
Creates an Event coroutine that triggers on specific key release.
Vruta::Event key_pressed(std::shared_ptr< Core::Window > window, IO::Keys key, std::function< void()> callback)
Creates an Event coroutine that triggers on specific key press.
Vruta::Event mouse_moved(std::shared_ptr< Core::Window > window, std::function< void(double, double)> callback)
Creates an Event coroutine that triggers on mouse movement.
Vruta::Event mouse_scrolled(std::shared_ptr< Core::Window > window, std::function< void(double, double)> callback)
Creates an Event coroutine that triggers on mouse scroll.
Vruta::Event window_closed(std::shared_ptr< Core::Window > window, std::function< void()> callback)
Creates an Event coroutine that triggers on window close.
Vruta::Event key_held(std::shared_ptr< Core::Window > window, IO::Keys key, std::function< void()> callback)
Creates an Event coroutine that triggers on key press and repeats while held.
Vruta::Event mouse_released(std::shared_ptr< Core::Window > window, IO::MouseButtons button, std::function< void(double, double)> callback)
Creates an Event coroutine that triggers on specific mouse button release.
Vruta::Event mouse_pressed(std::shared_ptr< Core::Window > window, IO::MouseButtons button, std::function< void(double, double)> callback)
Creates an Event coroutine that triggers on specific mouse button press.
Vruta::Event window_resized(std::shared_ptr< Core::Window > window, std::function< void(uint32_t, uint32_t)> callback)
Creates an Event coroutine that triggers on window resize.
Vruta::Event text_input(std::shared_ptr< Core::Window > window, std::function< void(uint32_t)> callback)
Creates an Event coroutine that triggers on resolved text input.
Axis-aligned bounding rectangle in a 2D coordinate space.