1use crate::Document;
2use apace_traits::events::{
3 ApacePointerEvent, ApacePointerId, DomEvent, DomEventData, EventState, Point, PointerCoords,
4 UiEvent,
5};
6use apace_traits::node_id::NodeId;
7use std::collections::VecDeque;
8
9pub trait EventHandler {
10 fn handle_event(
11 &mut self,
12 chain: &[NodeId],
13 event: &mut DomEvent,
14 doc: &mut dyn Document,
15 event_state: &mut EventState,
16 );
17}
18
19pub struct NoopEventHandler;
20impl EventHandler for NoopEventHandler {
21 fn handle_event(
22 &mut self,
23 _chain: &[NodeId],
24 _event: &mut DomEvent,
25 _doc: &mut dyn Document,
26 _event_state: &mut EventState,
27 ) {
28 }
30}
31
32pub struct EventDriver<'doc, Handler: EventHandler> {
33 doc: &'doc mut dyn Document,
34 handler: Handler,
35 queue: VecDeque<DomEvent>,
36}
37
38impl<'doc, Handler: EventHandler> EventDriver<'doc, Handler> {
39 pub fn new(doc: &'doc mut dyn Document, handler: Handler) -> Self {
40 EventDriver {
41 doc,
42 handler,
43 queue: VecDeque::with_capacity(4),
44 }
45 }
46
47 pub fn handle_pointer_move(&mut self, event: &ApacePointerEvent) -> Option<NodeId> {
48 let mut doc = self.doc.inner_mut();
49
50 let prev_hover_node_id = doc.hover_node_id;
51 let changed = doc.set_hover_to(event.page_x(), event.page_y());
52 let hover_node_id = doc.hover_node_id;
53
54 drop(doc);
55
56 if !changed {
57 return prev_hover_node_id;
58 }
59
60 self.dispatch_hover_change(prev_hover_node_id, hover_node_id, event);
61
62 hover_node_id
63 }
64
65 pub fn handle_pointer_leave(&mut self, event: &ApacePointerEvent) {
68 let mut doc = self.doc.inner_mut();
69 let prev_hover_node_id = doc.hover_node_id;
70 doc.clear_hover();
71 drop(doc);
72
73 self.dispatch_hover_change(prev_hover_node_id, None, event);
74 }
75
76 fn dispatch_hover_change(
77 &mut self,
78 prev_hover_node_id: Option<NodeId>,
79 hover_node_id: Option<NodeId>,
80 event: &ApacePointerEvent,
81 ) {
82 let doc = self.doc.inner();
83 let mut old_chain = prev_hover_node_id
84 .map(|id| doc.node_chain(id))
85 .unwrap_or_default();
86 let mut new_chain = hover_node_id
87 .map(|id| doc.node_chain(id))
88 .unwrap_or_default();
89 old_chain.reverse();
90 new_chain.reverse();
91
92 let old_len = old_chain.len();
94 let new_len = new_chain.len();
95
96 let first_difference_index = old_chain
97 .iter()
98 .zip(&new_chain)
99 .position(|(old, new)| old != new)
100 .unwrap_or_else(|| old_len.min(new_len));
101
102 drop(doc);
103
104 let is_mouse = event.is_mouse();
105
106 if let Some(target) = prev_hover_node_id {
107 self.handle_dom_event(DomEvent::new(
108 target,
109 DomEventData::PointerOut(event.clone()),
110 ));
111 if is_mouse {
112 self.handle_dom_event(DomEvent::new(target, DomEventData::MouseOut(event.clone())));
113 }
114
115 for node_id in old_chain
117 .get(first_difference_index..)
118 .unwrap_or(&[])
119 .iter()
120 {
121 self.handle_dom_event(DomEvent::new(
122 *node_id,
123 DomEventData::PointerLeave(event.clone()),
124 ));
125 if is_mouse {
126 self.handle_dom_event(DomEvent::new(
127 *node_id,
128 DomEventData::MouseLeave(event.clone()),
129 ));
130 }
131 }
132 }
133
134 if let Some(target) = hover_node_id {
135 self.handle_dom_event(DomEvent::new(
136 target,
137 DomEventData::PointerOver(event.clone()),
138 ));
139
140 if is_mouse {
141 self.handle_dom_event(DomEvent::new(
142 target,
143 DomEventData::MouseOver(event.clone()),
144 ));
145 }
146
147 for node_id in new_chain
149 .get(first_difference_index..)
150 .unwrap_or(&[])
151 .iter()
152 {
153 self.handle_dom_event(DomEvent::new(
154 *node_id,
155 DomEventData::PointerEnter(event.clone()),
156 ));
157
158 if is_mouse {
159 self.handle_dom_event(DomEvent::new(
160 *node_id,
161 DomEventData::MouseEnter(event.clone()),
162 ));
163 }
164 }
165 }
166 }
167
168 pub fn handle_ui_event(&mut self, event: UiEvent) {
169 let doc = self.doc.inner();
170
171 let mut hover_end_event = None;
173 let mut hover_node_id = doc.hover_node_id;
174 let focussed_node_id = doc.focus_node_id;
175 let prev_hover = doc.hover_state();
176 drop(doc);
177
178 let is_leave = matches!(event, UiEvent::PointerLeave(_));
180
181 match &event {
183 UiEvent::PointerMove(event) => {
184 hover_node_id = self.handle_pointer_move(event);
185 }
186 UiEvent::PointerDown(event) => {
187 hover_node_id = self.handle_pointer_move(event);
188 let mut doc = self.doc.inner_mut();
189 doc.active_node();
190 doc.set_mousedown_node_id(hover_node_id);
191 }
192 UiEvent::PointerUp(event) => {
193 hover_node_id = self.handle_pointer_move(event);
194 let mut doc = self.doc.inner_mut();
195 doc.unactive_node();
196
197 if event.is_primary && matches!(event.id, ApacePointerId::Finger(_)) {
198 hover_end_event = Some(event.clone());
199 }
200 }
201 UiEvent::PointerCancel(event) => {
202 hover_node_id = self.handle_pointer_move(event);
203 let mut doc = self.doc.inner_mut();
204 doc.unactive_node();
205
206 if event.is_primary && matches!(event.id, ApacePointerId::Finger(_)) {
207 hover_end_event = Some(event.clone());
208 }
209 }
210 UiEvent::PointerLeave(event) => {
211 self.handle_pointer_leave(event);
212 hover_node_id = None;
213 }
214 _ => {}
215 };
216
217 let target = match event {
218 UiEvent::PointerMove(_) => hover_node_id,
219 UiEvent::PointerUp(_) => hover_node_id,
220 UiEvent::PointerDown(_) => hover_node_id,
221 UiEvent::PointerCancel(_) => hover_node_id,
222 UiEvent::PointerLeave(_) => hover_node_id,
223 UiEvent::Wheel(_) => hover_node_id,
224 UiEvent::KeyUp(_) => focussed_node_id,
225 UiEvent::KeyDown(_) => focussed_node_id,
226 UiEvent::Ime(_) => focussed_node_id,
227 UiEvent::AppleStandardKeybinding(_) => focussed_node_id,
228 };
229 let Some(target) = target.or_else(|| self.doc.inner().try_root_element().map(|el| el.id))
232 else {
233 return;
234 };
235
236 match event {
237 UiEvent::PointerMove(data) => {
238 self.handle_pointer_event(
239 target,
240 data,
241 DomEventData::PointerMove,
242 Some(DomEventData::MouseMove),
243 DomEventData::TouchMove,
244 );
245 }
246 UiEvent::PointerUp(data) => {
247 self.handle_pointer_event(
248 target,
249 data,
250 DomEventData::PointerUp,
251 Some(DomEventData::MouseUp),
252 DomEventData::TouchEnd,
253 );
254 }
255 UiEvent::PointerDown(data) => {
256 self.handle_pointer_event(
257 target,
258 data,
259 DomEventData::PointerDown,
260 Some(DomEventData::MouseDown),
261 DomEventData::TouchStart,
262 );
263 }
264 UiEvent::PointerCancel(data) => {
265 self.handle_pointer_event(
268 target,
269 data,
270 DomEventData::PointerCancel,
271 None::<fn(ApacePointerEvent) -> DomEventData>,
272 DomEventData::TouchCancel,
273 );
274 }
275 UiEvent::PointerLeave(_) => {}
277 UiEvent::Wheel(data) => {
278 self.handle_dom_event(DomEvent::new(target, DomEventData::Wheel(data)))
279 }
280 UiEvent::KeyUp(data) => {
281 self.handle_dom_event(DomEvent::new(target, DomEventData::KeyUp(data)))
282 }
283 UiEvent::KeyDown(data) => {
284 self.handle_dom_event(DomEvent::new(target, DomEventData::KeyDown(data)))
285 }
286 UiEvent::Ime(data) => {
287 self.handle_dom_event(DomEvent::new(target, DomEventData::Ime(data)))
288 }
289 UiEvent::AppleStandardKeybinding(data) => {
290 let mut dom_event =
291 DomEvent::new(target, DomEventData::AppleStandardKeybinding(data));
292 self.run_default_action(&mut dom_event);
293 self.process_queue();
294 }
295 };
296
297 if let Some(event) = hover_end_event {
299 self.handle_pointer_leave(&event);
300 }
301
302 let doc = self.doc.inner();
305 if !is_leave && doc.hover_state() != prev_hover {
306 doc.update_cursor();
307 }
308 }
309
310 pub fn handle_dom_event(&mut self, event: DomEvent) {
311 self.queue.push_back(event);
312 self.process_queue();
313 }
314
315 fn handle_pointer_event(
316 &mut self,
317 target: NodeId,
318 data: ApacePointerEvent,
319 make_ptr_data: impl FnOnce(ApacePointerEvent) -> DomEventData,
320 make_mouse_data: Option<impl FnOnce(ApacePointerEvent) -> DomEventData>,
321 make_touch_data: impl FnOnce(ApacePointerEvent) -> DomEventData,
322 ) {
323 let mut ptr_event = DomEvent::new(target, make_ptr_data(data.clone()));
324 let mut event_state = EventState::default();
325 event_state = self.run_handler_event(&mut ptr_event, event_state);
326
327 if !event_state.is_cancelled() {
335 if data.is_mouse() {
336 if let Some(make_mouse_data) = make_mouse_data {
337 let mut mouse_event = DomEvent::new(target, make_mouse_data(data));
338 event_state = self.run_handler_event(&mut mouse_event, event_state);
339 }
340 } else if data.is_finger() || data.is_pen() {
341 let mut touch_event = DomEvent::new(target, make_touch_data(data));
342 event_state = self.run_handler_event(&mut touch_event, event_state);
343 }
344 }
345
346 if !event_state.is_cancelled() {
347 self.run_default_action(&mut ptr_event);
348 }
349 self.process_queue();
350 }
351
352 fn process_queue(&mut self) {
353 while let Some(mut event) = self.queue.pop_front() {
354 let event_state = self.run_handler_event(&mut event, EventState::default());
355 if !event_state.is_cancelled() {
356 self.run_default_action(&mut event);
357 }
358 }
359 }
360
361 fn adjust_element_coords(
362 &self,
363 target: NodeId,
364 coords: &PointerCoords,
365 element: &mut Point<f32>,
366 ) {
367 if let Some(rect) = self.doc.inner().get_client_bounding_rect(target) {
368 element.x = coords.client_x - rect.x as f32;
369 element.y = coords.client_y - rect.y as f32;
370 }
371 }
372
373 fn run_handler_event(
374 &mut self,
375 event: &mut DomEvent,
376 initial_event_state: EventState,
377 ) -> EventState {
378 let chain = if event.bubbles {
379 let doc = self.doc.inner();
380 doc.node_chain(event.target)
381 } else {
382 vec![event.target]
383 };
384
385 match &mut event.data {
386 DomEventData::PointerMove(data)
387 | DomEventData::PointerDown(data)
388 | DomEventData::PointerUp(data)
389 | DomEventData::PointerCancel(data)
390 | DomEventData::PointerEnter(data)
391 | DomEventData::PointerLeave(data)
392 | DomEventData::PointerOver(data)
393 | DomEventData::PointerOut(data)
394 | DomEventData::MouseMove(data)
395 | DomEventData::MouseDown(data)
396 | DomEventData::MouseUp(data)
397 | DomEventData::MouseEnter(data)
398 | DomEventData::MouseLeave(data)
399 | DomEventData::MouseOver(data)
400 | DomEventData::MouseOut(data)
401 | DomEventData::TouchStart(data)
402 | DomEventData::TouchEnd(data)
403 | DomEventData::TouchMove(data)
404 | DomEventData::TouchCancel(data)
405 | DomEventData::Click(data)
406 | DomEventData::ContextMenu(data)
407 | DomEventData::DoubleClick(data) => {
408 self.adjust_element_coords(event.target, &data.coords, &mut data.element)
409 }
410 DomEventData::Wheel(data) => {
411 self.adjust_element_coords(event.target, &data.coords, &mut data.element)
412 }
413 _ => {}
414 }
415
416 let mut event_state = initial_event_state;
417 self.handler
418 .handle_event(&chain, event, self.doc, &mut event_state);
419
420 event_state
421 }
422
423 fn run_default_action(&mut self, event: &mut DomEvent) {
424 let mut doc = self.doc.inner_mut();
425 doc.handle_dom_event(event, |new_evt| self.queue.push_back(new_evt));
426 }
427}