iced_native/
element.rs

1use crate::event::{self, Event};
2use crate::layout;
3use crate::mouse;
4use crate::overlay;
5use crate::renderer;
6use crate::widget;
7use crate::widget::tree::{self, Tree};
8use crate::{
9    Clipboard, Color, Layout, Length, Point, Rectangle, Shell, Widget,
10};
11
12use std::any::Any;
13use std::borrow::Borrow;
14
15/// A generic [`Widget`].
16///
17/// It is useful to build composable user interfaces that do not leak
18/// implementation details in their __view logic__.
19///
20/// If you have a [built-in widget], you should be able to use `Into<Element>`
21/// to turn it into an [`Element`].
22///
23/// [built-in widget]: crate::widget
24#[allow(missing_debug_implementations)]
25pub struct Element<'a, Message, Renderer> {
26    widget: Box<dyn Widget<Message, Renderer> + 'a>,
27}
28
29impl<'a, Message, Renderer> Element<'a, Message, Renderer> {
30    /// Creates a new [`Element`] containing the given [`Widget`].
31    pub fn new(widget: impl Widget<Message, Renderer> + 'a) -> Self
32    where
33        Renderer: crate::Renderer,
34    {
35        Self {
36            widget: Box::new(widget),
37        }
38    }
39
40    /// Returns a reference to the [`Widget`] of the [`Element`],
41    pub fn as_widget(&self) -> &dyn Widget<Message, Renderer> {
42        self.widget.as_ref()
43    }
44
45    /// Returns a mutable reference to the [`Widget`] of the [`Element`],
46    pub fn as_widget_mut(&mut self) -> &mut dyn Widget<Message, 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    /// ```
94    /// # mod counter {
95    /// #     type Text<'a> = iced_native::widget::Text<'a, iced_native::renderer::Null>;
96    /// #
97    /// #     #[derive(Debug, Clone, Copy)]
98    /// #     pub enum Message {}
99    /// #     pub struct Counter;
100    /// #
101    /// #     impl Counter {
102    /// #         pub fn view(&mut self) -> Text {
103    /// #             Text::new("")
104    /// #         }
105    /// #     }
106    /// # }
107    /// #
108    /// # mod iced_wgpu {
109    /// #     pub use iced_native::renderer::Null as Renderer;
110    /// # }
111    /// #
112    /// # use counter::Counter;
113    /// #
114    /// # struct ManyCounters {
115    /// #     counters: Vec<Counter>,
116    /// # }
117    /// #
118    /// # #[derive(Debug, Clone, Copy)]
119    /// # pub enum Message {
120    /// #    Counter(usize, counter::Message)
121    /// # }
122    /// use iced_native::Element;
123    /// use iced_native::widget::Row;
124    /// use iced_wgpu::Renderer;
125    ///
126    /// impl ManyCounters {
127    ///     pub fn view(&mut self) -> Row<Message, Renderer> {
128    ///         // We can quickly populate a `Row` by folding over our counters
129    ///         self.counters.iter_mut().enumerate().fold(
130    ///             Row::new().spacing(20),
131    ///             |row, (index, counter)| {
132    ///                 // We display the counter
133    ///                 let element: Element<counter::Message, Renderer> =
134    ///                     counter.view().into();
135    ///
136    ///                 row.push(
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    ///                     element.map(move |message| Message::Counter(index, message))
141    ///                 )
142    ///             }
143    ///         )
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>(
185        self,
186        f: impl Fn(Message) -> B + 'a,
187    ) -> Element<'a, B, Renderer>
188    where
189        Message: '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>>(
203        self,
204        color: C,
205    ) -> Element<'a, Message, Renderer>
206    where
207        Message: 'static,
208        Renderer: crate::Renderer + 'a,
209    {
210        Element {
211            widget: Box::new(Explain::new(self, color.into())),
212        }
213    }
214}
215
216impl<'a, Message, Renderer> Borrow<dyn Widget<Message, Renderer> + 'a>
217    for Element<'a, Message, Renderer>
218{
219    fn borrow(&self) -> &(dyn Widget<Message, Renderer> + 'a) {
220        self.widget.borrow()
221    }
222}
223
224impl<'a, Message, Renderer> Borrow<dyn Widget<Message, Renderer> + 'a>
225    for &Element<'a, Message, Renderer>
226{
227    fn borrow(&self) -> &(dyn Widget<Message, Renderer> + 'a) {
228        self.widget.borrow()
229    }
230}
231
232struct Map<'a, A, B, Renderer> {
233    widget: Box<dyn Widget<A, Renderer> + 'a>,
234    mapper: Box<dyn Fn(A) -> B + 'a>,
235}
236
237impl<'a, A, B, Renderer> Map<'a, A, B, Renderer> {
238    pub fn new<F>(
239        widget: Box<dyn Widget<A, Renderer> + 'a>,
240        mapper: F,
241    ) -> Map<'a, A, B, Renderer>
242    where
243        F: 'a + Fn(A) -> B,
244    {
245        Map {
246            widget,
247            mapper: Box::new(mapper),
248        }
249    }
250}
251
252impl<'a, A, B, Renderer> Widget<B, Renderer> for Map<'a, A, B, Renderer>
253where
254    Renderer: crate::Renderer + 'a,
255    A: 'a,
256    B: 'a,
257{
258    fn tag(&self) -> tree::Tag {
259        self.widget.tag()
260    }
261
262    fn state(&self) -> tree::State {
263        self.widget.state()
264    }
265
266    fn children(&self) -> Vec<Tree> {
267        self.widget.children()
268    }
269
270    fn diff(&self, tree: &mut Tree) {
271        self.widget.diff(tree)
272    }
273
274    fn width(&self) -> Length {
275        self.widget.width()
276    }
277
278    fn height(&self) -> Length {
279        self.widget.height()
280    }
281
282    fn layout(
283        &self,
284        renderer: &Renderer,
285        limits: &layout::Limits,
286    ) -> layout::Node {
287        self.widget.layout(renderer, limits)
288    }
289
290    fn operate(
291        &self,
292        tree: &mut Tree,
293        layout: Layout<'_>,
294        renderer: &Renderer,
295        operation: &mut dyn widget::Operation<B>,
296    ) {
297        struct MapOperation<'a, B> {
298            operation: &'a mut dyn widget::Operation<B>,
299        }
300
301        impl<'a, T, B> widget::Operation<T> for MapOperation<'a, B> {
302            fn container(
303                &mut self,
304                id: Option<&widget::Id>,
305                operate_on_children: &mut dyn FnMut(
306                    &mut dyn widget::Operation<T>,
307                ),
308            ) {
309                self.operation.container(id, &mut |operation| {
310                    operate_on_children(&mut MapOperation { operation });
311                });
312            }
313
314            fn focusable(
315                &mut self,
316                state: &mut dyn widget::operation::Focusable,
317                id: Option<&widget::Id>,
318            ) {
319                self.operation.focusable(state, id);
320            }
321
322            fn scrollable(
323                &mut self,
324                state: &mut dyn widget::operation::Scrollable,
325                id: Option<&widget::Id>,
326            ) {
327                self.operation.scrollable(state, id);
328            }
329
330            fn text_input(
331                &mut self,
332                state: &mut dyn widget::operation::TextInput,
333                id: Option<&widget::Id>,
334            ) {
335                self.operation.text_input(state, id);
336            }
337
338            fn custom(&mut self, state: &mut dyn Any, id: Option<&widget::Id>) {
339                self.operation.custom(state, id);
340            }
341        }
342
343        self.widget.operate(
344            tree,
345            layout,
346            renderer,
347            &mut MapOperation { operation },
348        );
349    }
350
351    fn on_event(
352        &mut self,
353        tree: &mut Tree,
354        event: Event,
355        layout: Layout<'_>,
356        cursor_position: Point,
357        renderer: &Renderer,
358        clipboard: &mut dyn Clipboard,
359        shell: &mut Shell<'_, B>,
360    ) -> event::Status {
361        let mut local_messages = Vec::new();
362        let mut local_shell = Shell::new(&mut local_messages);
363
364        let status = self.widget.on_event(
365            tree,
366            event,
367            layout,
368            cursor_position,
369            renderer,
370            clipboard,
371            &mut local_shell,
372        );
373
374        shell.merge(local_shell, &self.mapper);
375
376        status
377    }
378
379    fn draw(
380        &self,
381        tree: &Tree,
382        renderer: &mut Renderer,
383        theme: &Renderer::Theme,
384        style: &renderer::Style,
385        layout: Layout<'_>,
386        cursor_position: Point,
387        viewport: &Rectangle,
388    ) {
389        self.widget.draw(
390            tree,
391            renderer,
392            theme,
393            style,
394            layout,
395            cursor_position,
396            viewport,
397        )
398    }
399
400    fn mouse_interaction(
401        &self,
402        tree: &Tree,
403        layout: Layout<'_>,
404        cursor_position: Point,
405        viewport: &Rectangle,
406        renderer: &Renderer,
407    ) -> mouse::Interaction {
408        self.widget.mouse_interaction(
409            tree,
410            layout,
411            cursor_position,
412            viewport,
413            renderer,
414        )
415    }
416
417    fn overlay<'b>(
418        &'b mut self,
419        tree: &'b mut Tree,
420        layout: Layout<'_>,
421        renderer: &Renderer,
422    ) -> Option<overlay::Element<'b, B, Renderer>> {
423        let mapper = &self.mapper;
424
425        self.widget
426            .overlay(tree, layout, renderer)
427            .map(move |overlay| overlay.map(mapper))
428    }
429}
430
431struct Explain<'a, Message, Renderer: crate::Renderer> {
432    element: Element<'a, Message, Renderer>,
433    color: Color,
434}
435
436impl<'a, Message, Renderer> Explain<'a, Message, Renderer>
437where
438    Renderer: crate::Renderer,
439{
440    fn new(element: Element<'a, Message, Renderer>, color: Color) -> Self {
441        Explain { element, color }
442    }
443}
444
445impl<'a, Message, Renderer> Widget<Message, Renderer>
446    for Explain<'a, Message, Renderer>
447where
448    Renderer: crate::Renderer,
449{
450    fn width(&self) -> Length {
451        self.element.widget.width()
452    }
453
454    fn height(&self) -> Length {
455        self.element.widget.height()
456    }
457
458    fn tag(&self) -> tree::Tag {
459        self.element.widget.tag()
460    }
461
462    fn state(&self) -> tree::State {
463        self.element.widget.state()
464    }
465
466    fn children(&self) -> Vec<Tree> {
467        self.element.widget.children()
468    }
469
470    fn diff(&self, tree: &mut Tree) {
471        self.element.widget.diff(tree);
472    }
473
474    fn layout(
475        &self,
476        renderer: &Renderer,
477        limits: &layout::Limits,
478    ) -> layout::Node {
479        self.element.widget.layout(renderer, limits)
480    }
481
482    fn operate(
483        &self,
484        state: &mut Tree,
485        layout: Layout<'_>,
486        renderer: &Renderer,
487        operation: &mut dyn widget::Operation<Message>,
488    ) {
489        self.element
490            .widget
491            .operate(state, layout, renderer, operation)
492    }
493
494    fn on_event(
495        &mut self,
496        state: &mut Tree,
497        event: Event,
498        layout: Layout<'_>,
499        cursor_position: Point,
500        renderer: &Renderer,
501        clipboard: &mut dyn Clipboard,
502        shell: &mut Shell<'_, Message>,
503    ) -> event::Status {
504        self.element.widget.on_event(
505            state,
506            event,
507            layout,
508            cursor_position,
509            renderer,
510            clipboard,
511            shell,
512        )
513    }
514
515    fn draw(
516        &self,
517        state: &Tree,
518        renderer: &mut Renderer,
519        theme: &Renderer::Theme,
520        style: &renderer::Style,
521        layout: Layout<'_>,
522        cursor_position: Point,
523        viewport: &Rectangle,
524    ) {
525        fn explain_layout<Renderer: crate::Renderer>(
526            renderer: &mut Renderer,
527            color: Color,
528            layout: Layout<'_>,
529        ) {
530            renderer.fill_quad(
531                renderer::Quad {
532                    bounds: layout.bounds(),
533                    border_color: color,
534                    border_width: 1.0,
535                    border_radius: 0.0.into(),
536                },
537                Color::TRANSPARENT,
538            );
539
540            for child in layout.children() {
541                explain_layout(renderer, color, child);
542            }
543        }
544
545        self.element.widget.draw(
546            state,
547            renderer,
548            theme,
549            style,
550            layout,
551            cursor_position,
552            viewport,
553        );
554
555        explain_layout(renderer, self.color, layout);
556    }
557
558    fn mouse_interaction(
559        &self,
560        state: &Tree,
561        layout: Layout<'_>,
562        cursor_position: Point,
563        viewport: &Rectangle,
564        renderer: &Renderer,
565    ) -> mouse::Interaction {
566        self.element.widget.mouse_interaction(
567            state,
568            layout,
569            cursor_position,
570            viewport,
571            renderer,
572        )
573    }
574
575    fn overlay<'b>(
576        &'b mut self,
577        state: &'b mut Tree,
578        layout: Layout<'_>,
579        renderer: &Renderer,
580    ) -> Option<overlay::Element<'b, Message, Renderer>> {
581        self.element.widget.overlay(state, layout, renderer)
582    }
583}