1use crate::events::{KeyboardEvent, MouseEvent, Propagation, TouchEvent};
22use crate::tree::{WidgetId, WidgetTree};
23
24#[derive(Clone, Debug, PartialEq)]
26pub enum DispatchEvent {
27 Mouse(MouseEvent),
29 Keyboard(KeyboardEvent),
31 Touch(TouchEvent),
33}
34
35#[derive(Clone, Copy, Debug, PartialEq, Eq)]
37pub enum Phase {
38 Capture,
40 Target,
42 Bubble,
44}
45
46enum RegistryEdit {
49 Add {
51 id: WidgetId,
53 phase: Phase,
55 handler: Box<dyn EventHandler>,
57 },
58 RemoveAll {
60 id: WidgetId,
62 },
63}
64
65pub struct HandlerCtx<'a> {
71 pub event: &'a DispatchEvent,
73 pub current: WidgetId,
75 pub phase: Phase,
77 pub target: WidgetId,
79 pending: &'a mut Vec<RegistryEdit>,
81}
82
83impl HandlerCtx<'_> {
84 pub fn add_handler(&mut self, id: WidgetId, phase: Phase, handler: Box<dyn EventHandler>) {
86 self.pending.push(RegistryEdit::Add { id, phase, handler });
87 }
88
89 pub fn remove_handlers(&mut self, id: WidgetId) {
95 self.pending.push(RegistryEdit::RemoveAll { id });
96 }
97}
98
99pub trait EventHandler {
101 fn handle(&mut self, ctx: &mut HandlerCtx<'_>) -> Propagation;
103}
104
105impl<F> EventHandler for F
107where
108 F: FnMut(&mut HandlerCtx<'_>) -> Propagation,
109{
110 fn handle(&mut self, ctx: &mut HandlerCtx<'_>) -> Propagation {
111 self(ctx)
112 }
113}
114
115#[derive(Default)]
117struct NodeHandlers {
118 capture: Vec<Box<dyn EventHandler>>,
119 bubble: Vec<Box<dyn EventHandler>>,
120}
121
122#[derive(Default)]
128pub struct EventDispatcher {
129 handlers: std::collections::HashMap<WidgetId, NodeHandlers>,
130}
131
132impl EventDispatcher {
133 pub fn new() -> Self {
135 Self::default()
136 }
137
138 pub fn on_capture(&mut self, id: WidgetId, handler: Box<dyn EventHandler>) {
140 self.handlers.entry(id).or_default().capture.push(handler);
141 }
142
143 pub fn on_bubble(&mut self, id: WidgetId, handler: Box<dyn EventHandler>) {
147 self.handlers.entry(id).or_default().bubble.push(handler);
148 }
149
150 pub fn clear_node(&mut self, id: WidgetId) -> bool {
152 self.handlers.remove(&id).is_some()
153 }
154
155 pub fn registered_nodes(&self) -> usize {
157 self.handlers.len()
158 }
159
160 fn path_to(tree: &WidgetTree, target: WidgetId) -> Vec<WidgetId> {
162 let mut path = Vec::new();
163 let mut cur = tree.get(target);
164 while let Some(node) = cur {
165 path.push(node.id);
166 cur = node.parent.and_then(|p| tree.get(p));
167 }
168 path.reverse(); path
170 }
171
172 pub fn dispatch(
179 &mut self,
180 tree: &WidgetTree,
181 target: WidgetId,
182 event: DispatchEvent,
183 ) -> Propagation {
184 let path = Self::path_to(tree, target);
185 if path.is_empty() {
186 return Propagation::CONTINUE;
187 }
188
189 let mut pending: Vec<RegistryEdit> = Vec::new();
190 let mut result = Propagation::CONTINUE;
191 let actual_target = path.last().copied().unwrap_or(target);
192
193 'capture: for &id in path.iter().take(path.len().saturating_sub(1)) {
195 let mut taken = match self.handlers.get_mut(&id) {
199 Some(h) if !h.capture.is_empty() => std::mem::take(&mut h.capture),
200 _ => continue,
201 };
202 for handler in taken.iter_mut() {
203 let mut ctx = HandlerCtx {
204 event: &event,
205 current: id,
206 phase: Phase::Capture,
207 target: actual_target,
208 pending: &mut pending,
209 };
210 let prop = handler.handle(&mut ctx);
211 result = result.merge(prop);
212 if prop.stop_propagation {
213 self.restore_capture(id, taken);
214 break 'capture;
215 }
216 }
217 self.restore_capture(id, taken);
218 }
219
220 if !result.stop_propagation {
221 'bubble: for (i, &id) in path.iter().rev().enumerate() {
223 let phase = if i == 0 { Phase::Target } else { Phase::Bubble };
224 let mut taken = match self.handlers.get_mut(&id) {
225 Some(h) if !h.bubble.is_empty() => std::mem::take(&mut h.bubble),
226 _ => continue,
227 };
228 for handler in taken.iter_mut() {
229 let mut ctx = HandlerCtx {
230 event: &event,
231 current: id,
232 phase,
233 target: actual_target,
234 pending: &mut pending,
235 };
236 let prop = handler.handle(&mut ctx);
237 result = result.merge(prop);
238 if prop.stop_propagation {
239 self.restore_bubble(id, taken);
240 break 'bubble;
241 }
242 }
243 self.restore_bubble(id, taken);
244 }
245 }
246
247 self.apply_pending(pending);
248 result
249 }
250
251 fn restore_capture(&mut self, id: WidgetId, mut taken: Vec<Box<dyn EventHandler>>) {
254 let slot = self.handlers.entry(id).or_default();
255 taken.append(&mut slot.capture);
259 slot.capture = taken;
260 }
261
262 fn restore_bubble(&mut self, id: WidgetId, mut taken: Vec<Box<dyn EventHandler>>) {
264 let slot = self.handlers.entry(id).or_default();
265 taken.append(&mut slot.bubble);
266 slot.bubble = taken;
267 }
268
269 fn apply_pending(&mut self, pending: Vec<RegistryEdit>) {
271 for edit in pending {
272 match edit {
273 RegistryEdit::Add { id, phase, handler } => match phase {
274 Phase::Capture => self.on_capture(id, handler),
275 Phase::Bubble | Phase::Target => self.on_bubble(id, handler),
276 },
277 RegistryEdit::RemoveAll { id } => {
278 self.handlers.remove(&id);
279 }
280 }
281 }
282 }
283}
284
285#[cfg(test)]
286mod tests {
287 use super::*;
288 use crate::events::{Modifiers, MouseButton};
289 use crate::geometry::{Point, Rect};
290 use std::cell::RefCell;
291 use std::rc::Rc;
292
293 fn mouse_down() -> DispatchEvent {
294 DispatchEvent::Mouse(MouseEvent::Down {
295 pos: Point::new(5.0, 5.0),
296 button: MouseButton::Left,
297 modifiers: Modifiers::NONE,
298 })
299 }
300
301 fn linear_tree() -> (WidgetTree, WidgetId, WidgetId) {
303 let mut t = WidgetTree::new(Rect::new(0.0, 0.0, 100.0, 100.0));
304 let a = t
305 .insert(WidgetId::ROOT, Rect::new(0.0, 0.0, 50.0, 50.0))
306 .expect("root");
307 let target = t.insert(a, Rect::new(0.0, 0.0, 20.0, 20.0)).expect("a");
308 (t, a, target)
309 }
310
311 #[test]
312 fn capture_then_bubble_ordering() {
313 let (tree, a, target) = linear_tree();
314 let log = Rc::new(RefCell::new(Vec::<String>::new()));
315 let mut d = EventDispatcher::new();
316
317 for (id, name) in [(WidgetId::ROOT, "root"), (a, "a"), (target, "target")] {
318 let log_c = Rc::clone(&log);
319 d.on_capture(
320 id,
321 Box::new(move |ctx: &mut HandlerCtx<'_>| {
322 log_c
323 .borrow_mut()
324 .push(format!("cap:{name}:{:?}", ctx.phase));
325 Propagation::CONTINUE
326 }),
327 );
328 let log_b = Rc::clone(&log);
329 d.on_bubble(
330 id,
331 Box::new(move |ctx: &mut HandlerCtx<'_>| {
332 log_b
333 .borrow_mut()
334 .push(format!("bub:{name}:{:?}", ctx.phase));
335 Propagation::CONTINUE
336 }),
337 );
338 }
339
340 d.dispatch(&tree, target, mouse_down());
341 let seen = log.borrow().clone();
342 assert_eq!(
343 seen,
344 vec![
345 "cap:root:Capture",
347 "cap:a:Capture",
348 "bub:target:Target",
350 "bub:a:Bubble",
351 "bub:root:Bubble",
352 ]
353 );
354 }
355
356 #[test]
357 fn stop_propagation_halts_bubble() {
358 let (tree, a, target) = linear_tree();
359 let log = Rc::new(RefCell::new(Vec::<String>::new()));
360 let mut d = EventDispatcher::new();
361
362 let log_t = Rc::clone(&log);
363 d.on_bubble(
364 target,
365 Box::new(move |_: &mut HandlerCtx<'_>| {
366 log_t.borrow_mut().push("target".to_string());
367 Propagation::stop() }),
369 );
370 let log_a = Rc::clone(&log);
371 d.on_bubble(
372 a,
373 Box::new(move |_: &mut HandlerCtx<'_>| {
374 log_a.borrow_mut().push("a".to_string());
375 Propagation::CONTINUE
376 }),
377 );
378
379 let result = d.dispatch(&tree, target, mouse_down());
380 assert!(result.stop_propagation);
381 assert_eq!(*log.borrow(), vec!["target".to_string()]);
382 }
383
384 #[test]
385 fn prevent_default_is_reported() {
386 let (tree, _a, target) = linear_tree();
387 let mut d = EventDispatcher::new();
388 d.on_bubble(
389 target,
390 Box::new(|_: &mut HandlerCtx<'_>| Propagation::prevent()),
391 );
392 let result = d.dispatch(&tree, target, mouse_down());
393 assert!(result.prevent_default);
394 assert!(!result.stop_propagation);
395 }
396
397 #[test]
398 fn handler_removal_during_dispatch_is_deferred() {
399 let (tree, _a, target) = linear_tree();
400 let count = Rc::new(RefCell::new(0u32));
401 let mut d = EventDispatcher::new();
402
403 let count_c = Rc::clone(&count);
406 d.on_bubble(
407 target,
408 Box::new(move |ctx: &mut HandlerCtx<'_>| {
409 *count_c.borrow_mut() += 1;
410 ctx.remove_handlers(target); Propagation::CONTINUE
412 }),
413 );
414
415 d.dispatch(&tree, target, mouse_down());
416 assert_eq!(*count.borrow(), 1);
417 assert_eq!(
418 d.registered_nodes(),
419 0,
420 "handler should be removed post-dispatch"
421 );
422
423 d.dispatch(&tree, target, mouse_down());
425 assert_eq!(*count.borrow(), 1);
426 }
427
428 #[test]
429 fn handler_add_during_dispatch_is_deferred() {
430 let (tree, _a, target) = linear_tree();
431 let fired = Rc::new(RefCell::new(Vec::<&'static str>::new()));
432 let mut d = EventDispatcher::new();
433
434 let fired_outer = Rc::clone(&fired);
435 let fired_inner = Rc::clone(&fired);
436 d.on_bubble(
437 target,
438 Box::new(move |ctx: &mut HandlerCtx<'_>| {
439 fired_outer.borrow_mut().push("outer");
440 let f = Rc::clone(&fired_inner);
441 ctx.add_handler(
443 target,
444 Phase::Bubble,
445 Box::new(move |_: &mut HandlerCtx<'_>| {
446 f.borrow_mut().push("inner");
447 Propagation::CONTINUE
448 }),
449 );
450 Propagation::CONTINUE
451 }),
452 );
453
454 d.dispatch(&tree, target, mouse_down());
455 assert_eq!(
456 *fired.borrow(),
457 vec!["outer"],
458 "added handler must not fire same dispatch"
459 );
460 d.dispatch(&tree, target, mouse_down());
461 assert_eq!(*fired.borrow(), vec!["outer", "outer", "inner"]);
463 }
464
465 #[test]
466 fn dispatch_to_missing_target_is_noop() {
467 let (tree, _a, _t) = linear_tree();
468 let mut d = EventDispatcher::new();
469 let prop = d.dispatch(&tree, WidgetId(9999), mouse_down());
470 assert_eq!(prop, Propagation::CONTINUE);
471 }
472}