CYD-UI
A C++ library for building native graphic user interfaces
Loading...
Searching...
No Matches
layout_ev_dispatch.cppm
Go to the documentation of this file.
1
5
6module;
7#include <tracy/Tracy.hpp>
8#define SDL_MAIN_HANDLED
9#include <SDL3/SDL.h>
10
11
12export module cydui:layout_ev_dispatch;
13
14import std;
15import fabric.logging;
16import fabric.profiling;
17
19
20export import :layout;
21
22export namespace cydui {
23#define INSTANCE_EV_HANDLER(STATE_PTR) \
24 if (STATE_PTR->component_instance.has_value()) \
25 STATE_PTR->component_instance.value()->get_event_dispatcher()
26
27
28 std::vector<fabric::async::raw_listener::sptr> Layout::make_event_listeners() {
29 ZoneScopedN("Layout:make_event_listeners");
30 std::vector<fabric::async::raw_listener::sptr> listeners{};
31
32 static auto make_listener = [&](auto&& fun) { return win->on_event(fun).raw(); };
33
34 listeners = {
35 make_listener([&](const RequestComponentFocus& ev) -> fabric::task<> {
36 const auto& target = ev.component;
37 if (nullptr == target) {
38 co_return;
39 }
40 if (focused != target->state()) {
41 if (focused) {
42 focused->focused = false;
43 INSTANCE_EV_HANDLER(focused)->dispatch_focus_changed();
44 if (focused->is_text_input()) {
45 SDL_StopTextInput(win->native()->window);
46 }
47 if (focused->component_instance.has_value()) {
48 component_stylist->apply_style(focused->component_instance.value());
49 }
50 focused->mark_dirty();
51 focused = nullptr;
52 }
53 focused = target->state();
54 focused->focused = true;
55 INSTANCE_EV_HANDLER(focused)->dispatch_focus_changed();
56 if (focused->is_text_input()) {
57 SDL_StartTextInput(win->native()->window);
58 }
59 if (focused->component_instance.has_value()) {
60 component_stylist->apply_style(focused->component_instance.value());
61 }
62 focused->mark_dirty();
63 }
64
65 render_if_dirty(root);
66 co_return;
67 }),
68 make_listener([&](const WindowClosed& ev) -> fabric::task<> {
69 win->terminate();
70 co_return;
71 }),
72 make_listener([&](const RedrawEvent& ev) -> fabric::task<> {
73 ZoneScopedN("Redraw Event");
74 auto _pev = this->win->profiling_ctx.scope_event("Redraw");
75 if (ev.component) {
76 components::component_state_t* target_state =
77 ((components::component_state_t*)ev.component);
78 if (target_state->component_instance.has_value()) {
79 update_component(target_state->component_instance.value());
80 }
81 } else {
82 update_component(root);
83 }
84
85 update_dimensions();
86 component_renderer->render(*win->native(), root);
87 co_return;
88 }),
89 make_listener([&](const KeyEvent& ev) -> fabric::task<> {
90 ZoneScopedN("Key Event");
91 auto _pev = this->win->profiling_ctx.scope_event("Key");
92 if (ev.keysym.code == SDLK_F12 && ev.pressed && not ev.holding) {
93 LOG::print{INFO}("Pressed Debug Key");
94 co_return;
95 }
96 if (focused && focused->component_instance) {
97 if (focused->focused) {
98 if (ev.pressed) {
99 INSTANCE_EV_HANDLER(focused)->dispatch_key_press(ev);
100 } else if (ev.released) {
101 INSTANCE_EV_HANDLER(focused)->dispatch_key_release(ev);
102 }
103 render_if_dirty(focused->component_instance.value());
104 } else {
105 focused = nullptr;
106 }
107 }
108 co_return;
109 }),
110 make_listener([&](const TextInputEvent& ev) -> fabric::task<> {
111 ZoneScopedN("Key Event");
112 auto _pev = this->win->profiling_ctx.scope_event("Key");
113 if (focused && focused->component_instance) {
114 if (focused->focused) {
115 INSTANCE_EV_HANDLER(focused)->dispatch_text_input(ev);
116 render_if_dirty(focused->component_instance.value());
117 } else {
118 focused = nullptr;
119 }
120 }
121 co_return;
122 }),
123 make_listener([&](const ButtonEvent& ev) -> fabric::task<> {
124 ZoneScopedN("Button Event");
125 auto _pev = this->win->profiling_ctx.scope_event("Button");
126
127 components::component_base_t* target = root.get();
128 components::component_base_t* specified_target = find_by_coords(ev.x, ev.y);
129 if (specified_target) {
130 target = specified_target;
131 }
132
133 auto dim = target->get_dimensional_relations();
134 auto& int_rel = target->get_internal_relations();
135 auto rel_x = ev.x - dimensions::get_value(int_rel.cx);
136 auto rel_y = ev.y - dimensions::get_value(int_rel.cy);
137
138 if (focused != target->state()) {
139 if (focused) {
140 focused->focused = false;
141 INSTANCE_EV_HANDLER(focused)->dispatch_focus_changed();
142 if (focused->is_text_input()) {
143 SDL_StopTextInput(win->native()->window);
144 }
145 if (focused->component_instance.has_value()) {
146 component_stylist->apply_style(focused->component_instance.value());
147 }
148 focused->mark_dirty();
149 focused = nullptr;
150 }
151 focused = target->state();
152 focused->focused = true;
153 INSTANCE_EV_HANDLER(focused)->dispatch_focus_changed();
154 if (focused->is_text_input()) {
155 SDL_StartTextInput(win->native()->window);
156 }
157 if (focused->component_instance.has_value()) {
158 component_stylist->apply_style(focused->component_instance.value());
159 }
160 focused->mark_dirty();
161 }
162
163 render_if_dirty(root);
164 if (ev.pressed) {
165 target->get_event_dispatcher()->dispatch_button_press((Button)ev.button, rel_x, rel_y);
166 } else {
167 target->get_event_dispatcher()->dispatch_button_release((Button)ev.button, rel_x, rel_y);
168 }
169 render_if_dirty(root);
170 co_return;
171 }),
172 make_listener([&](const ScrollEvent& ev) -> fabric::task<> {
173 ZoneScopedN("Scroll Event");
174 auto _pev = this->win->profiling_ctx.scope_event("Scroll");
175 components::component_base_t* target = root.get();
176 components::component_base_t* specified_target = find_by_coords(ev.x, ev.y);
177 if (specified_target) {
178 target = specified_target;
179 }
180
181 target->get_event_dispatcher()->dispatch_scroll(ev.dx, ev.dy);
182
183 render_if_dirty(root);
184 co_return;
185 }),
186 make_listener([&](const MotionEvent& ev) -> fabric::task<> {
187 auto _pev = this->win->profiling_ctx.scope_event("Motion");
188 ZoneScopedN("MotionEvent");
189
190 if (ev.x == dimensions::screen_measure{-1} && ev.y == dimensions::screen_measure{-1}) {
191 clear_hovering_flag(root_state, ev);
192 } else {
193 components::component_base_t* target = root.get();
194 components::component_base_t* specified_target = find_by_coords(ev.x, ev.y);
195 if (specified_target)
196 target = specified_target;
197
198 if (not set_hovering_flag(target->state().get(), ev, true)) {
199 auto& int_rel = target->get_internal_relations();
200 auto rel_x = ev.x - dimensions::get_value(int_rel.cx);
201 auto rel_y = ev.y - dimensions::get_value(int_rel.cy);
202 target->get_event_dispatcher()->dispatch_mouse_motion(rel_x, rel_y);
203 }
204 }
205
206 // Calling 'Drag' related event handlers
207 // cydui::components::Component* target = root;
208 // cydui::components::Component* specified_target =
209 // find_by_coords(root, it.x, it.y);
210 // if (specified_target)
211 // target = specified_target;
212 //
213 // if (it.dragging) {
214 // if (dragging_context.dragging) {
215 // int rel_x = it.x - (*target->state.unwrap())->dim.cx.val();
216 // int rel_y = it.y - (*target->state.unwrap())->dim.cy.val();
217 // dragging_context.dragging_item.drag_move(dragging_context.dragging_item, rel_x,
218 // rel_y); target->on_drag_motion(rel_x, rel_y);
219 // } else {
220 // int rel_x = it.x - (*target->state.unwrap())->dim.cx.val();
221 // int rel_y = it.y - (*target->state.unwrap())->dim.cy.val();
222 // target->state.let(_(components::ComponentState * , {
223 // for (auto &item : it->draggable_sources) {
224 // if (item.x - 10 <= rel_x && rel_x <= item.x + 10
225 // && item.y - 10 <= rel_y && rel_y <= item.y + 10) {
226 // dragging_context.dragging_item = item.start_drag(rel_x, rel_y);
227 // break;
228 // }
229 // }
230 // }));
231 // target->on_drag_start(rel_x, rel_y);
232 // dragging_context.dragging = true;
233 // }
234 //} else if (dragging_context.dragging) {
235 // int rel_x = it.x - (*target->state.unwrap())->dim.cx.val();
236 // int rel_y = it.y - (*target->state.unwrap())->dim.cy.val();
237 // dragging_context.dragging_item.drag_end(dragging_context.dragging_item, rel_x, rel_y);
238 // target->on_drag_finish(rel_x, rel_y);
239 // dragging_context.dragging = false;
240 // dragging_context.dragging_item = drag_n_drop::draggable_t {};
241 //}
242
243 render_if_dirty(root);
244 co_return;
245 }),
246 make_listener([&](const ResizeEvent& ev) -> fabric::task<> {
247 ZoneScopedN("Resize Event");
248 auto _pev = this->win->profiling_ctx.scope_event("Resize");
249
250 auto dim = root->get_dimensional_relations();
251 static const auto* width_field =
252 refl::type_info::from<components::style_base_t>()
253 .field_by_offset(offsetof(components::style_base_t, width))
254 .value();
255 static const auto* height_field =
256 refl::type_info::from<components::style_base_t>()
257 .field_by_offset(offsetof(components::style_base_t, height))
258 .value();
259 root->get_style_data().set_base_field_override(width_field, dimension_t{ev.w});
260 root->get_style_data().set_base_field_override(height_field, dimension_t{ev.h});
261 co_return;
262 // component_stylist->apply_style(root);
263
264 // update_dimensions();
265 // if (is_compositing.test()) {
266 // composite_is_outdated.test_and_set();
267 // return;
268 // }
269 // update_fragments();
270 // render();
271 }),
272 };
273
274 return listeners;
275 }
276} // namespace cydui
bool render_if_dirty(const components::component_base_t::sptr &c)
Definition layout.cppm:305
bool set_hovering_flag(components::component_state_t *state, const MotionEvent &ev, bool clear_children=true)
Definition layout.cppm:383
void update_component(const components::component_base_t::sptr &target)
Definition layout.cppm:284
void clear_hovering_flag(const components::component_state_ref &state, const MotionEvent &ev)
Definition layout.cppm:428
components::component_base_t * find_by_coords(dimensions::screen_measure x, dimensions::screen_measure y)
Definition layout.cppm:320
#define INSTANCE_EV_HANDLER(STATE_PTR)
const S & get_value(dimension< S > &dimension)
Definition api.cppm:24
quantify::quantity_t< screen::pixel, double > screen_measure
Definition _types.cppm:21
dimensions::dimension< dimensions::screen_measure > dimension_t
Definition @index.cppm:15