suzy/widget/
mod.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! This module contains all the types associated with defining custom
6//! widgets.
7
8use std::ops::{Deref, DerefMut};
9
10pub use drying_paint::Watched;
11use drying_paint::{Watcher, WatcherId};
12
13use crate::adapter::Adaptable;
14use crate::dims::{Dim, Rect};
15use crate::graphics::DrawContext;
16use crate::platform::{DefaultRenderPlatform, RenderPlatform};
17use crate::pointer::PointerEvent;
18
19mod anon;
20mod content;
21mod graphic;
22mod init;
23mod internal;
24pub mod layout;
25mod receivers;
26mod rect;
27
28use internal::WidgetInternal;
29use receivers::{
30    DrawChildReceiver, DrawGraphicBeforeReceiver, DrawGraphicOrderedReceiver,
31    DrawGraphicUnorderedReceiver, FindWidgetReceiver,
32    PointerEventChildReceiver,
33};
34
35pub use anon::AnonWidget;
36pub use content::WidgetContent;
37pub use graphic::WidgetGraphic;
38pub use init::WidgetInit;
39pub use internal::WidgetExtra;
40pub use receivers::{WidgetChildReceiver, WidgetGraphicReceiver};
41pub use rect::WidgetRect;
42
43pub(crate) type FindWidgetCallback<'a, P> =
44    Option<Box<dyn FnOnce(&mut dyn AnonWidget<P>) + 'a>>;
45
46/// A basic structure to wrap some data and turn it into a widget.
47pub struct Widget<T, P = DefaultRenderPlatform>
48where
49    P: RenderPlatform + ?Sized,
50    T: WidgetContent<P> + ?Sized,
51{
52    watcher: Watcher<WidgetInternal<P, T>>,
53}
54
55impl<T, P, Data> Adaptable<Data> for Widget<T, P>
56where
57    P: RenderPlatform,
58    T: WidgetContent<P> + Adaptable<Data>,
59{
60    fn adapt(&mut self, data: &Data) {
61        self.watcher.data_mut().content.adapt(data);
62    }
63
64    fn from(data: &Data) -> Self {
65        Widget::create_from(data)
66    }
67}
68
69impl<T, P> Default for Widget<T, P>
70where
71    P: RenderPlatform,
72    T: WidgetContent<P> + Default + ?Sized,
73{
74    fn default() -> Self {
75        Self {
76            watcher: Default::default(),
77        }
78    }
79}
80
81impl<T, P> Deref for Widget<T, P>
82where
83    P: RenderPlatform + ?Sized,
84    T: WidgetContent<P>,
85{
86    type Target = T;
87    fn deref(&self) -> &T {
88        &self.watcher.data().content
89    }
90}
91
92impl<T, P> DerefMut for Widget<T, P>
93where
94    P: RenderPlatform + ?Sized,
95    T: WidgetContent<P>,
96{
97    fn deref_mut(&mut self) -> &mut T {
98        &mut self.watcher.data_mut().content
99    }
100}
101
102impl<P, T> Widget<T, P>
103where
104    P: RenderPlatform + ?Sized,
105    T: WidgetContent<P>,
106{
107    /// Create a new widget, populating it's content using the adaptable
108    /// trait.
109    pub fn create_from<Data>(data: &Data) -> Self
110    where
111        T: Adaptable<Data>,
112    {
113        Widget {
114            watcher: Watcher::create(WidgetInternal {
115                rect: WidgetRect::default(),
116                content: Adaptable::from(data),
117                _platform: Default::default(),
118            }),
119        }
120    }
121
122    /// Create a new widget, populating it's content using the adaptable
123    /// trait and with a specific initial position and size
124    pub fn create_with_rect<Data, R>(data: &Data, rect: &R) -> Self
125    where
126        T: Adaptable<Data>,
127        R: Rect,
128    {
129        Widget {
130            watcher: Watcher::create(WidgetInternal {
131                rect: WidgetRect::external_from(rect),
132                content: Adaptable::from(data),
133                _platform: Default::default(),
134            }),
135        }
136    }
137
138    /// Get a value representing a unique id for this Widget.  This value may
139    /// outlive the widget, and will never compare equal to a value returned
140    /// by the id method of a Widget other than this one.
141    pub fn id(this: &Self) -> WidgetId {
142        WidgetId {
143            id: this.watcher.id(),
144        }
145    }
146
147    pub(crate) fn draw(this: &mut Self, ctx: &mut DrawContext<P>) {
148        let wid_int = this.watcher.data_mut();
149        let content = &mut wid_int.content;
150        content.graphics(DrawGraphicBeforeReceiver { ctx });
151        content.children(DrawChildReceiver { ctx });
152        let mut num_ordered = 0;
153        content.graphics(DrawGraphicUnorderedReceiver {
154            ctx,
155            num_ordered: &mut num_ordered,
156        });
157        for target in (0..num_ordered).rev() {
158            content.graphics(DrawGraphicOrderedReceiver {
159                ctx,
160                target,
161                current: 0,
162            });
163        }
164    }
165
166    pub(crate) fn find_widget(
167        this: &mut Self,
168        id: &WidgetId,
169        func: &mut FindWidgetCallback<P>,
170    ) {
171        if let Some(f) = func.take() {
172            if Widget::id(this) == *id {
173                f(this);
174            } else {
175                *func = Some(f);
176                let content: &mut T = this;
177                content.children(FindWidgetReceiver { id, func });
178            }
179        }
180    }
181
182    pub(crate) fn pointer_event(
183        this: &mut Self,
184        event: &mut PointerEvent,
185    ) -> bool {
186        let id = Widget::id(this);
187        let wid_int = this.watcher.data_mut();
188        let mut extra = WidgetExtra {
189            id,
190            rect: &mut wid_int.rect,
191        };
192        T::pointer_event_before(&mut wid_int.content, &mut extra, event)
193            || {
194                let mut handled_by_child = false;
195                wid_int.content.children(PointerEventChildReceiver {
196                    event,
197                    handled: &mut handled_by_child,
198                });
199                handled_by_child
200            }
201            || T::pointer_event(&mut wid_int.content, &mut extra, event)
202    }
203
204    pub(crate) fn pointer_event_self(
205        this: &mut Self,
206        event: &mut PointerEvent,
207    ) -> bool {
208        let id = Widget::id(this);
209        let wid_int = this.watcher.data_mut();
210        let mut extra = WidgetExtra {
211            id,
212            rect: &mut wid_int.rect,
213        };
214        T::pointer_event(&mut wid_int.content, &mut extra, event)
215    }
216}
217
218impl<P, T> Widget<T, P>
219where
220    P: RenderPlatform,
221    T: WidgetContent<P> + Default,
222{
223    /// Create a Widget with a specified initial position and size
224    pub fn default_with_rect<R: Rect>(rect: &R) -> Self {
225        Widget {
226            watcher: Watcher::create(WidgetInternal {
227                rect: WidgetRect::external_from(rect),
228                content: Default::default(),
229                _platform: Default::default(),
230            }),
231        }
232    }
233}
234
235impl<P, T> Rect for Widget<T, P>
236where
237    P: RenderPlatform + ?Sized,
238    T: WidgetContent<P>,
239{
240    fn x(&self) -> Dim {
241        self.watcher.data().rect.x()
242    }
243    fn y(&self) -> Dim {
244        self.watcher.data().rect.y()
245    }
246
247    fn x_mut<F, R>(&mut self, f: F) -> R
248    where
249        F: FnOnce(&mut Dim) -> R,
250    {
251        self.watcher.data_mut().rect.external_x_mut(f)
252    }
253
254    fn y_mut<F, R>(&mut self, f: F) -> R
255    where
256        F: FnOnce(&mut Dim) -> R,
257    {
258        self.watcher.data_mut().rect.external_y_mut(f)
259    }
260}
261
262/// A unique id for a widget
263///
264/// This value may outlive the widget, and will never compare equal to a
265/// value obtained from a different widget.
266#[derive(Clone, Debug, PartialEq, Eq)]
267pub struct WidgetId {
268    id: WatcherId,
269}
270
271impl<P, T> From<&Widget<T, P>> for WidgetId
272where
273    P: RenderPlatform,
274    T: WidgetContent<P>,
275{
276    fn from(widget: &Widget<T, P>) -> Self {
277        widget.id()
278    }
279}
280
281impl From<&mut WidgetExtra<'_>> for WidgetId {
282    fn from(extra: &mut WidgetExtra) -> Self {
283        extra.id()
284    }
285}