Skip to main content

ferroui_xaml_interactivity/events/
add_event_handler_registry.rs

1//! Port of `Events/AddEventHandlerRegistry.cs`.
2
3use super::handlers::{FlyoutEventHandler, FuncAddEventHandler};
4use super::{AddEventHandlerCallback, IAddEventHandler};
5use ferroui_base::interactivity::{CancelRoutedEventArgs, RoutedEventArgs, RoutedEventHandlerToken};
6use ferroui_base::reactive::IDisposable;
7use ferroui_base::{BoxedValue, Ref};
8use ferroui_controls::{Button, Control, MenuItem, ToolTip};
9use std::cell::RefCell;
10use std::rc::Rc;
11
12/// A registry for adding event handlers to various controls: the events an event trigger
13/// subscribes by name before it looks for the event in the metadata of the source.
14///
15/// The registry belongs to the thread (handlers hold objects of the thread).
16pub struct AddEventHandlerRegistry;
17
18ferroui_base::ferro_thread_local! {
19    static ADD_EVENT_HANDLERS: RefCell<Vec<Rc<dyn IAddEventHandler>>> = RefCell::new(AddEventHandlerRegistry::default_handlers());
20}
21
22impl AddEventHandlerRegistry {
23    /// The handlers the static constructor of the reference registers.
24    fn default_handlers() -> Vec<Rc<dyn IAddEventHandler>> {
25        let mut handlers: Vec<Rc<dyn IAddEventHandler>> = Vec::new();
26
27        // handlers.push(Rc::new(ButtonClickEventHandler));
28
29        handlers.push(Rc::new(FuncAddEventHandler::<Ref<Button>, RoutedEventArgs, RoutedEventHandlerToken>::new(
30            "Click",
31            |o, h| o.click(move |sender, e| h(Some(&(Rc::new(sender.to_ref()) as BoxedValue)), e)),
32            |o, h| {
33                o.remove_handler(Button::click_event(), h);
34            },
35        )));
36
37        handlers.push(Rc::new(FuncAddEventHandler::<Ref<MenuItem>, RoutedEventArgs, RoutedEventHandlerToken>::new(
38            "Click",
39            |o, h| o.click(move |sender, e| h(Some(&(Rc::new(sender.to_ref()) as BoxedValue)), e)),
40            |o, h| {
41                o.remove_handler(MenuItem::click_event(), h);
42            },
43        )));
44
45        handlers.push(Rc::new(FlyoutEventHandler));
46
47        handlers.push(Rc::new(FuncAddEventHandler::<Ref<Control>, CancelRoutedEventArgs, RoutedEventHandlerToken>::new(
48            "ToolTipOpening",
49            |o, h| ToolTip::add_tool_tip_opening_handler(o, move |sender, e| h(Some(&(Rc::new(sender.to_ref()) as BoxedValue)), e)),
50            |o, h| ToolTip::remove_tool_tip_opening_handler(o, h),
51        )));
52
53        handlers.push(Rc::new(FuncAddEventHandler::<Ref<Control>, RoutedEventArgs, RoutedEventHandlerToken>::new(
54            "ToolTipClosing",
55            |o, h| ToolTip::add_tool_tip_closing_handler(o, move |sender, e| h(Some(&(Rc::new(sender.to_ref()) as BoxedValue)), e)),
56            |o, h| ToolTip::remove_tool_tip_closing_handler(o, h),
57        )));
58
59        handlers
60    }
61
62    /// Registers an event handler.
63    pub fn register(add_event_handler: Rc<dyn IAddEventHandler>) {
64        ADD_EVENT_HANDLERS.with(|handlers| {
65            let mut handlers = handlers.borrow_mut();
66            if !handlers.iter().any(|handler| Rc::ptr_eq(handler, &add_event_handler)) {
67                handlers.push(add_event_handler);
68            }
69        });
70    }
71
72    /// Unregisters an event handler.
73    pub fn unregister(add_event_handler: &Rc<dyn IAddEventHandler>) {
74        ADD_EVENT_HANDLERS.with(|handlers| {
75            handlers.borrow_mut().retain(|handler| !Rc::ptr_eq(handler, add_event_handler));
76        });
77    }
78
79    /// Subscribes `handler` to the event `event_name` of `source` through the first registered
80    /// handler that matches them; `None` when none does.
81    pub fn try_register_event_handler(
82        source: &BoxedValue,
83        event_name: &str,
84        handler: AddEventHandlerCallback,
85    ) -> Option<Rc<dyn IDisposable>> {
86        let add_event_handler = ADD_EVENT_HANDLERS.with(|handlers| {
87            handlers.borrow().iter().find(|handler| handler.matches(source, event_name)).cloned()
88        });
89
90        add_event_handler?.add_handler(source, event_name, handler)
91    }
92}