Skip to main content

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