Skip to main content

iced_core/
element.rs

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