Skip to main content

ferroui_base/interactivity/
interactive_extensions.rs

1//! Extension methods for [`Interactive`].
2
3use super::{IRoutedEventArgs, Interactive, RoutedEvent, RoutingStrategies};
4use crate::reactive::{Disposable, IDisposable, IObservable, Observable};
5use crate::Ref;
6use std::rc::Rc;
7
8impl Interactive {
9    /// Adds a handler for a routed event (direct and bubble routes,
10    /// unhandled events) and returns a disposable that removes the handler
11    /// when disposed.
12    pub fn add_disposable_handler<TEventArgs: IRoutedEventArgs>(
13        &self,
14        routed_event: &RoutedEvent<TEventArgs>,
15        handler: impl Fn(&Interactive, &TEventArgs) + 'static,
16    ) -> Rc<dyn IDisposable> {
17        self.add_disposable_handler_with(routed_event, handler, Self::DEFAULT_ROUTES, false)
18    }
19
20    /// Adds a handler for a routed event and returns a disposable that
21    /// removes the handler when disposed.
22    pub fn add_disposable_handler_with<TEventArgs: IRoutedEventArgs>(
23        &self,
24        routed_event: &RoutedEvent<TEventArgs>,
25        handler: impl Fn(&Interactive, &TEventArgs) + 'static,
26        routes: RoutingStrategies,
27        handled_events_too: bool,
28    ) -> Rc<dyn IDisposable> {
29        let token = self.add_handler_with(routed_event, handler, routes, handled_events_too);
30        // Deviation (DEVIATIONS.md, Routed events): the managed original
31        // captures the object. An element that keeps the
32        // disposable of a handler it added to itself (a templated control and
33        // the handler of its own pointer events) would keep itself alive that
34        // way; the handlers of an object that is gone are gone with it.
35        let instance = self.to_ref().downgrade();
36        let routed_event = routed_event.as_routed_event();
37
38        Disposable::create(move || {
39            if let Some(instance) = instance.upgrade() {
40                instance.remove_handler(&routed_event, token);
41            }
42        })
43    }
44
45    /// The interactive parent of the object for bubbling and tunneling
46    /// events.
47    pub fn get_interactive_parent(&self) -> Option<Ref<Interactive>> {
48        self.interactive_parent()
49    }
50
51    /// Gets an observable for a routed event (direct and bubble routes,
52    /// unhandled events).
53    ///
54    /// See [`get_observable_with`](Self::get_observable_with).
55    pub fn get_observable<TEventArgs: IRoutedEventArgs + Clone>(
56        &self,
57        routed_event: &RoutedEvent<TEventArgs>,
58    ) -> Rc<dyn IObservable<TEventArgs>> {
59        self.get_observable_with(routed_event, Self::DEFAULT_ROUTES, false)
60    }
61
62    /// Gets an observable for a routed event.
63    ///
64    /// Observers receive a copy of the args of every raise. The copy
65    /// reflects the routing state at the time of the notification; marking
66    /// the copy as handled does not affect the event being routed. Use a
67    /// handler for that.
68    pub fn get_observable_with<TEventArgs: IRoutedEventArgs + Clone>(
69        &self,
70        routed_event: &RoutedEvent<TEventArgs>,
71        routes: RoutingStrategies,
72        handled_events_too: bool,
73    ) -> Rc<dyn IObservable<TEventArgs>> {
74        let o = self.to_ref();
75        let routed_event = *routed_event;
76
77        Observable::create(move |observer| {
78            o.add_disposable_handler_with(
79                &routed_event,
80                move |_, e: &TEventArgs| observer.on_next(e.clone()),
81                routes,
82                handled_events_too,
83            )
84        })
85    }
86}