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, Node, 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(Scrollable using self.inner where W: trait)]
21    #[derive_widget]
22    pub struct AdaptEvents<W: Widget> {
23        /// The inner widget
24        #[widget]
25        pub inner: W,
26        on_configure: Option<Box<dyn Fn(&mut AdaptConfigCx, &mut W)>>,
27        on_update: Option<Box<dyn Fn(&mut AdaptConfigCx, &mut W, &W::Data)>>,
28        message_handlers: Vec<Box<dyn Fn(&mut AdaptEventCx, &mut W, &W::Data)>>,
29    }
30
31    impl<W: Widget> AdaptEvents<W> {
32        /// Construct
33        #[inline]
34        pub fn new(inner: W) -> Self {
35            AdaptEvents {
36                inner,
37                on_configure: None,
38                on_update: None,
39                message_handlers: vec![],
40            }
41        }
42
43        /// Call the given closure on [`Events::configure`]
44        #[must_use]
45        pub fn on_configure<F>(mut self, f: F) -> Self
46        where
47            F: Fn(&mut AdaptConfigCx, &mut W) + 'static,
48        {
49            self.on_configure = Some(Box::new(f));
50            self
51        }
52
53        /// Call the given closure on [`Events::update`]
54        #[must_use]
55        pub fn on_update<F>(mut self, f: F) -> Self
56        where
57            F: Fn(&mut AdaptConfigCx, &mut W, &W::Data) + 'static,
58        {
59            self.on_update = Some(Box::new(f));
60            self
61        }
62
63        /// Add a handler on message of type `M`
64        ///
65        /// The child index may be inferred via [`EventCx::last_child`].
66        /// (Note: this is only possible since `AdaptEvents` is a special "thin" wrapper.)
67        ///
68        /// Where access to input data is required, use [`Self::on_messages`] instead.
69        #[must_use]
70        pub fn on_message<M, H>(self, handler: H) -> Self
71        where
72            M: Debug + 'static,
73            H: Fn(&mut AdaptEventCx, &mut W, M) + 'static,
74        {
75            self.on_messages(move |cx, w, _data| {
76                if let Some(m) = cx.try_pop() {
77                    handler(cx, w, m);
78                }
79            })
80        }
81
82        /// Add a child handler to map messages of type `M` to `N`
83        ///
84        /// # Example
85        ///
86        /// ```
87        /// use kas::messages::Select;
88        /// use kas_widgets::{AdaptWidget, Row, Tab};
89        ///
90        /// #[derive(Clone, Debug)]
91        /// struct MsgSelectIndex(usize);
92        ///
93        /// let tabs = Row::new([Tab::new("A")])
94        ///     .map_message(|index, Select| MsgSelectIndex(index));
95        /// ```
96        pub fn map_message<M, N, H>(self, handler: H) -> Self
97        where
98            M: Debug + 'static,
99            N: Debug + 'static,
100            H: Fn(usize, M) -> N + 'static,
101        {
102            self.on_messages(move |cx, _, _| {
103                if let Some(index) = cx.last_child() {
104                    if let Some(m) = cx.try_pop() {
105                        cx.push(handler(index, m));
106                    }
107                }
108            })
109        }
110
111        /// Add a generic message handler
112        ///
113        /// The child index may be inferred via [`EventCx::last_child`].
114        /// (Note: this is only possible since `AdaptEvents` is a special "thin" wrapper.)
115        #[must_use]
116        pub fn on_messages<H>(mut self, handler: H) -> Self
117        where
118            H: Fn(&mut AdaptEventCx, &mut W, &W::Data) + 'static,
119        {
120            self.message_handlers.push(Box::new(handler));
121            self
122        }
123    }
124
125    impl<W: Widget> Widget for AdaptEvents<W> {
126        type Data = W::Data;
127
128        #[inline]
129        fn as_node<'a>(&'a mut self, data: &'a Self::Data) -> Node<'a> {
130            Node::new(self, data)
131        }
132
133        #[inline]
134        fn child_node<'n>(&'n mut self, data: &'n Self::Data, index: usize) -> Option<Node<'n>> {
135            self.inner.child_node(data, index)
136        }
137
138        fn _configure(&mut self, cx: &mut ConfigCx, data: &Self::Data, id: Id) {
139            self.inner._configure(cx, data, id);
140
141            if let Some(ref f) = self.on_configure {
142                let mut cx = AdaptConfigCx::new(cx, self.inner.id());
143                f(&mut cx, &mut self.inner);
144            }
145            if let Some(ref f) = self.on_update {
146                let mut cx = AdaptConfigCx::new(cx, self.inner.id());
147                f(&mut cx, &mut self.inner, data);
148            }
149        }
150
151        fn _update(&mut self, cx: &mut ConfigCx, data: &Self::Data) {
152            self.inner._update(cx, data);
153
154            if let Some(ref f) = self.on_update {
155                let mut cx = AdaptConfigCx::new(cx, self.inner.id());
156                f(&mut cx, &mut self.inner, data);
157            }
158        }
159
160        fn _send(&mut self, cx: &mut EventCx, data: &Self::Data, id: Id, event: Event) -> IsUsed {
161            let is_used = self.inner._send(cx, data, id, event);
162
163            if cx.has_msg() {
164                let mut cx = AdaptEventCx::new(cx, self.inner.id());
165                for handler in self.message_handlers.iter() {
166                    handler(&mut cx, &mut self.inner, data);
167                }
168            }
169
170            is_used
171        }
172
173        fn _replay(&mut self, cx: &mut EventCx, data: &Self::Data, id: Id) {
174            self.inner._replay(cx, data, id);
175
176            if cx.has_msg() {
177                let mut cx = AdaptEventCx::new(cx, self.inner.id());
178                for handler in self.message_handlers.iter() {
179                    handler(&mut cx, &mut self.inner, data);
180                }
181            }
182        }
183    }
184}