ferroui_xaml_interactivity/events/handlers/
func_event_handler.rs1use crate::events::{AddEventHandlerCallback, IAddEventHandler};
4use crate::DisposableAction;
5use ferroui_base::data::core::WeakValue;
6use ferroui_base::interactivity::{CancelRoutedEventArgs, IRoutedEventArgs, RoutedEventArgs};
7use ferroui_base::metadata::from_markup_value;
8use ferroui_base::reactive::IDisposable;
9use ferroui_base::utilities::EventArgs;
10use ferroui_base::BoxedValue;
11use std::cell::RefCell;
12use std::rc::Rc;
13
14pub trait EventArgsValue {
17 fn to_event_args_value(&self) -> BoxedValue;
19}
20
21impl EventArgsValue for EventArgs {
22 fn to_event_args_value(&self) -> BoxedValue {
23 Rc::new(*self)
24 }
25}
26
27impl EventArgsValue for RoutedEventArgs {
29 fn to_event_args_value(&self) -> BoxedValue {
30 Rc::new(self.share())
31 }
32}
33
34impl EventArgsValue for CancelRoutedEventArgs {
36 fn to_event_args_value(&self) -> BoxedValue {
37 Rc::new(self.share())
38 }
39}
40
41pub type EventHandler<TEventArgs> = Rc<dyn Fn(Option<&BoxedValue>, &TEventArgs)>;
44
45pub struct FuncAddEventHandler<TTarget, TEventArgs, TToken = Rc<dyn IDisposable>> {
53 name: String,
54 add: Box<dyn Fn(&TTarget, EventHandler<TEventArgs>) -> TToken>,
55 remove: Rc<dyn Fn(&TTarget, TToken)>,
56}
57
58impl<TTarget, TEventArgs, TToken> FuncAddEventHandler<TTarget, TEventArgs, TToken>
59where
60 TTarget: Clone + 'static,
61 TEventArgs: EventArgsValue + 'static,
62 TToken: 'static,
63{
64 pub fn new(
67 name: &str,
68 add: impl Fn(&TTarget, EventHandler<TEventArgs>) -> TToken + 'static,
69 remove: impl Fn(&TTarget, TToken) + 'static,
70 ) -> Self {
71 Self { name: name.to_string(), add: Box::new(add), remove: Rc::new(remove) }
72 }
73
74 fn target_of(source: &BoxedValue) -> Option<TTarget> {
76 from_markup_value::<TTarget>(&Some(source.clone()))
77 }
78}
79
80impl<TTarget, TEventArgs, TToken> IAddEventHandler for FuncAddEventHandler<TTarget, TEventArgs, TToken>
81where
82 TTarget: Clone + 'static,
83 TEventArgs: EventArgsValue + 'static,
84 TToken: 'static,
85{
86 fn matches(&self, source: &BoxedValue, event_name: &str) -> bool {
87 Self::target_of(source).is_some() && event_name == self.name
88 }
89
90 fn add_handler(
91 &self,
92 source: &BoxedValue,
93 event_name: &str,
94 handler: AddEventHandlerCallback,
95 ) -> Option<Rc<dyn IDisposable>> {
96 let target = Self::target_of(source)?;
97 if event_name != self.name {
98 return None;
99 }
100
101 let event_handler: EventHandler<TEventArgs> =
102 Rc::new(move |sender: Option<&BoxedValue>, e: &TEventArgs| handler(sender, &e.to_event_args_value()));
103 let token = (self.add)(&target, event_handler);
104
105 let source = WeakValue::new(source);
108 let token = RefCell::new(Some(token));
109 let remove = self.remove.clone();
110 Some(DisposableAction::create(move || {
111 let Some(token) = token.borrow_mut().take() else {
112 return;
113 };
114 if let Some(target) = source.upgrade().and_then(|source| Self::target_of(&source)) {
115 remove(&target, token);
116 }
117 }))
118 }
119}