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