1pub mod dispatcher;
4
5use std::fmt;
6use std::sync::{Arc, Mutex};
7
8pub use dispatcher::ComponentEventDispatcher;
9
10#[derive(Debug, Clone, PartialEq)]
12pub enum Event {
13 Click { x: f64, y: f64, button: MouseButton },
15 MouseMove { x: f64, y: f64 },
17 MouseDown { x: f64, y: f64, button: MouseButton },
19 MouseUp { x: f64, y: f64, button: MouseButton },
21 MouseEnter,
23 MouseLeave,
25 KeyPress { key: String, modifiers: Modifiers },
27 KeyDown { key: String, modifiers: Modifiers },
29 KeyUp { key: String, modifiers: Modifiers },
31 Input { value: String },
33 Change { value: String },
35 Focus,
37 Blur,
39 Submit,
41 Touch {
43 x: f64,
44 y: f64,
45 touch_type: TouchType,
46 },
47 Scroll { x: f64, y: f64 },
49 Resize { width: u32, height: u32 },
51 Custom { name: String, data: String },
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub enum MouseButton {
58 Left,
59 Right,
60 Middle,
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum TouchType {
66 Start,
67 Move,
68 End,
69 Cancel,
70}
71
72#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
74pub struct Modifiers {
75 pub ctrl: bool,
76 pub alt: bool,
77 pub shift: bool,
78 pub meta: bool,
79}
80
81pub trait EventHandler: Send + Sync {
83 fn handle(&self, event: Event);
85}
86
87pub struct FnHandler<F>
89where
90 F: Fn(Event) + Send + Sync,
91{
92 handler: F,
93}
94
95impl<F> FnHandler<F>
96where
97 F: Fn(Event) + Send + Sync,
98{
99 pub fn new(handler: F) -> Self {
100 Self { handler }
101 }
102}
103
104impl<F> EventHandler for FnHandler<F>
105where
106 F: Fn(Event) + Send + Sync,
107{
108 fn handle(&self, event: Event) {
109 (self.handler)(event);
110 }
111}
112
113impl fmt::Display for Event {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 match self {
116 Event::Click { x, y, button } => write!(f, "Click({}, {}, {:?})", x, y, button),
117 Event::MouseMove { x, y } => write!(f, "MouseMove({}, {})", x, y),
118 Event::MouseDown { x, y, button } => write!(f, "MouseDown({}, {}, {:?})", x, y, button),
119 Event::MouseUp { x, y, button } => write!(f, "MouseUp({}, {}, {:?})", x, y, button),
120 Event::MouseEnter => write!(f, "MouseEnter"),
121 Event::MouseLeave => write!(f, "MouseLeave"),
122 Event::KeyPress { key, .. } => write!(f, "KeyPress({})", key),
123 Event::KeyDown { key, .. } => write!(f, "KeyDown({})", key),
124 Event::KeyUp { key, .. } => write!(f, "KeyUp({})", key),
125 Event::Input { value } => write!(f, "Input({})", value),
126 Event::Change { value } => write!(f, "Change({})", value),
127 Event::Focus => write!(f, "Focus"),
128 Event::Blur => write!(f, "Blur"),
129 Event::Submit => write!(f, "Submit"),
130 Event::Touch { x, y, touch_type } => write!(f, "Touch({}, {}, {:?})", x, y, touch_type),
131 Event::Scroll { x, y } => write!(f, "Scroll({}, {})", x, y),
132 Event::Resize { width, height } => write!(f, "Resize({}, {})", width, height),
133 Event::Custom { name, .. } => write!(f, "Custom({})", name),
134 }
135 }
136}
137
138#[derive(Debug, Clone)]
140pub struct EventContext {
141 pub target: String,
143 pub current_target: String,
145 pub phase: EventPhase,
147 stopped: Arc<Mutex<bool>>,
149 immediate_stopped: Arc<Mutex<bool>>,
151 default_prevented: Arc<Mutex<bool>>,
153}
154
155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
157pub enum EventPhase {
158 Capturing,
160 AtTarget,
162 Bubbling,
164}
165
166impl EventContext {
167 pub fn new(target: String) -> Self {
169 Self {
170 target: target.clone(),
171 current_target: target,
172 phase: EventPhase::AtTarget,
173 stopped: Arc::new(Mutex::new(false)),
174 immediate_stopped: Arc::new(Mutex::new(false)),
175 default_prevented: Arc::new(Mutex::new(false)),
176 }
177 }
178
179 pub fn stop_propagation(&self) {
181 *self.stopped.lock().unwrap() = true;
182 }
183
184 pub fn stop_immediate_propagation(&self) {
186 *self.immediate_stopped.lock().unwrap() = true;
187 }
188
189 pub fn prevent_default(&self) {
191 *self.default_prevented.lock().unwrap() = true;
192 }
193
194 pub fn is_propagation_stopped(&self) -> bool {
196 *self.stopped.lock().unwrap()
197 }
198
199 pub fn is_immediate_propagation_stopped(&self) -> bool {
201 *self.immediate_stopped.lock().unwrap()
202 }
203
204 pub fn is_default_prevented(&self) -> bool {
206 *self.default_prevented.lock().unwrap()
207 }
208}
209
210pub struct EventListener {
212 pub event_type: String,
214 #[allow(clippy::type_complexity)]
216 pub handler: Arc<dyn Fn(&Event, &EventContext) + Send + Sync>,
217 pub capture: bool,
219}
220
221impl EventListener {
222 pub fn new<F>(event_type: String, handler: F, capture: bool) -> Self
224 where
225 F: Fn(&Event, &EventContext) + Send + Sync + 'static,
226 {
227 Self {
228 event_type,
229 handler: Arc::new(handler),
230 capture,
231 }
232 }
233
234 pub fn invoke(&self, event: &Event, context: &EventContext) {
236 (self.handler)(event, context);
237 }
238}
239
240pub struct EventDispatcher {
242 listeners: Arc<Mutex<std::collections::HashMap<String, Vec<EventListener>>>>,
244}
245
246impl EventDispatcher {
247 pub fn new() -> Self {
249 Self {
250 listeners: Arc::new(Mutex::new(std::collections::HashMap::new())),
251 }
252 }
253
254 pub fn add_listener(&self, element_id: String, listener: EventListener) {
256 let mut listeners = self.listeners.lock().unwrap();
257 listeners.entry(element_id).or_default().push(listener);
258 }
259
260 pub fn remove_listeners(&self, element_id: &str) {
262 let mut listeners = self.listeners.lock().unwrap();
263 listeners.remove(element_id);
264 }
265
266 pub fn dispatch(&self, event: &Event, target_id: String, path: Vec<String>) {
268 let context = EventContext::new(target_id.clone());
269
270 let mut ctx = context.clone();
272 ctx.phase = EventPhase::Capturing;
273 for element_id in path.iter().rev() {
274 if ctx.is_propagation_stopped() {
275 break;
276 }
277 ctx.current_target = element_id.clone();
278 self.invoke_listeners(element_id, event, &ctx, true);
279 }
280
281 if !context.is_propagation_stopped() {
283 let mut ctx = context.clone();
284 ctx.phase = EventPhase::AtTarget;
285 ctx.current_target = target_id.clone();
286 self.invoke_listeners(&target_id, event, &ctx, false);
287 }
288
289 if !context.is_propagation_stopped() {
291 let mut ctx = context.clone();
292 ctx.phase = EventPhase::Bubbling;
293 for element_id in path.iter() {
294 if ctx.is_propagation_stopped() {
295 break;
296 }
297 ctx.current_target = element_id.clone();
298 self.invoke_listeners(element_id, event, &ctx, false);
299 }
300 }
301 }
302
303 fn invoke_listeners(
304 &self,
305 element_id: &str,
306 event: &Event,
307 context: &EventContext,
308 capture_phase: bool,
309 ) {
310 let listeners = self.listeners.lock().unwrap();
311 if let Some(element_listeners) = listeners.get(element_id) {
312 for listener in element_listeners {
313 if context.is_immediate_propagation_stopped() {
314 break;
315 }
316 if listener.capture == capture_phase {
317 listener.invoke(event, context);
318 }
319 }
320 }
321 }
322}
323
324impl Default for EventDispatcher {
325 fn default() -> Self {
326 Self::new()
327 }
328}
329
330#[cfg(test)]
331mod tests {
332 use super::*;
333
334 #[test]
335 fn test_event_display() {
336 let event = Event::Click {
337 x: 10.0,
338 y: 20.0,
339 button: MouseButton::Left,
340 };
341 assert!(event.to_string().contains("Click"));
342 }
343
344 #[test]
345 fn test_modifiers_default() {
346 let mods = Modifiers::default();
347 assert!(!mods.ctrl);
348 assert!(!mods.alt);
349 assert!(!mods.shift);
350 assert!(!mods.meta);
351 }
352
353 #[test]
354 fn test_fn_handler() {
355 let called = std::sync::Arc::new(std::sync::Mutex::new(false));
356 let called_clone = called.clone();
357
358 let handler = FnHandler::new(move |_event| {
359 *called_clone.lock().unwrap() = true;
360 });
361
362 handler.handle(Event::Submit);
363 assert!(*called.lock().unwrap());
364 }
365
366 #[test]
367 fn test_event_context_stop_propagation() {
368 let ctx = EventContext::new("button".to_string());
369 assert!(!ctx.is_propagation_stopped());
370
371 ctx.stop_propagation();
372 assert!(ctx.is_propagation_stopped());
373 }
374
375 #[test]
376 fn test_event_context_prevent_default() {
377 let ctx = EventContext::new("link".to_string());
378 assert!(!ctx.is_default_prevented());
379
380 ctx.prevent_default();
381 assert!(ctx.is_default_prevented());
382 }
383
384 #[test]
385 fn test_event_dispatcher_add_listener() {
386 let dispatcher = EventDispatcher::new();
387 let called = std::sync::Arc::new(std::sync::Mutex::new(0));
388 let called_clone = called.clone();
389
390 let listener = EventListener::new(
391 "click".to_string(),
392 move |_event, _ctx| {
393 *called_clone.lock().unwrap() += 1;
394 },
395 false,
396 );
397
398 dispatcher.add_listener("button".to_string(), listener);
399
400 let event = Event::Click {
401 x: 10.0,
402 y: 20.0,
403 button: MouseButton::Left,
404 };
405 dispatcher.dispatch(&event, "button".to_string(), vec!["root".to_string()]);
406
407 assert_eq!(*called.lock().unwrap(), 1);
408 }
409
410 #[test]
411 fn test_event_propagation_bubbling() {
412 let dispatcher = EventDispatcher::new();
413 let events = std::sync::Arc::new(std::sync::Mutex::new(Vec::new()));
414
415 let events_clone = events.clone();
417 let parent_listener = EventListener::new(
418 "click".to_string(),
419 move |_event, ctx| {
420 events_clone
421 .lock()
422 .unwrap()
423 .push(ctx.current_target.clone());
424 },
425 false,
426 );
427 dispatcher.add_listener("parent".to_string(), parent_listener);
428
429 let events_clone = events.clone();
431 let child_listener = EventListener::new(
432 "click".to_string(),
433 move |_event, ctx| {
434 events_clone
435 .lock()
436 .unwrap()
437 .push(ctx.current_target.clone());
438 },
439 false,
440 );
441 dispatcher.add_listener("child".to_string(), child_listener);
442
443 let event = Event::Click {
444 x: 10.0,
445 y: 20.0,
446 button: MouseButton::Left,
447 };
448
449 dispatcher.dispatch(&event, "child".to_string(), vec!["parent".to_string()]);
451
452 let recorded_events = events.lock().unwrap();
453 assert_eq!(recorded_events.len(), 2);
454 assert_eq!(recorded_events[0], "child"); assert_eq!(recorded_events[1], "parent"); }
457
458 #[test]
459 fn test_event_stop_propagation() {
460 let dispatcher = EventDispatcher::new();
461 let events = std::sync::Arc::new(std::sync::Mutex::new(Vec::new()));
462
463 let events_clone = events.clone();
465 let parent_listener = EventListener::new(
466 "click".to_string(),
467 move |_event, ctx| {
468 events_clone
469 .lock()
470 .unwrap()
471 .push(ctx.current_target.clone());
472 },
473 false,
474 );
475 dispatcher.add_listener("parent".to_string(), parent_listener);
476
477 let events_clone = events.clone();
479 let child_listener = EventListener::new(
480 "click".to_string(),
481 move |_event, ctx| {
482 events_clone
483 .lock()
484 .unwrap()
485 .push(ctx.current_target.clone());
486 ctx.stop_propagation();
487 },
488 false,
489 );
490 dispatcher.add_listener("child".to_string(), child_listener);
491
492 let event = Event::Click {
493 x: 10.0,
494 y: 20.0,
495 button: MouseButton::Left,
496 };
497
498 dispatcher.dispatch(&event, "child".to_string(), vec!["parent".to_string()]);
499
500 let recorded_events = events.lock().unwrap();
501 assert_eq!(recorded_events.len(), 1); assert_eq!(recorded_events[0], "child");
503 }
504}