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, 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 overlay = element.as_overlay_mut();
43            let node = overlay.layout(renderer, bounds);
44
45            let nested_node = overlay
46                .overlay(Layout::new(&node), renderer)
47                .as_mut()
48                .map(|nested| recurse(nested, renderer, bounds));
49
50            if let Some(nested_node) = nested_node {
51                layout::Node::with_children(
52                    node.size(),
53                    vec![node, nested_node],
54                )
55            } else {
56                layout::Node::with_children(node.size(), vec![node])
57            }
58        }
59
60        recurse(&mut self.overlay, renderer, bounds)
61    }
62
63    /// Draws the [`Nested`] overlay using the associated `Renderer`.
64    pub fn draw(
65        &mut self,
66        renderer: &mut Renderer,
67        theme: &Theme,
68        style: &renderer::Style,
69        layout: Layout<'_>,
70        cursor: mouse::Cursor,
71    ) {
72        fn recurse<Message, Theme, Renderer>(
73            element: &mut overlay::Element<'_, Message, Theme, Renderer>,
74            layout: Layout<'_>,
75            renderer: &mut Renderer,
76            theme: &Theme,
77            style: &renderer::Style,
78            cursor: mouse::Cursor,
79        ) where
80            Renderer: renderer::Renderer,
81        {
82            let mut layouts = layout.children();
83
84            if let Some(layout) = layouts.next() {
85                let nested_layout = layouts.next();
86                let overlay = element.as_overlay_mut();
87
88                let is_over = cursor
89                    .position()
90                    .zip(nested_layout)
91                    .and_then(|(cursor_position, nested_layout)| {
92                        overlay.overlay(layout, renderer).map(|nested| {
93                            nested.as_overlay().mouse_interaction(
94                                nested_layout.children().next().unwrap(),
95                                mouse::Cursor::Available(cursor_position),
96                                renderer,
97                            ) != mouse::Interaction::None
98                        })
99                    })
100                    .unwrap_or_default();
101
102                renderer.with_layer(layout.bounds(), |renderer| {
103                    overlay.draw(
104                        renderer,
105                        theme,
106                        style,
107                        layout,
108                        if is_over {
109                            mouse::Cursor::Unavailable
110                        } else {
111                            cursor
112                        },
113                    );
114                });
115
116                if let Some((mut nested, nested_layout)) =
117                    overlay.overlay(layout, renderer).zip(nested_layout)
118                {
119                    recurse(
120                        &mut nested,
121                        nested_layout,
122                        renderer,
123                        theme,
124                        style,
125                        cursor,
126                    );
127                }
128            }
129        }
130
131        recurse(&mut self.overlay, layout, renderer, theme, style, cursor);
132    }
133
134    /// Applies a [`widget::Operation`] to the [`Nested`] overlay.
135    pub fn operate(
136        &mut self,
137        layout: Layout<'_>,
138        renderer: &Renderer,
139        operation: &mut dyn widget::Operation,
140    ) {
141        fn recurse<Message, Theme, Renderer>(
142            element: &mut overlay::Element<'_, Message, Theme, Renderer>,
143            layout: Layout<'_>,
144            renderer: &Renderer,
145            operation: &mut dyn widget::Operation,
146        ) where
147            Renderer: renderer::Renderer,
148        {
149            let mut layouts = layout.children();
150
151            if let Some(layout) = layouts.next() {
152                let overlay = element.as_overlay_mut();
153
154                overlay.operate(layout, renderer, operation);
155
156                if let Some((mut nested, nested_layout)) =
157                    overlay.overlay(layout, renderer).zip(layouts.next())
158                {
159                    recurse(&mut nested, nested_layout, renderer, operation);
160                }
161            }
162        }
163
164        recurse(&mut self.overlay, layout, renderer, operation);
165    }
166
167    /// Processes a runtime [`Event`].
168    pub fn update(
169        &mut self,
170        event: &Event,
171        layout: Layout<'_>,
172        cursor: mouse::Cursor,
173        renderer: &Renderer,
174        clipboard: &mut dyn Clipboard,
175        shell: &mut Shell<'_, Message>,
176    ) {
177        fn recurse<Message, Theme, Renderer>(
178            element: &mut overlay::Element<'_, Message, Theme, Renderer>,
179            layout: Layout<'_>,
180            event: &Event,
181            cursor: mouse::Cursor,
182            renderer: &Renderer,
183            clipboard: &mut dyn Clipboard,
184            shell: &mut Shell<'_, Message>,
185        ) -> bool
186        where
187            Renderer: renderer::Renderer,
188        {
189            let mut layouts = layout.children();
190
191            if let Some(layout) = layouts.next() {
192                let overlay = element.as_overlay_mut();
193
194                let nested_is_over = if let Some((mut nested, nested_layout)) =
195                    overlay.overlay(layout, renderer).zip(layouts.next())
196                {
197                    recurse(
198                        &mut nested,
199                        nested_layout,
200                        event,
201                        cursor,
202                        renderer,
203                        clipboard,
204                        shell,
205                    )
206                } else {
207                    false
208                };
209
210                if shell.event_status() == event::Status::Ignored {
211                    let is_over = nested_is_over
212                        || cursor
213                            .position()
214                            .map(|cursor_position| {
215                                overlay.mouse_interaction(
216                                    layout,
217                                    mouse::Cursor::Available(cursor_position),
218                                    renderer,
219                                ) != mouse::Interaction::None
220                            })
221                            .unwrap_or_default();
222
223                    overlay.update(
224                        event,
225                        layout,
226                        if nested_is_over {
227                            mouse::Cursor::Unavailable
228                        } else {
229                            cursor
230                        },
231                        renderer,
232                        clipboard,
233                        shell,
234                    );
235
236                    is_over
237                } else {
238                    nested_is_over
239                }
240            } else {
241                false
242            }
243        }
244
245        let _ = recurse(
246            &mut self.overlay,
247            layout,
248            event,
249            cursor,
250            renderer,
251            clipboard,
252            shell,
253        );
254    }
255
256    /// Returns the current [`mouse::Interaction`] of the [`Nested`] overlay.
257    pub fn mouse_interaction(
258        &mut self,
259        layout: Layout<'_>,
260        cursor: mouse::Cursor,
261        renderer: &Renderer,
262    ) -> mouse::Interaction {
263        fn recurse<Message, Theme, Renderer>(
264            element: &mut overlay::Element<'_, Message, Theme, Renderer>,
265            layout: Layout<'_>,
266            cursor: mouse::Cursor,
267            renderer: &Renderer,
268        ) -> Option<mouse::Interaction>
269        where
270            Renderer: renderer::Renderer,
271        {
272            let mut layouts = layout.children();
273
274            let layout = layouts.next()?;
275            let overlay = element.as_overlay_mut();
276
277            Some(
278                overlay
279                    .overlay(layout, renderer)
280                    .zip(layouts.next())
281                    .and_then(|(mut overlay, layout)| {
282                        recurse(&mut overlay, layout, cursor, renderer)
283                    })
284                    .unwrap_or_else(|| {
285                        overlay.mouse_interaction(layout, cursor, renderer)
286                    }),
287            )
288        }
289
290        recurse(&mut self.overlay, layout, cursor, renderer).unwrap_or_default()
291    }
292}