Skip to main content

iced_core/
element.rs

1use crate::layout;
2use crate::mouse;
3use crate::overlay;
4use crate::renderer;
5use crate::widget;
6use crate::widget::tree::{self, Tree};
7use crate::{Border, Color, Event, Layout, Length, Rectangle, Shell, Size, Vector, Widget};
8
9use std::borrow::Borrow;
10
11/// A generic [`Widget`].
12///
13/// It is useful to build composable user interfaces that do not leak
14/// implementation details in their __view logic__.
15///
16/// If you have a [built-in widget], you should be able to use `Into<Element>`
17/// to turn it into an [`Element`].
18///
19/// [built-in widget]: crate::widget
20pub struct Element<'a, Message, Theme, Renderer> {
21    widget: Box<dyn Widget<Message, Theme, Renderer> + 'a>,
22}
23
24impl<'a, Message, Theme, Renderer> Element<'a, Message, Theme, Renderer> {
25    /// Creates a new [`Element`] containing the given [`Widget`].
26    pub fn new(widget: impl Widget<Message, Theme, Renderer> + 'a) -> Self
27    where
28        Renderer: crate::Renderer,
29    {
30        Self {
31            widget: Box::new(widget),
32        }
33    }
34
35    /// Returns a reference to the [`Widget`] of the [`Element`],
36    pub fn as_widget(&self) -> &dyn Widget<Message, Theme, Renderer> {
37        self.widget.as_ref()
38    }
39
40    /// Returns a mutable reference to the [`Widget`] of the [`Element`],
41    pub fn as_widget_mut(&mut self) -> &mut dyn Widget<Message, Theme, Renderer> {
42        self.widget.as_mut()
43    }
44
45    /// Applies a transformation to the produced message of the [`Element`].
46    ///
47    /// This method is useful when you want to decouple different parts of your
48    /// UI and make them __composable__.
49    ///
50    /// # Example
51    /// Imagine we want to use [our counter](index.html#usage). But instead of
52    /// showing a single counter, we want to display many of them. We can reuse
53    /// the `Counter` type as it is!
54    ///
55    /// We use composition to model the __state__ of our new application:
56    ///
57    /// ```
58    /// # mod counter {
59    /// #     pub struct Counter;
60    /// # }
61    /// use counter::Counter;
62    ///
63    /// struct ManyCounters {
64    ///     counters: Vec<Counter>,
65    /// }
66    /// ```
67    ///
68    /// We can store the state of multiple counters now. However, the
69    /// __messages__ we implemented before describe the user interactions
70    /// of a __single__ counter. Right now, we need to also identify which
71    /// counter is receiving user interactions. Can we use composition again?
72    /// Yes.
73    ///
74    /// ```
75    /// # mod counter {
76    /// #     #[derive(Debug, Clone, Copy)]
77    /// #     pub enum Message {}
78    /// # }
79    /// #[derive(Debug, Clone, Copy)]
80    /// pub enum Message {
81    ///     Counter(usize, counter::Message)
82    /// }
83    /// ```
84    ///
85    /// We compose the previous __messages__ with the index of the counter
86    /// producing them. Let's implement our __view logic__ now:
87    ///
88    /// ```no_run
89    /// # mod iced {
90    /// #     pub use iced_core::Function;
91    /// #     pub type Element<'a, Message> = iced_core::Element<'a, Message, iced_core::Theme, ()>;
92    /// #
93    /// #     pub mod widget {
94    /// #         pub fn row<'a, Message>(iter: impl IntoIterator<Item = super::Element<'a, Message>>) -> super::Element<'a, Message> {
95    /// #             unimplemented!()
96    /// #         }
97    /// #     }
98    /// # }
99    /// #
100    /// # mod counter {
101    /// #     #[derive(Debug, Clone, Copy)]
102    /// #     pub enum Message {}
103    /// #     pub struct Counter;
104    /// #
105    /// #     pub type Element<'a, Message> = iced_core::Element<'a, Message, iced_core::Theme, ()>;
106    /// #
107    /// #     impl Counter {
108    /// #         pub fn view(&self) -> Element<Message> {
109    /// #             unimplemented!()
110    /// #         }
111    /// #     }
112    /// # }
113    /// #
114    /// use counter::Counter;
115    ///
116    /// use iced::widget::row;
117    /// use iced::{Element, Function};
118    ///
119    /// struct ManyCounters {
120    ///     counters: Vec<Counter>,
121    /// }
122    ///
123    /// #[derive(Debug, Clone, Copy)]
124    /// pub enum Message {
125    ///     Counter(usize, counter::Message),
126    /// }
127    ///
128    /// impl ManyCounters {
129    ///     pub fn view(&self) -> Element<Message> {
130    ///         // We can quickly populate a `row` by mapping our counters
131    ///         row(
132    ///             self.counters
133    ///                 .iter()
134    ///                 .map(Counter::view)
135    ///                 .enumerate()
136    ///                 .map(|(index, counter)| {
137    ///                     // Here we turn our `Element<counter::Message>` into
138    ///                     // an `Element<Message>` by combining the `index` and the
139    ///                     // message of the `element`.
140    ///                     counter.map(Message::Counter.with(index))
141    ///                 }),
142    ///         )
143    ///         .into()
144    ///     }
145    /// }
146    /// ```
147    ///
148    /// Finally, our __update logic__ is pretty straightforward: simple
149    /// delegation.
150    ///
151    /// ```
152    /// # mod counter {
153    /// #     #[derive(Debug, Clone, Copy)]
154    /// #     pub enum Message {}
155    /// #     pub struct Counter;
156    /// #
157    /// #     impl Counter {
158    /// #         pub fn update(&mut self, _message: Message) {}
159    /// #     }
160    /// # }
161    /// #
162    /// # use counter::Counter;
163    /// #
164    /// # struct ManyCounters {
165    /// #     counters: Vec<Counter>,
166    /// # }
167    /// #
168    /// # #[derive(Debug, Clone, Copy)]
169    /// # pub enum Message {
170    /// #    Counter(usize, counter::Message)
171    /// # }
172    /// impl ManyCounters {
173    ///     pub fn update(&mut self, message: Message) {
174    ///         match message {
175    ///             Message::Counter(index, counter_msg) => {
176    ///                 if let Some(counter) = self.counters.get_mut(index) {
177    ///                     counter.update(counter_msg);
178    ///                 }
179    ///             }
180    ///         }
181    ///     }
182    /// }
183    /// ```
184    pub fn map<B>(self, f: impl Fn(Message) -> B + 'a) -> Element<'a, B, Theme, Renderer>
185    where
186        Message: 'a,
187        Theme: 'a,
188        Renderer: crate::Renderer + 'a,
189        B: 'a,
190    {
191        Element::new(Map::new(self.widget, f))
192    }
193
194    /// Marks the [`Element`] as _to-be-explained_.
195    ///
196    /// The [`Renderer`] will explain the layout of the [`Element`] graphically.
197    /// This can be very useful for debugging your layout!
198    ///
199    /// [`Renderer`]: crate::Renderer
200    pub fn explain<C: Into<Color>>(self, color: C) -> Element<'a, Message, Theme, Renderer>
201    where
202        Message: 'a,
203        Theme: 'a,
204        Renderer: crate::Renderer + 'a,
205    {
206        Element {
207            widget: Box::new(Explain::new(self, color.into())),
208        }
209    }
210}
211
212impl<'a, Message, Theme, Renderer> Borrow<dyn Widget<Message, Theme, Renderer> + 'a>
213    for Element<'a, Message, Theme, Renderer>
214{
215    fn borrow(&self) -> &(dyn Widget<Message, Theme, Renderer> + 'a) {
216        self.widget.borrow()
217    }
218}
219
220impl<'a, Message, Theme, Renderer> Borrow<dyn Widget<Message, Theme, Renderer> + 'a>
221    for &Element<'a, Message, Theme, Renderer>
222{
223    fn borrow(&self) -> &(dyn Widget<Message, Theme, Renderer> + 'a) {
224        self.widget.borrow()
225    }
226}
227
228struct Map<'a, A, B, Theme, Renderer> {
229    widget: Box<dyn Widget<A, Theme, Renderer> + 'a>,
230    mapper: Box<dyn Fn(A) -> B + 'a>,
231}
232
233impl<'a, A, B, Theme, Renderer> Map<'a, A, B, Theme, Renderer> {
234    pub fn new<F>(
235        widget: Box<dyn Widget<A, Theme, Renderer> + 'a>,
236        mapper: F,
237    ) -> Map<'a, A, B, Theme, Renderer>
238    where
239        F: 'a + Fn(A) -> B,
240    {
241        Map {
242            widget,
243            mapper: Box::new(mapper),
244        }
245    }
246}
247
248impl<'a, A, B, Theme, Renderer> Widget<B, Theme, Renderer> for Map<'a, A, B, Theme, Renderer>
249where
250    Renderer: crate::Renderer + 'a,
251    A: 'a,
252    B: 'a,
253{
254    fn tag(&self) -> tree::Tag {
255        self.widget.tag()
256    }
257
258    fn state(&self) -> tree::State {
259        self.widget.state()
260    }
261
262    fn children(&self) -> Vec<Tree> {
263        self.widget.children()
264    }
265
266    fn diff(&self, tree: &mut Tree) {
267        self.widget.diff(tree);
268    }
269
270    fn size(&self) -> Size<Length> {
271        self.widget.size()
272    }
273
274    fn size_hint(&self) -> Size<Length> {
275        self.widget.size_hint()
276    }
277
278    fn layout(
279        &mut self,
280        tree: &mut Tree,
281        renderer: &Renderer,
282        limits: &layout::Limits,
283    ) -> layout::Node {
284        self.widget.layout(tree, renderer, limits)
285    }
286
287    fn operate(
288        &mut self,
289        tree: &mut Tree,
290        layout: Layout<'_>,
291        renderer: &Renderer,
292        operation: &mut dyn widget::Operation,
293    ) {
294        self.widget.operate(tree, layout, renderer, operation);
295    }
296
297    fn update(
298        &mut self,
299        tree: &mut Tree,
300        event: &Event,
301        layout: Layout<'_>,
302        cursor: mouse::Cursor,
303        renderer: &Renderer,
304        shell: &mut Shell<'_, B>,
305        viewport: &Rectangle,
306    ) {
307        let mut local_messages = Vec::new();
308        let mut local_shell = Shell::new(&mut local_messages);
309
310        self.widget.update(
311            tree,
312            event,
313            layout,
314            cursor,
315            renderer,
316            &mut local_shell,
317            viewport,
318        );
319
320        shell.merge(local_shell, &self.mapper);
321    }
322
323    fn draw(
324        &self,
325        tree: &Tree,
326        renderer: &mut Renderer,
327        theme: &Theme,
328        style: &renderer::Style,
329        layout: Layout<'_>,
330        cursor: mouse::Cursor,
331        viewport: &Rectangle,
332    ) {
333        self.widget
334            .draw(tree, renderer, theme, style, layout, cursor, viewport);
335    }
336
337    fn mouse_interaction(
338        &self,
339        tree: &Tree,
340        layout: Layout<'_>,
341        cursor: mouse::Cursor,
342        viewport: &Rectangle,
343        renderer: &Renderer,
344    ) -> mouse::Interaction {
345        self.widget
346            .mouse_interaction(tree, layout, cursor, viewport, renderer)
347    }
348
349    fn overlay<'b>(
350        &'b mut self,
351        tree: &'b mut Tree,
352        layout: Layout<'b>,
353        renderer: &Renderer,
354        viewport: &Rectangle,
355        translation: Vector,
356    ) -> Option<overlay::Element<'b, B, Theme, Renderer>> {
357        let mapper = &self.mapper;
358
359        self.widget
360            .overlay(tree, layout, renderer, viewport, translation)
361            .map(move |overlay| overlay.map(mapper))
362    }
363}
364
365struct Explain<'a, Message, Theme, Renderer: crate::Renderer> {
366    element: Element<'a, Message, Theme, Renderer>,
367    color: Color,
368}
369
370impl<'a, Message, Theme, Renderer> Explain<'a, Message, Theme, Renderer>
371where
372    Renderer: crate::Renderer,
373{
374    fn new(element: Element<'a, Message, Theme, Renderer>, color: Color) -> Self {
375        Explain { element, color }
376    }
377}
378
379impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
380    for Explain<'_, Message, Theme, Renderer>
381where
382    Renderer: crate::Renderer,
383{
384    fn size(&self) -> Size<Length> {
385        self.element.widget.size()
386    }
387
388    fn size_hint(&self) -> Size<Length> {
389        self.element.widget.size_hint()
390    }
391
392    fn tag(&self) -> tree::Tag {
393        self.element.widget.tag()
394    }
395
396    fn state(&self) -> tree::State {
397        self.element.widget.state()
398    }
399
400    fn children(&self) -> Vec<Tree> {
401        self.element.widget.children()
402    }
403
404    fn diff(&self, tree: &mut Tree) {
405        self.element.widget.diff(tree);
406    }
407
408    fn layout(
409        &mut self,
410        tree: &mut Tree,
411        renderer: &Renderer,
412        limits: &layout::Limits,
413    ) -> layout::Node {
414        self.element.widget.layout(tree, renderer, limits)
415    }
416
417    fn operate(
418        &mut self,
419        tree: &mut Tree,
420        layout: Layout<'_>,
421        renderer: &Renderer,
422        operation: &mut dyn widget::Operation,
423    ) {
424        self.element
425            .widget
426            .operate(tree, layout, renderer, operation);
427    }
428
429    fn update(
430        &mut self,
431        tree: &mut Tree,
432        event: &Event,
433        layout: Layout<'_>,
434        cursor: mouse::Cursor,
435        renderer: &Renderer,
436        shell: &mut Shell<'_, Message>,
437        viewport: &Rectangle,
438    ) {
439        self.element
440            .widget
441            .update(tree, event, layout, cursor, renderer, shell, viewport);
442    }
443
444    fn draw(
445        &self,
446        tree: &Tree,
447        renderer: &mut Renderer,
448        theme: &Theme,
449        style: &renderer::Style,
450        layout: Layout<'_>,
451        cursor: mouse::Cursor,
452        viewport: &Rectangle,
453    ) {
454        fn explain_layout<Renderer: crate::Renderer>(
455            renderer: &mut Renderer,
456            color: Color,
457            layout: Layout<'_>,
458        ) {
459            renderer.fill_quad(
460                renderer::Quad {
461                    bounds: layout.bounds(),
462                    border: Border {
463                        color,
464                        width: 1.0,
465                        ..Border::default()
466                    },
467                    ..renderer::Quad::default()
468                },
469                Color::TRANSPARENT,
470            );
471
472            for child in layout.children() {
473                explain_layout(renderer, color, child);
474            }
475        }
476
477        self.element
478            .widget
479            .draw(tree, renderer, theme, style, layout, cursor, viewport);
480
481        renderer.with_layer(Rectangle::INFINITE, |renderer| {
482            explain_layout(renderer, self.color, layout);
483        });
484    }
485
486    fn mouse_interaction(
487        &self,
488        tree: &Tree,
489        layout: Layout<'_>,
490        cursor: mouse::Cursor,
491        viewport: &Rectangle,
492        renderer: &Renderer,
493    ) -> mouse::Interaction {
494        self.element
495            .widget
496            .mouse_interaction(tree, layout, cursor, viewport, renderer)
497    }
498
499    fn overlay<'b>(
500        &'b mut self,
501        tree: &'b mut Tree,
502        layout: Layout<'b>,
503        renderer: &Renderer,
504        viewport: &Rectangle,
505        translation: Vector,
506    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
507        self.element
508            .widget
509            .overlay(tree, layout, renderer, viewport, translation)
510    }
511}
512
513impl<'a, T, Message, Theme, Renderer> From<Option<T>> for Element<'a, Message, Theme, Renderer>
514where
515    T: Into<Self>,
516    Renderer: crate::Renderer,
517{
518    fn from(element: Option<T>) -> Self {
519        struct Void;
520
521        impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Void
522        where
523            Renderer: crate::Renderer,
524        {
525            fn size(&self) -> Size<Length> {
526                Size {
527                    width: Length::Fixed(0.0),
528                    height: Length::Fixed(0.0),
529                }
530            }
531
532            fn layout(
533                &mut self,
534                _tree: &mut Tree,
535                _renderer: &Renderer,
536                _limits: &layout::Limits,
537            ) -> layout::Node {
538                layout::Node::new(Size::ZERO)
539            }
540
541            fn draw(
542                &self,
543                _tree: &Tree,
544                _renderer: &mut Renderer,
545                _theme: &Theme,
546                _style: &renderer::Style,
547                _layout: Layout<'_>,
548                _cursor: mouse::Cursor,
549                _viewport: &Rectangle,
550            ) {
551            }
552        }
553
554        element.map(T::into).unwrap_or_else(|| Element::new(Void))
555    }
556}