Skip to main content

kas_widgets/adapt/
adapt_events.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4//     https://www.apache.org/licenses/LICENSE-2.0
5
6//! Event adapters
7
8use super::{AdaptConfigCx, AdaptEventCx};
9#[allow(unused)] use kas::Events;
10use kas::event::{ConfigCx, Event, EventCx, IsUsed};
11use kas::{Id, Widget};
12use kas::{autoimpl, impl_self};
13use std::fmt::Debug;
14
15#[impl_self]
16mod AdaptEvents {
17    /// Wrapper with configure / update / message handling callbacks.
18    ///
19    /// This type is constructed by some [`AdaptWidget`](super::AdaptWidget) methods.
20    #[autoimpl(Deref, DerefMut using self.inner)]
21    #[autoimpl(Viewport using self.inner where W: trait)]
22    #[derive_widget]
23    pub struct AdaptEvents<W: Widget> {
24        /// The inner widget
25        #[widget]
26        pub inner: W,
27        on_configure: Option<Box<dyn Fn(&mut AdaptConfigCx, &mut W)>>,
28        on_update: Option<Box<dyn Fn(&mut AdaptConfigCx, &mut W, &W::Data)>>,
29        message_handlers: Vec<Box<dyn Fn(&mut AdaptEventCx, &mut W, &W::Data)>>,
30    }
31
32    impl<W: Widget> AdaptEvents<W> {
33        /// Construct
34        #[inline]
35        pub fn new(inner: W) -> Self {
36            AdaptEvents {
37                inner,
38                on_configure: None,
39                on_update: None,
40                message_handlers: vec![],
41            }
42        }
43
44        /// Call the given closure on [configuration]
45        ///
46        /// Specifically, the closure is called after [`Events::post_configure`].
47        ///
48        /// [configuration]: Events#configuration
49        #[must_use]
50        pub fn on_configure<F>(mut self, f: F) -> Self
51        where
52            F: Fn(&mut AdaptConfigCx, &mut W) + 'static,
53        {
54            self.on_configure = Some(Box::new(f));
55            self
56        }
57
58        /// Call the given closure on [update]
59        ///
60        /// The closure is called after the [`Self::on_configure`] handler
61        /// during [configuration] and after [`Events::update`] during [update].
62        ///
63        /// [configuration]: Events#configuration
64        /// [update]: Events#update
65        #[must_use]
66        pub fn on_update<F>(mut self, f: F) -> Self
67        where
68            F: Fn(&mut AdaptConfigCx, &mut W, &W::Data) + 'static,
69        {
70            self.on_update = Some(Box::new(f));
71            self
72        }
73
74        /// Add a handler on message of type `M`
75        ///
76        /// The child index may be inferred via [`EventCx::last_child`].
77        /// (Note: this is only possible since `AdaptEvents` is a special "thin" wrapper.)
78        ///
79        /// Where access to input data is required, use [`Self::on_messages`] instead.
80        #[must_use]
81        pub fn on_message<M, H>(self, handler: H) -> Self
82        where
83            M: Debug + 'static,
84            H: Fn(&mut AdaptEventCx, &mut W, M) + 'static,
85        {
86            self.on_messages(move |cx, w, _data| {
87                if let Some(m) = cx.try_pop() {
88                    handler(cx, w, m);
89                }
90            })
91        }
92
93        /// Add a child handler to map messages of type `M` to `N`
94        ///
95        /// # Example
96        ///
97        /// ```
98        /// use kas::messages::Select;
99        /// use kas_widgets::{AdaptWidget, Row, Tab};
100        ///
101        /// #[derive(Clone, Debug)]
102        /// struct MsgSelectIndex(usize);
103        ///
104        /// let tabs = Row::new([Tab::new("A")])
105        ///     .map_message(|index, Select| MsgSelectIndex(index));
106        /// ```
107        pub fn map_message<M, N, H>(self, handler: H) -> Self
108        where
109            M: Debug + 'static,
110            N: Debug + 'static,
111            H: Fn(usize, M) -> N + 'static,
112        {
113            self.on_messages(move |cx, _, _| {
114                if let Some(index) = cx.last_child() {
115                    if let Some(m) = cx.try_pop() {
116                        cx.push(handler(index, m));
117                    }
118                }
119            })
120        }
121
122        /// Add a generic message handler
123        ///
124        /// The child index may be inferred via [`EventCx::last_child`].
125        /// (Note: this is only possible since `AdaptEvents` is a special "thin" wrapper.)
126        #[must_use]
127        pub fn on_messages<H>(mut self, handler: H) -> Self
128        where
129            H: Fn(&mut AdaptEventCx, &mut W, &W::Data) + 'static,
130        {
131            self.message_handlers.push(Box::new(handler));
132            self
133        }
134    }
135
136    impl<W: Widget> Widget for AdaptEvents<W> {
137        type Data = W::Data;
138
139        // NOTE: internal widget methods are used here to call additional event
140        // handlers. This is not otherwise supported by #[derive_widget].
141
142        fn _configure(&mut self, cx: &mut ConfigCx, data: &Self::Data, id: Id) {
143            self.inner._configure(cx, data, id);
144
145            if let Some(ref f) = self.on_configure {
146                let mut cx = AdaptConfigCx::new(cx, self.inner.id());
147                f(&mut cx, &mut self.inner);
148            }
149            if let Some(ref f) = self.on_update {
150                let mut cx = AdaptConfigCx::new(cx, self.inner.id());
151                f(&mut cx, &mut self.inner, data);
152            }
153        }
154
155        fn _update(&mut self, cx: &mut ConfigCx, data: &Self::Data) {
156            self.inner._update(cx, data);
157
158            if let Some(ref f) = self.on_update {
159                let mut cx = AdaptConfigCx::new(cx, self.inner.id());
160                f(&mut cx, &mut self.inner, data);
161            }
162        }
163
164        fn _send(&mut self, cx: &mut EventCx, data: &Self::Data, id: Id, event: Event) -> IsUsed {
165            let is_used = self.inner._send(cx, data, id, event);
166
167            if cx.has_msg() {
168                let mut cx = AdaptEventCx::new(cx, self.inner.id());
169                for handler in self.message_handlers.iter() {
170                    handler(&mut cx, &mut self.inner, data);
171                }
172            }
173
174            is_used
175        }
176
177        fn _replay(&mut self, cx: &mut EventCx, data: &Self::Data, id: Id) {
178            self.inner._replay(cx, data, id);
179
180            if cx.has_msg() {
181                let mut cx = AdaptEventCx::new(cx, self.inner.id());
182                for handler in self.message_handlers.iter() {
183                    handler(&mut cx, &mut self.inner, data);
184                }
185            }
186        }
187    }
188}