kas_widgets/adapt/
adapt.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//! Adapt widget
7
8use super::{AdaptConfigCx, AdaptEventCx};
9use kas::prelude::*;
10use linear_map::LinearMap;
11use std::fmt::Debug;
12use std::marker::PhantomData;
13
14impl_scope! {
15    /// Data adaption node
16    ///
17    /// Where [`Map`] allows mapping to a sub-set of input data, `Adapt` allows
18    /// mapping to a super-set (including internal storage). Further, `Adapt`
19    /// supports message handlers which mutate internal storage.
20    #[autoimpl(Deref, DerefMut using self.inner)]
21    #[autoimpl(Scrollable using self.inner where W: trait)]
22    #[widget {
23        layout = self.inner;
24    }]
25    pub struct Adapt<A, W: Widget<Data = S>, S: Debug> {
26        core: widget_core!(),
27        state: S,
28        #[widget(&self.state)]
29        inner: W,
30        configure_handler: Option<Box<dyn Fn(&mut AdaptConfigCx, &mut S)>>,
31        update_handler: Option<Box<dyn Fn(&mut AdaptConfigCx, &mut S, &A)>>,
32        timer_handlers: LinearMap<u64, Box<dyn Fn(&mut AdaptEventCx, &mut S, &A)>>,
33        message_handlers: Vec<Box<dyn Fn(&mut AdaptEventCx, &mut S, &A)>>,
34    }
35
36    impl Self {
37        /// Construct over `inner` with additional `state`
38        #[inline]
39        pub fn new(inner: W, state: S) -> Self {
40            Adapt {
41                core: Default::default(),
42                state,
43                inner,
44                configure_handler: None,
45                update_handler: None,
46                timer_handlers: LinearMap::new(),
47                message_handlers: vec![],
48            }
49        }
50
51        /// Add a handler to be called on configuration
52        pub fn on_configure<F>(mut self, handler: F) -> Self
53        where
54            F: Fn(&mut AdaptConfigCx, &mut S) + 'static,
55        {
56            debug_assert!(self.configure_handler.is_none());
57            self.configure_handler = Some(Box::new(handler));
58            self
59        }
60
61        /// Add a handler to be called on update of input data
62        ///
63        /// Children will be updated after the handler is called.
64        pub fn on_update<F>(mut self, handler: F) -> Self
65        where
66            F: Fn(&mut AdaptConfigCx, &mut S, &A) + 'static,
67        {
68            debug_assert!(self.update_handler.is_none());
69            self.update_handler = Some(Box::new(handler));
70            self
71        }
72
73        /// Set a timer handler
74        ///
75        /// It is assumed that state is modified by this timer. Frequent usage
76        /// of timers which don't do anything may be inefficient; prefer usage
77        /// of [`EventState::push_async`](kas::event::EventState::push_async).
78        pub fn on_timer<H>(mut self, timer_id: u64, handler: H) -> Self
79        where
80            H: Fn(&mut AdaptEventCx, &mut S, &A) + 'static,
81        {
82            debug_assert!(self.timer_handlers.get(&timer_id).is_none());
83            self.timer_handlers.insert(timer_id, Box::new(handler));
84            self
85        }
86
87        /// Add a handler on message of type `M`
88        ///
89        /// Children will be updated whenever this handler is invoked.
90        ///
91        /// Where access to input data (from parent widgets) is required,
92        /// use [`Self::on_messages`] instead.
93        pub fn on_message<M, H>(self, handler: H) -> Self
94        where
95            M: Debug + 'static,
96            H: Fn(&mut AdaptEventCx, &mut S, M) + 'static,
97        {
98            self.on_messages(move |cx, state, _data| {
99                if let Some(m) = cx.try_pop() {
100                    handler(cx, state, m);
101                }
102            })
103        }
104
105        /// Add a generic message handler
106        pub fn on_messages<H>(mut self, handler: H) -> Self
107        where
108            H: Fn(&mut AdaptEventCx, &mut S, &A) + 'static,
109        {
110            self.message_handlers.push(Box::new(handler));
111            self
112        }
113    }
114
115    impl Events for Self {
116        type Data = A;
117
118        fn configure(&mut self, cx: &mut ConfigCx) {
119            if let Some(handler) = self.configure_handler.as_ref() {
120                let mut cx = AdaptConfigCx::new(cx, self.id());
121                handler(&mut cx, &mut self.state);
122            }
123        }
124
125        fn update(&mut self, cx: &mut ConfigCx, data: &A) {
126            if let Some(handler) = self.update_handler.as_ref() {
127                let mut cx = AdaptConfigCx::new(cx, self.id());
128                handler(&mut cx, &mut self.state, data);
129            }
130        }
131
132        fn handle_event(&mut self, cx: &mut EventCx, data: &Self::Data, event: Event) -> IsUsed {
133            match event {
134                Event::Timer(timer_id) => {
135                    if let Some(handler) = self.timer_handlers.get(&timer_id) {
136                        let mut cx = AdaptEventCx::new(cx, self.id());
137                        handler(&mut cx, &mut self.state, data);
138                        cx.update(self.as_node(data));
139                        Used
140                    } else {
141                        Unused
142                    }
143                }
144                _ => Unused,
145            }
146        }
147
148        fn handle_messages(&mut self, cx: &mut EventCx, data: &A) {
149            let count = cx.msg_op_count();
150            let mut cx = AdaptEventCx::new(cx, self.id());
151            for handler in self.message_handlers.iter() {
152                handler(&mut cx, &mut self.state, data);
153            }
154            if cx.msg_op_count() != count {
155                cx.update(self.as_node(data));
156            }
157        }
158    }
159}
160
161impl_scope! {
162    /// Data mapping
163    ///
164    /// This is a generic data-mapping widget. See also [`Adapt`], [`MapAny`](super::MapAny).
165    #[autoimpl(Deref, DerefMut using self.inner)]
166    #[autoimpl(Scrollable using self.inner where W: trait)]
167    #[widget {
168        Data = A;
169        layout = self.inner;
170    }]
171    pub struct Map<A, W: Widget, F>
172    where
173        F: for<'a> Fn(&'a A) -> &'a W::Data,
174    {
175        core: widget_core!(),
176        #[widget((self.map_fn)(data))]
177        inner: W,
178        map_fn: F,
179        _data: PhantomData<A>,
180    }
181
182    impl Self {
183        /// Construct
184        ///
185        /// -   Over an `inner` widget
186        /// -   And `map_fn` mapping to the inner widget's data type
187        pub fn new(inner: W, map_fn: F) -> Self {
188            Map {
189                core: Default::default(),
190                inner,
191                map_fn,
192                _data: PhantomData,
193            }
194        }
195    }
196}