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