iced_core/overlay/
nested.rs

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