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, BorrowMut};
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
228impl<'a, Message, Theme, Renderer> Borrow<dyn Widget<Message, Theme, Renderer> + 'a>
229    for &mut Element<'a, Message, Theme, Renderer>
230{
231    fn borrow(&self) -> &(dyn Widget<Message, Theme, Renderer> + 'a) {
232        self.widget.borrow()
233    }
234}
235
236impl<'a, Message, Theme, Renderer> BorrowMut<dyn Widget<Message, Theme, Renderer> + 'a>
237    for Element<'a, Message, Theme, Renderer>
238{
239    fn borrow_mut(&mut self) -> &mut (dyn Widget<Message, Theme, Renderer> + 'a) {
240        self.widget.borrow_mut()
241    }
242}
243
244impl<'a, Message, Theme, Renderer> BorrowMut<dyn Widget<Message, Theme, Renderer> + 'a>
245    for &mut Element<'a, Message, Theme, Renderer>
246{
247    fn borrow_mut(&mut self) -> &mut (dyn Widget<Message, Theme, Renderer> + 'a) {
248        self.widget.borrow_mut()
249    }
250}
251
252struct Map<'a, A, B, Theme, Renderer> {
253    widget: Box<dyn Widget<A, Theme, Renderer> + 'a>,
254    mapper: Box<dyn Fn(A) -> B + 'a>,
255}
256
257impl<'a, A, B, Theme, Renderer> Map<'a, A, B, Theme, Renderer> {
258    pub fn new<F>(
259        widget: Box<dyn Widget<A, Theme, Renderer> + 'a>,
260        mapper: F,
261    ) -> Map<'a, A, B, Theme, Renderer>
262    where
263        F: 'a + Fn(A) -> B,
264    {
265        Map {
266            widget,
267            mapper: Box::new(mapper),
268        }
269    }
270}
271
272impl<'a, A, B, Theme, Renderer> Widget<B, Theme, Renderer> for Map<'a, A, B, Theme, Renderer>
273where
274    Renderer: crate::Renderer + 'a,
275    A: 'a,
276    B: 'a,
277{
278    fn tag(&self) -> tree::Tag {
279        self.widget.tag()
280    }
281
282    fn state(&self) -> tree::State {
283        self.widget.state()
284    }
285
286    fn diff(&mut self, tree: &mut Tree) {
287        self.widget.diff(tree);
288    }
289
290    fn size(&self) -> Size<Length> {
291        self.widget.size()
292    }
293
294    fn layout(
295        &mut self,
296        tree: &mut Tree,
297        renderer: &Renderer,
298        limits: &layout::Limits,
299    ) -> layout::Node {
300        self.widget.layout(tree, renderer, limits)
301    }
302
303    fn operate(
304        &mut self,
305        tree: &mut Tree,
306        layout: Layout<'_>,
307        renderer: &Renderer,
308        operation: &mut dyn widget::Operation,
309    ) {
310        self.widget.operate(tree, layout, renderer, operation);
311    }
312
313    fn update(
314        &mut self,
315        tree: &mut Tree,
316        event: &Event,
317        layout: Layout<'_>,
318        cursor: mouse::Cursor,
319        renderer: &Renderer,
320        shell: &mut Shell<'_, B>,
321        viewport: &Rectangle,
322    ) {
323        let mut local_messages = Vec::new();
324        let mut local_shell = shell.local(&mut local_messages);
325
326        self.widget.update(
327            tree,
328            event,
329            layout,
330            cursor,
331            renderer,
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(element: Element<'a, Message, Theme, Renderer>, color: Color) -> Self {
391        Explain { element, color }
392    }
393}
394
395impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
396    for Explain<'_, Message, Theme, Renderer>
397where
398    Renderer: crate::Renderer,
399{
400    fn size(&self) -> Size<Length> {
401        self.element.widget.size()
402    }
403
404    fn tag(&self) -> tree::Tag {
405        self.element.widget.tag()
406    }
407
408    fn state(&self) -> tree::State {
409        self.element.widget.state()
410    }
411
412    fn diff(&mut self, tree: &mut Tree) {
413        self.element.widget.diff(tree);
414    }
415
416    fn layout(
417        &mut self,
418        tree: &mut Tree,
419        renderer: &Renderer,
420        limits: &layout::Limits,
421    ) -> layout::Node {
422        self.element.widget.layout(tree, renderer, limits)
423    }
424
425    fn operate(
426        &mut self,
427        tree: &mut Tree,
428        layout: Layout<'_>,
429        renderer: &Renderer,
430        operation: &mut dyn widget::Operation,
431    ) {
432        self.element
433            .widget
434            .operate(tree, layout, renderer, operation);
435    }
436
437    fn update(
438        &mut self,
439        tree: &mut Tree,
440        event: &Event,
441        layout: Layout<'_>,
442        cursor: mouse::Cursor,
443        renderer: &Renderer,
444        shell: &mut Shell<'_, Message>,
445        viewport: &Rectangle,
446    ) {
447        self.element
448            .widget
449            .update(tree, event, layout, cursor, renderer, shell, viewport);
450    }
451
452    fn draw(
453        &self,
454        tree: &Tree,
455        renderer: &mut Renderer,
456        theme: &Theme,
457        style: &renderer::Style,
458        layout: Layout<'_>,
459        cursor: mouse::Cursor,
460        viewport: &Rectangle,
461    ) {
462        fn explain_layout<Renderer: crate::Renderer>(
463            renderer: &mut Renderer,
464            color: Color,
465            layout: Layout<'_>,
466        ) {
467            renderer.fill_quad(
468                renderer::Quad {
469                    bounds: layout.bounds(),
470                    border: Border {
471                        color,
472                        width: 1.0,
473                        ..Border::default()
474                    },
475                    ..renderer::Quad::default()
476                },
477                Color::TRANSPARENT,
478            );
479
480            for child in layout.children() {
481                explain_layout(renderer, color, child);
482            }
483        }
484
485        self.element
486            .widget
487            .draw(tree, renderer, theme, style, layout, cursor, viewport);
488
489        renderer.with_layer(Rectangle::INFINITE, |renderer| {
490            explain_layout(renderer, self.color, layout);
491        });
492    }
493
494    fn mouse_interaction(
495        &self,
496        tree: &Tree,
497        layout: Layout<'_>,
498        cursor: mouse::Cursor,
499        viewport: &Rectangle,
500        renderer: &Renderer,
501    ) -> mouse::Interaction {
502        self.element
503            .widget
504            .mouse_interaction(tree, layout, cursor, viewport, renderer)
505    }
506
507    fn overlay<'b>(
508        &'b mut self,
509        tree: &'b mut Tree,
510        layout: Layout<'b>,
511        renderer: &Renderer,
512        viewport: &Rectangle,
513        translation: Vector,
514    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
515        self.element
516            .widget
517            .overlay(tree, layout, renderer, viewport, translation)
518    }
519}
520
521impl<'a, T, Message, Theme, Renderer> From<Option<T>> for Element<'a, Message, Theme, Renderer>
522where
523    T: Into<Self>,
524    Renderer: crate::Renderer,
525{
526    fn from(element: Option<T>) -> Self {
527        struct Void;
528
529        impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Void
530        where
531            Renderer: crate::Renderer,
532        {
533            fn size(&self) -> Size<Length> {
534                Size {
535                    width: Length::Fixed(0.0),
536                    height: Length::Fixed(0.0),
537                }
538            }
539
540            fn layout(
541                &mut self,
542                _tree: &mut Tree,
543                _renderer: &Renderer,
544                _limits: &layout::Limits,
545            ) -> layout::Node {
546                layout::Node::new(Size::ZERO)
547            }
548
549            fn draw(
550                &self,
551                _tree: &Tree,
552                _renderer: &mut Renderer,
553                _theme: &Theme,
554                _style: &renderer::Style,
555                _layout: Layout<'_>,
556                _cursor: mouse::Cursor,
557                _viewport: &Rectangle,
558            ) {
559            }
560        }
561
562        element.map(T::into).unwrap_or_else(|| Element::new(Void))
563    }
564}