Skip to main content

iced_core/
widget.rs

1//! Create custom widgets and operate on them.
2pub mod operation;
3pub mod text;
4pub mod tree;
5
6mod element;
7mod id;
8
9pub use element::Element;
10pub use id::Id;
11pub use operation::Operation;
12pub use text::Text;
13pub use tree::Tree;
14
15use crate::layout::{self, Layout};
16use crate::mouse;
17use crate::overlay;
18use crate::renderer;
19use crate::shell;
20use crate::{Event, Length, Rectangle, Shell, Size, Vector};
21
22/// A component that displays information and allows interaction.
23///
24/// If you want to build your own widgets, you will need to implement this
25/// trait.
26///
27/// # Examples
28/// The repository has some [examples] showcasing how to implement a custom
29/// widget:
30///
31/// - [`custom_widget`], a demonstration of how to build a custom widget that
32///   draws a circle.
33/// - [`geometry`], a custom widget showcasing how to draw geometry with the
34///   `Mesh2D` primitive in [`iced_wgpu`].
35///
36/// [examples]: https://github.com/iced-rs/iced/tree/master/examples
37/// [`custom_widget`]: https://github.com/iced-rs/iced/tree/master/examples/custom_widget
38/// [`geometry`]: https://github.com/iced-rs/iced/tree/master/examples/geometry
39/// [`iced_wgpu`]: https://github.com/iced-rs/iced/tree/master/wgpu
40pub trait Widget<Message, Theme, Renderer>: Meta {
41    /// Returns the [`Size`] of the [`Widget`] in lengths.
42    fn size(&self) -> Size<Length>;
43
44    /// Returns the [`Tag`] of the [`Widget`].
45    ///
46    /// [`Tag`]: tree::Tag
47    fn tag(&self) -> tree::Tag {
48        tree::Tag::stateless()
49    }
50
51    /// Returns the [`State`] of the [`Widget`].
52    ///
53    /// [`State`]: tree::State
54    fn state(&self) -> tree::State {
55        tree::State::None
56    }
57
58    /// Reconciles the [`Widget`] with the provided [`Tree`].
59    fn diff(&mut self, tree: &mut Tree) {
60        tree.children.clear();
61    }
62
63    /// Lays out the [`Widget`].
64    ///
65    /// This computes the [`Layout`] of the [`Widget`] and stores the result
66    /// in the provided [`Tree`].
67    fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits);
68
69    /// Draws the [`Widget`] using the associated `Renderer`.
70    fn draw(
71        &self,
72        tree: &Tree,
73        renderer: &mut Renderer,
74        theme: &Theme,
75        style: &renderer::Style,
76        layout: Layout,
77        cursor: mouse::Cursor,
78        viewport: &Rectangle,
79    );
80
81    /// Applies an [`Operation`] to the [`Widget`].
82    fn operate(
83        &mut self,
84        _tree: &mut Tree,
85        _layout: Layout,
86        _viewport: &Rectangle,
87        _renderer: &Renderer,
88        _operation: &mut dyn Operation,
89    ) {
90    }
91
92    /// Processes a runtime [`Event`].
93    ///
94    /// By default, it does nothing.
95    fn update(
96        &mut self,
97        _tree: &mut Tree,
98        _event: &Event,
99        _layout: Layout,
100        _cursor: mouse::Cursor,
101        _renderer: &Renderer,
102        _shell: &mut Shell<'_, Message>,
103        _viewport: &Rectangle,
104    ) {
105    }
106
107    /// Returns the current [`mouse::Interaction`] of the [`Widget`].
108    ///
109    /// By default, it returns [`mouse::Interaction::None`].
110    fn mouse_interaction(
111        &self,
112        _tree: &Tree,
113        _layout: Layout,
114        _cursor: mouse::Cursor,
115        _viewport: &Rectangle,
116        _renderer: &Renderer,
117    ) -> mouse::Interaction {
118        mouse::Interaction::None
119    }
120
121    /// Returns the overlays of the [`Widget`].
122    fn overlay<'a>(
123        &'a mut self,
124        _tree: &'a mut Tree,
125        _layout: Layout,
126        _renderer: &Renderer,
127        _viewport: &Rectangle,
128        _translation: Vector,
129        _window: Size,
130    ) -> Vec<overlay::Element<'a, Message, Theme, Renderer>> {
131        Vec::new()
132    }
133
134    /// Applies a transformation to the produced message of this [`Widget`],
135    /// returning a [`Map`].
136    ///
137    /// This method is useful when you want to decouple different parts of your
138    /// UI and make them __composable__.
139    fn _map<F, B>(self, f: F) -> Map<Self, F, Message>
140    where
141        Self: Sized,
142        F: Fn(Message) -> B,
143    {
144        Map {
145            widget: self,
146            mapper: f,
147            _input: std::marker::PhantomData,
148        }
149    }
150
151    /// Boxes this [`Widget`], turning it into a generic [`Element`].
152    fn _boxed<'a>(self) -> Element<'a, Message, Theme, Renderer>
153    where
154        Self: Sized + 'a,
155    {
156        Element::new(self)
157    }
158}
159
160/// Metadata of a [`Widget`], independent of its generic parameters.
161pub trait Meta {
162    /// Returns whether the [`Widget`] is [`Void`].
163    fn is_void(&self) -> bool {
164        false
165    }
166}
167
168impl<T> Meta for &mut T
169where
170    T: Meta,
171{
172    fn is_void(&self) -> bool {
173        T::is_void(self)
174    }
175}
176
177impl<T, Message, Theme, Renderer> Widget<Message, Theme, Renderer> for &mut T
178where
179    Renderer: crate::Renderer,
180    T: Widget<Message, Theme, Renderer>,
181{
182    fn size(&self) -> Size<Length> {
183        T::size(self)
184    }
185
186    fn tag(&self) -> tree::Tag {
187        T::tag(self)
188    }
189
190    fn state(&self) -> tree::State {
191        T::state(self)
192    }
193
194    fn diff(&mut self, tree: &mut Tree) {
195        T::diff(self, tree);
196    }
197
198    fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits) {
199        T::layout(self, tree, renderer, limits);
200    }
201
202    fn draw(
203        &self,
204        tree: &Tree,
205        renderer: &mut Renderer,
206        theme: &Theme,
207        style: &renderer::Style,
208        layout: Layout,
209        cursor: mouse::Cursor,
210        viewport: &Rectangle,
211    ) {
212        T::draw(self, tree, renderer, theme, style, layout, cursor, viewport);
213    }
214
215    fn operate(
216        &mut self,
217        tree: &mut Tree,
218        layout: Layout,
219        viewport: &Rectangle,
220        renderer: &Renderer,
221        operation: &mut dyn Operation,
222    ) {
223        T::operate(self, tree, layout, viewport, renderer, operation);
224    }
225
226    fn update(
227        &mut self,
228        tree: &mut Tree,
229        event: &Event,
230        layout: Layout,
231        cursor: mouse::Cursor,
232        renderer: &Renderer,
233        shell: &mut Shell<'_, Message>,
234        viewport: &Rectangle,
235    ) {
236        T::update(self, tree, event, layout, cursor, renderer, shell, viewport);
237    }
238
239    fn mouse_interaction(
240        &self,
241        tree: &Tree,
242        layout: Layout,
243        cursor: mouse::Cursor,
244        viewport: &Rectangle,
245        renderer: &Renderer,
246    ) -> mouse::Interaction {
247        T::mouse_interaction(self, tree, layout, cursor, viewport, renderer)
248    }
249
250    fn overlay<'a>(
251        &'a mut self,
252        tree: &'a mut Tree,
253        layout: Layout,
254        renderer: &Renderer,
255        viewport: &Rectangle,
256        translation: Vector,
257        window: Size,
258    ) -> Vec<overlay::Element<'a, Message, Theme, Renderer>> {
259        T::overlay(self, tree, layout, renderer, viewport, translation, window)
260    }
261}
262
263/// A zero-sized [`Widget`] that does nothing and will be filtered out by containers.
264pub struct Void;
265
266impl Meta for Void {
267    fn is_void(&self) -> bool {
268        true
269    }
270}
271
272impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Void {
273    fn size(&self) -> Size<Length> {
274        Size {
275            width: Length::Shrink,
276            height: Length::Shrink,
277        }
278    }
279
280    fn layout(&mut self, _tree: &mut Tree, _renderer: &Renderer, _limits: &layout::Limits) {}
281
282    fn draw(
283        &self,
284        _tree: &Tree,
285        _renderer: &mut Renderer,
286        _theme: &Theme,
287        _style: &renderer::Style,
288        _layout: Layout,
289        _cursor: mouse::Cursor,
290        _viewport: &Rectangle,
291    ) {
292    }
293}
294
295/// A [`Widget`] that transforms the produced message of another widget.
296///
297/// This widget is returned by [`Widget::map`](Widget::_map).
298pub struct Map<W, F, A> {
299    widget: W,
300    mapper: F,
301    _input: std::marker::PhantomData<A>,
302}
303
304impl<W, F, A> Meta for Map<W, F, A>
305where
306    W: Meta,
307{
308    fn is_void(&self) -> bool {
309        self.widget.is_void()
310    }
311}
312
313impl<W, A, B, F, Theme, Renderer> Widget<B, Theme, Renderer> for Map<W, F, A>
314where
315    W: Widget<A, Theme, Renderer>,
316    B: 'static,
317    F: Fn(A) -> B,
318    Theme: 'static,
319    Renderer: crate::Renderer + 'static,
320{
321    fn size(&self) -> Size<Length> {
322        self.widget.size()
323    }
324
325    fn tag(&self) -> tree::Tag {
326        self.widget.tag()
327    }
328
329    fn state(&self) -> tree::State {
330        self.widget.state()
331    }
332
333    fn diff(&mut self, tree: &mut Tree) {
334        self.widget.diff(tree);
335    }
336
337    fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits) {
338        self.widget.layout(tree, renderer, limits);
339    }
340
341    fn operate(
342        &mut self,
343        tree: &mut Tree,
344        layout: Layout,
345        viewport: &Rectangle,
346        renderer: &Renderer,
347        operation: &mut dyn Operation,
348    ) {
349        self.widget
350            .operate(tree, layout, viewport, renderer, operation);
351    }
352
353    fn update(
354        &mut self,
355        tree: &mut Tree,
356        event: &Event,
357        layout: Layout,
358        cursor: mouse::Cursor,
359        renderer: &Renderer,
360        shell: &mut Shell<'_, B>,
361        viewport: &Rectangle,
362    ) {
363        let mut local_messages = shell::Bus::new();
364        let mut local_shell = shell.local(&mut local_messages);
365
366        self.widget.update(
367            tree,
368            event,
369            layout,
370            cursor,
371            renderer,
372            &mut local_shell,
373            viewport,
374        );
375
376        shell.merge(local_shell, &self.mapper);
377    }
378
379    fn draw(
380        &self,
381        tree: &Tree,
382        renderer: &mut Renderer,
383        theme: &Theme,
384        style: &renderer::Style,
385        layout: Layout,
386        cursor: mouse::Cursor,
387        viewport: &Rectangle,
388    ) {
389        self.widget
390            .draw(tree, renderer, theme, style, layout, cursor, viewport);
391    }
392
393    fn mouse_interaction(
394        &self,
395        tree: &Tree,
396        layout: Layout,
397        cursor: mouse::Cursor,
398        viewport: &Rectangle,
399        renderer: &Renderer,
400    ) -> mouse::Interaction {
401        self.widget
402            .mouse_interaction(tree, layout, cursor, viewport, renderer)
403    }
404
405    fn overlay<'b>(
406        &'b mut self,
407        tree: &'b mut Tree,
408        layout: Layout,
409        renderer: &Renderer,
410        viewport: &Rectangle,
411        translation: Vector,
412        window: Size,
413    ) -> Vec<overlay::Element<'b, B, Theme, Renderer>> {
414        let mapper = &self.mapper;
415
416        self.widget
417            .overlay(tree, layout, renderer, viewport, translation, window)
418            .into_iter()
419            .map(move |overlay| overlay.map(mapper))
420            .collect()
421    }
422}
423
424impl<T> Meta for Option<T>
425where
426    T: Meta,
427{
428    fn is_void(&self) -> bool {
429        self.is_none()
430    }
431}
432
433impl<T, Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Option<T>
434where
435    T: Widget<Message, Theme, Renderer>,
436    Renderer: crate::Renderer,
437{
438    fn size(&self) -> Size<Length> {
439        let Some(widget) = self else {
440            return Size {
441                width: Length::Shrink,
442                height: Length::Shrink,
443            };
444        };
445
446        widget.size()
447    }
448
449    fn tag(&self) -> tree::Tag {
450        let Some(widget) = self else {
451            return tree::Tag::stateless();
452        };
453
454        widget.tag()
455    }
456
457    fn state(&self) -> tree::State {
458        let Some(widget) = self else {
459            return tree::State::None;
460        };
461
462        widget.state()
463    }
464
465    fn diff(&mut self, tree: &mut Tree) {
466        let Some(widget) = self else {
467            tree.children.clear();
468            return;
469        };
470
471        widget.diff(tree);
472    }
473
474    fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits) {
475        let Some(widget) = self else {
476            return;
477        };
478
479        widget.layout(tree, renderer, limits);
480    }
481
482    fn draw(
483        &self,
484        tree: &Tree,
485        renderer: &mut Renderer,
486        theme: &Theme,
487        style: &renderer::Style,
488        layout: Layout,
489        cursor: mouse::Cursor,
490        viewport: &Rectangle,
491    ) {
492        let Some(widget) = self else {
493            return;
494        };
495
496        widget.draw(tree, renderer, theme, style, layout, cursor, viewport);
497    }
498
499    fn operate(
500        &mut self,
501        tree: &mut Tree,
502        layout: Layout,
503        viewport: &Rectangle,
504        renderer: &Renderer,
505        operation: &mut dyn Operation,
506    ) {
507        let Some(widget) = self else {
508            return;
509        };
510
511        widget.operate(tree, layout, viewport, renderer, operation);
512    }
513
514    fn update(
515        &mut self,
516        tree: &mut Tree,
517        event: &Event,
518        layout: Layout,
519        cursor: mouse::Cursor,
520        renderer: &Renderer,
521        shell: &mut Shell<'_, Message>,
522        viewport: &Rectangle,
523    ) {
524        let Some(widget) = self else {
525            return;
526        };
527
528        widget.update(tree, event, layout, cursor, renderer, shell, viewport);
529    }
530
531    fn mouse_interaction(
532        &self,
533        tree: &Tree,
534        layout: Layout,
535        cursor: mouse::Cursor,
536        viewport: &Rectangle,
537        renderer: &Renderer,
538    ) -> mouse::Interaction {
539        let Some(widget) = self else {
540            return mouse::Interaction::None;
541        };
542
543        widget.mouse_interaction(tree, layout, cursor, viewport, renderer)
544    }
545
546    fn overlay<'a>(
547        &'a mut self,
548        tree: &'a mut Tree,
549        layout: Layout,
550        renderer: &Renderer,
551        viewport: &Rectangle,
552        translation: Vector,
553        window: Size,
554    ) -> Vec<overlay::Element<'a, Message, Theme, Renderer>> {
555        let Some(widget) = self else {
556            return Vec::new();
557        };
558
559        widget.overlay(tree, layout, renderer, viewport, translation, window)
560    }
561}