iced_runtime/overlay/
nested.rs

1use crate::core::event;
2use crate::core::layout;
3use crate::core::mouse;
4use crate::core::overlay;
5use crate::core::renderer;
6use crate::core::widget;
7use crate::core::{Clipboard, Event, Layout, Point, Rectangle, Shell, Size};
8
9/// An overlay container that displays nested overlays
10#[allow(missing_debug_implementations)]
11pub struct Nested<'a, Message, Theme, Renderer> {
12    overlay: overlay::Element<'a, Message, Theme, Renderer>,
13}
14
15impl<'a, Message, Theme, Renderer> Nested<'a, Message, Theme, Renderer>
16where
17    Renderer: renderer::Renderer,
18{
19    /// Creates a nested overlay from the provided [`overlay::Element`]
20    pub fn new(
21        element: overlay::Element<'a, Message, Theme, Renderer>,
22    ) -> Self {
23        Self { overlay: element }
24    }
25
26    /// Returns the layout [`Node`] of the [`Nested`] overlay.
27    ///
28    /// [`Node`]: layout::Node
29    pub fn layout(
30        &mut self,
31        renderer: &Renderer,
32        bounds: Size,
33    ) -> layout::Node {
34        fn recurse<Message, Theme, Renderer>(
35            element: &mut overlay::Element<'_, Message, Theme, Renderer>,
36            renderer: &Renderer,
37            bounds: Size,
38        ) -> layout::Node
39        where
40            Renderer: renderer::Renderer,
41        {
42            let node = element.layout(renderer, bounds);
43
44            if let Some(mut nested) =
45                element.overlay(Layout::new(&node), renderer)
46            {
47                layout::Node::with_children(
48                    node.size(),
49                    vec![node, recurse(&mut nested, renderer, bounds)],
50                )
51            } else {
52                layout::Node::with_children(node.size(), vec![node])
53            }
54        }
55
56        recurse(&mut self.overlay, renderer, bounds)
57    }
58
59    /// Draws the [`Nested`] overlay using the associated `Renderer`.
60    pub fn draw(
61        &mut self,
62        renderer: &mut Renderer,
63        theme: &Theme,
64        style: &renderer::Style,
65        layout: Layout<'_>,
66        cursor: mouse::Cursor,
67    ) {
68        fn recurse<Message, Theme, Renderer>(
69            element: &mut overlay::Element<'_, Message, Theme, Renderer>,
70            layout: Layout<'_>,
71            renderer: &mut Renderer,
72            theme: &Theme,
73            style: &renderer::Style,
74            cursor: mouse::Cursor,
75        ) where
76            Renderer: renderer::Renderer,
77        {
78            let mut layouts = layout.children();
79
80            if let Some(layout) = layouts.next() {
81                let nested_layout = layouts.next();
82
83                let is_over = cursor
84                    .position()
85                    .zip(nested_layout)
86                    .and_then(|(cursor_position, nested_layout)| {
87                        element.overlay(layout, renderer).map(|nested| {
88                            nested.is_over(
89                                nested_layout.children().next().unwrap(),
90                                renderer,
91                                cursor_position,
92                            )
93                        })
94                    })
95                    .unwrap_or_default();
96
97                renderer.with_layer(layout.bounds(), |renderer| {
98                    element.draw(
99                        renderer,
100                        theme,
101                        style,
102                        layout,
103                        if is_over {
104                            mouse::Cursor::Unavailable
105                        } else {
106                            cursor
107                        },
108                    );
109                });
110
111                if let Some((mut nested, nested_layout)) =
112                    element.overlay(layout, renderer).zip(nested_layout)
113                {
114                    recurse(
115                        &mut nested,
116                        nested_layout,
117                        renderer,
118                        theme,
119                        style,
120                        cursor,
121                    );
122                }
123            }
124        }
125
126        recurse(&mut self.overlay, layout, renderer, theme, style, cursor);
127    }
128
129    /// Applies a [`widget::Operation`] to the [`Nested`] overlay.
130    pub fn operate(
131        &mut self,
132        layout: Layout<'_>,
133        renderer: &Renderer,
134        operation: &mut dyn widget::Operation,
135    ) {
136        fn recurse<Message, Theme, Renderer>(
137            element: &mut overlay::Element<'_, Message, Theme, Renderer>,
138            layout: Layout<'_>,
139            renderer: &Renderer,
140            operation: &mut dyn widget::Operation,
141        ) where
142            Renderer: renderer::Renderer,
143        {
144            let mut layouts = layout.children();
145
146            if let Some(layout) = layouts.next() {
147                element.operate(layout, renderer, operation);
148
149                if let Some((mut nested, nested_layout)) =
150                    element.overlay(layout, renderer).zip(layouts.next())
151                {
152                    recurse(&mut nested, nested_layout, renderer, operation);
153                }
154            }
155        }
156
157        recurse(&mut self.overlay, layout, renderer, operation);
158    }
159
160    /// Processes a runtime [`Event`].
161    pub fn update(
162        &mut self,
163        event: &Event,
164        layout: Layout<'_>,
165        cursor: mouse::Cursor,
166        renderer: &Renderer,
167        clipboard: &mut dyn Clipboard,
168        shell: &mut Shell<'_, Message>,
169    ) {
170        fn recurse<Message, Theme, Renderer>(
171            element: &mut overlay::Element<'_, Message, Theme, Renderer>,
172            layout: Layout<'_>,
173            event: &Event,
174            cursor: mouse::Cursor,
175            renderer: &Renderer,
176            clipboard: &mut dyn Clipboard,
177            shell: &mut Shell<'_, Message>,
178        ) -> bool
179        where
180            Renderer: renderer::Renderer,
181        {
182            let mut layouts = layout.children();
183
184            if let Some(layout) = layouts.next() {
185                let nested_is_over = if let Some((mut nested, nested_layout)) =
186                    element.overlay(layout, renderer).zip(layouts.next())
187                {
188                    recurse(
189                        &mut nested,
190                        nested_layout,
191                        event,
192                        cursor,
193                        renderer,
194                        clipboard,
195                        shell,
196                    )
197                } else {
198                    false
199                };
200
201                if shell.event_status() == event::Status::Ignored {
202                    let is_over = nested_is_over
203                        || cursor
204                            .position()
205                            .map(|cursor_position| {
206                                element.is_over(
207                                    layout,
208                                    renderer,
209                                    cursor_position,
210                                )
211                            })
212                            .unwrap_or_default();
213
214                    element.update(
215                        event,
216                        layout,
217                        if nested_is_over {
218                            mouse::Cursor::Unavailable
219                        } else {
220                            cursor
221                        },
222                        renderer,
223                        clipboard,
224                        shell,
225                    );
226
227                    is_over
228                } else {
229                    nested_is_over
230                }
231            } else {
232                false
233            }
234        }
235
236        let _ = recurse(
237            &mut self.overlay,
238            layout,
239            event,
240            cursor,
241            renderer,
242            clipboard,
243            shell,
244        );
245    }
246
247    /// Returns the current [`mouse::Interaction`] of the [`Nested`] overlay.
248    pub fn mouse_interaction(
249        &mut self,
250        layout: Layout<'_>,
251        cursor: mouse::Cursor,
252        viewport: &Rectangle,
253        renderer: &Renderer,
254    ) -> mouse::Interaction {
255        fn recurse<Message, Theme, Renderer>(
256            element: &mut overlay::Element<'_, Message, Theme, Renderer>,
257            layout: Layout<'_>,
258            cursor: mouse::Cursor,
259            viewport: &Rectangle,
260            renderer: &Renderer,
261        ) -> Option<mouse::Interaction>
262        where
263            Renderer: renderer::Renderer,
264        {
265            let mut layouts = layout.children();
266
267            let layout = layouts.next()?;
268            let cursor_position = cursor.position()?;
269
270            if !element.is_over(layout, renderer, cursor_position) {
271                return None;
272            }
273
274            Some(
275                element
276                    .overlay(layout, renderer)
277                    .zip(layouts.next())
278                    .and_then(|(mut overlay, layout)| {
279                        recurse(
280                            &mut overlay,
281                            layout,
282                            cursor,
283                            viewport,
284                            renderer,
285                        )
286                    })
287                    .unwrap_or_else(|| {
288                        element.mouse_interaction(
289                            layout, cursor, viewport, renderer,
290                        )
291                    }),
292            )
293        }
294
295        recurse(&mut self.overlay, layout, cursor, viewport, renderer)
296            .unwrap_or_default()
297    }
298
299    /// Returns true if the cursor is over the [`Nested`] overlay.
300    pub fn is_over(
301        &mut self,
302        layout: Layout<'_>,
303        renderer: &Renderer,
304        cursor_position: Point,
305    ) -> bool {
306        fn recurse<Message, Theme, Renderer>(
307            element: &mut overlay::Element<'_, Message, Theme, Renderer>,
308            layout: Layout<'_>,
309            renderer: &Renderer,
310            cursor_position: Point,
311        ) -> bool
312        where
313            Renderer: renderer::Renderer,
314        {
315            let mut layouts = layout.children();
316
317            if let Some(layout) = layouts.next() {
318                if element.is_over(layout, renderer, cursor_position) {
319                    return true;
320                }
321
322                if let Some((mut nested, nested_layout)) =
323                    element.overlay(layout, renderer).zip(layouts.next())
324                {
325                    recurse(
326                        &mut nested,
327                        nested_layout,
328                        renderer,
329                        cursor_position,
330                    )
331                } else {
332                    false
333                }
334            } else {
335                false
336            }
337        }
338
339        recurse(&mut self.overlay, layout, renderer, cursor_position)
340    }
341}