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
23#[allow(missing_debug_implementations)]
24pub struct Element<'a, Message, Theme, Renderer> {
25    widget: Box<dyn Widget<Message, Theme, Renderer> + 'a>,
26}
27
28impl<'a, Message, Theme, Renderer> Element<'a, Message, Theme, Renderer> {
29    /// Creates a new [`Element`] containing the given [`Widget`].
30    pub fn new(widget: impl Widget<Message, Theme, Renderer> + 'a) -> Self
31    where
32        Renderer: crate::Renderer,
33    {
34        Self {
35            widget: Box::new(widget),
36        }
37    }
38
39    /// Returns a reference to the [`Widget`] of the [`Element`],
40    pub fn as_widget(&self) -> &dyn Widget<Message, Theme, Renderer> {
41        self.widget.as_ref()
42    }
43
44    /// Returns a mutable reference to the [`Widget`] of the [`Element`],
45    pub fn as_widget_mut(
46        &mut self,
47    ) -> &mut dyn Widget<Message, Theme, Renderer> {
48        self.widget.as_mut()
49    }
50
51    /// Applies a transformation to the produced message of the [`Element`].
52    ///
53    /// This method is useful when you want to decouple different parts of your
54    /// UI and make them __composable__.
55    ///
56    /// # Example
57    /// Imagine we want to use [our counter](index.html#usage). But instead of
58    /// showing a single counter, we want to display many of them. We can reuse
59    /// the `Counter` type as it is!
60    ///
61    /// We use composition to model the __state__ of our new application:
62    ///
63    /// ```
64    /// # mod counter {
65    /// #     pub struct Counter;
66    /// # }
67    /// use counter::Counter;
68    ///
69    /// struct ManyCounters {
70    ///     counters: Vec<Counter>,
71    /// }
72    /// ```
73    ///
74    /// We can store the state of multiple counters now. However, the
75    /// __messages__ we implemented before describe the user interactions
76    /// of a __single__ counter. Right now, we need to also identify which
77    /// counter is receiving user interactions. Can we use composition again?
78    /// Yes.
79    ///
80    /// ```
81    /// # mod counter {
82    /// #     #[derive(Debug, Clone, Copy)]
83    /// #     pub enum Message {}
84    /// # }
85    /// #[derive(Debug, Clone, Copy)]
86    /// pub enum Message {
87    ///     Counter(usize, counter::Message)
88    /// }
89    /// ```
90    ///
91    /// We compose the previous __messages__ with the index of the counter
92    /// producing them. Let's implement our __view logic__ now:
93    ///
94    /// ```no_run
95    /// # mod iced {
96    /// #     pub use iced_core::Function;
97    /// #     pub type Element<'a, Message> = iced_core::Element<'a, Message, iced_core::Theme, ()>;
98    /// #
99    /// #     pub mod widget {
100    /// #         pub fn row<'a, Message>(iter: impl IntoIterator<Item = super::Element<'a, Message>>) -> super::Element<'a, Message> {
101    /// #             unimplemented!()
102    /// #         }
103    /// #     }
104    /// # }
105    /// #
106    /// # mod counter {
107    /// #     #[derive(Debug, Clone, Copy)]
108    /// #     pub enum Message {}
109    /// #     pub struct Counter;
110    /// #
111    /// #     pub type Element<'a, Message> = iced_core::Element<'a, Message, iced_core::Theme, ()>;
112    /// #
113    /// #     impl Counter {
114    /// #         pub fn view(&self) -> Element<Message> {
115    /// #             unimplemented!()
116    /// #         }
117    /// #     }
118    /// # }
119    /// #
120    /// use counter::Counter;
121    ///
122    /// use iced::widget::row;
123    /// use iced::{Element, Function};
124    ///
125    /// struct ManyCounters {
126    ///     counters: Vec<Counter>,
127    /// }
128    ///
129    /// #[derive(Debug, Clone, Copy)]
130    /// pub enum Message {
131    ///     Counter(usize, counter::Message),
132    /// }
133    ///
134    /// impl ManyCounters {
135    ///     pub fn view(&self) -> Element<Message> {
136    ///         // We can quickly populate a `row` by mapping our counters
137    ///         row(
138    ///             self.counters
139    ///                 .iter()
140    ///                 .map(Counter::view)
141    ///                 .enumerate()
142    ///                 .map(|(index, counter)| {
143    ///                     // Here we turn our `Element<counter::Message>` into
144    ///                     // an `Element<Message>` by combining the `index` and the
145    ///                     // message of the `element`.
146    ///                     counter.map(Message::Counter.with(index))
147    ///                 }),
148    ///         )
149    ///         .into()
150    ///     }
151    /// }
152    /// ```
153    ///
154    /// Finally, our __update logic__ is pretty straightforward: simple
155    /// delegation.
156    ///
157    /// ```
158    /// # mod counter {
159    /// #     #[derive(Debug, Clone, Copy)]
160    /// #     pub enum Message {}
161    /// #     pub struct Counter;
162    /// #
163    /// #     impl Counter {
164    /// #         pub fn update(&mut self, _message: Message) {}
165    /// #     }
166    /// # }
167    /// #
168    /// # use counter::Counter;
169    /// #
170    /// # struct ManyCounters {
171    /// #     counters: Vec<Counter>,
172    /// # }
173    /// #
174    /// # #[derive(Debug, Clone, Copy)]
175    /// # pub enum Message {
176    /// #    Counter(usize, counter::Message)
177    /// # }
178    /// impl ManyCounters {
179    ///     pub fn update(&mut self, message: Message) {
180    ///         match message {
181    ///             Message::Counter(index, counter_msg) => {
182    ///                 if let Some(counter) = self.counters.get_mut(index) {
183    ///                     counter.update(counter_msg);
184    ///                 }
185    ///             }
186    ///         }
187    ///     }
188    /// }
189    /// ```
190    pub fn map<B>(
191        self,
192        f: impl Fn(Message) -> B + 'a,
193    ) -> Element<'a, B, Theme, Renderer>
194    where
195        Message: 'a,
196        Theme: 'a,
197        Renderer: crate::Renderer + 'a,
198        B: 'a,
199    {
200        Element::new(Map::new(self.widget, f))
201    }
202
203    /// Marks the [`Element`] as _to-be-explained_.
204    ///
205    /// The [`Renderer`] will explain the layout of the [`Element`] graphically.
206    /// This can be very useful for debugging your layout!
207    ///
208    /// [`Renderer`]: crate::Renderer
209    pub fn explain<C: Into<Color>>(
210        self,
211        color: C,
212    ) -> Element<'a, Message, Theme, Renderer>
213    where
214        Message: 'a,
215        Theme: 'a,
216        Renderer: crate::Renderer + 'a,
217    {
218        Element {
219            widget: Box::new(Explain::new(self, color.into())),
220        }
221    }
222}
223
224impl<'a, Message, Theme, Renderer>
225    Borrow<dyn Widget<Message, Theme, Renderer> + 'a>
226    for Element<'a, Message, Theme, Renderer>
227{
228    fn borrow(&self) -> &(dyn Widget<Message, Theme, Renderer> + 'a) {
229        self.widget.borrow()
230    }
231}
232
233impl<'a, Message, Theme, Renderer>
234    Borrow<dyn Widget<Message, Theme, Renderer> + 'a>
235    for &Element<'a, Message, Theme, Renderer>
236{
237    fn borrow(&self) -> &(dyn Widget<Message, Theme, Renderer> + 'a) {
238        self.widget.borrow()
239    }
240}
241
242struct Map<'a, A, B, Theme, Renderer> {
243    widget: Box<dyn Widget<A, Theme, Renderer> + 'a>,
244    mapper: Box<dyn Fn(A) -> B + 'a>,
245}
246
247impl<'a, A, B, Theme, Renderer> Map<'a, A, B, Theme, Renderer> {
248    pub fn new<F>(
249        widget: Box<dyn Widget<A, Theme, Renderer> + 'a>,
250        mapper: F,
251    ) -> Map<'a, A, B, Theme, Renderer>
252    where
253        F: 'a + Fn(A) -> B,
254    {
255        Map {
256            widget,
257            mapper: Box::new(mapper),
258        }
259    }
260}
261
262impl<'a, A, B, Theme, Renderer> Widget<B, Theme, Renderer>
263    for Map<'a, A, B, Theme, Renderer>
264where
265    Renderer: crate::Renderer + 'a,
266    A: 'a,
267    B: 'a,
268{
269    fn tag(&self) -> tree::Tag {
270        self.widget.tag()
271    }
272
273    fn state(&self) -> tree::State {
274        self.widget.state()
275    }
276
277    fn children(&self) -> Vec<Tree> {
278        self.widget.children()
279    }
280
281    fn diff(&self, tree: &mut Tree) {
282        self.widget.diff(tree);
283    }
284
285    fn size(&self) -> Size<Length> {
286        self.widget.size()
287    }
288
289    fn size_hint(&self) -> Size<Length> {
290        self.widget.size_hint()
291    }
292
293    fn layout(
294        &self,
295        tree: &mut Tree,
296        renderer: &Renderer,
297        limits: &layout::Limits,
298    ) -> layout::Node {
299        self.widget.layout(tree, renderer, limits)
300    }
301
302    fn operate(
303        &self,
304        tree: &mut Tree,
305        layout: Layout<'_>,
306        renderer: &Renderer,
307        operation: &mut dyn widget::Operation,
308    ) {
309        self.widget.operate(tree, layout, renderer, operation);
310    }
311
312    fn update(
313        &mut self,
314        tree: &mut Tree,
315        event: &Event,
316        layout: Layout<'_>,
317        cursor: mouse::Cursor,
318        renderer: &Renderer,
319        clipboard: &mut dyn Clipboard,
320        shell: &mut Shell<'_, B>,
321        viewport: &Rectangle,
322    ) {
323        let mut local_messages = Vec::new();
324        let mut local_shell = Shell::new(&mut local_messages);
325
326        self.widget.update(
327            tree,
328            event,
329            layout,
330            cursor,
331            renderer,
332            clipboard,
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<'_>,
370        renderer: &Renderer,
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, 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        &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        &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<'_>,
521        renderer: &Renderer,
522        translation: Vector,
523    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
524        self.element
525            .widget
526            .overlay(state, layout, renderer, translation)
527    }
528}