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