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 on_event(
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    ) -> event::Status {
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        ) -> (event::Status, 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_status, nested_is_over) =
186                    if let Some((mut nested, nested_layout)) =
187                        element.overlay(layout, renderer).zip(layouts.next())
188                    {
189                        recurse(
190                            &mut nested,
191                            nested_layout,
192                            event.clone(),
193                            cursor,
194                            renderer,
195                            clipboard,
196                            shell,
197                        )
198                    } else {
199                        (event::Status::Ignored, false)
200                    };
201
202                if matches!(nested_status, event::Status::Ignored) {
203                    let is_over = nested_is_over
204                        || cursor
205                            .position()
206                            .map(|cursor_position| {
207                                element.is_over(
208                                    layout,
209                                    renderer,
210                                    cursor_position,
211                                )
212                            })
213                            .unwrap_or_default();
214
215                    (
216                        element.on_event(
217                            event,
218                            layout,
219                            if nested_is_over {
220                                mouse::Cursor::Unavailable
221                            } else {
222                                cursor
223                            },
224                            renderer,
225                            clipboard,
226                            shell,
227                        ),
228                        is_over,
229                    )
230                } else {
231                    (nested_status, nested_is_over)
232                }
233            } else {
234                (event::Status::Ignored, false)
235            }
236        }
237
238        let (status, _) = recurse(
239            &mut self.overlay,
240            layout,
241            event,
242            cursor,
243            renderer,
244            clipboard,
245            shell,
246        );
247
248        status
249    }
250
251    /// Returns the current [`mouse::Interaction`] of the [`Nested`] overlay.
252    pub fn mouse_interaction(
253        &mut self,
254        layout: Layout<'_>,
255        cursor: mouse::Cursor,
256        viewport: &Rectangle,
257        renderer: &Renderer,
258    ) -> mouse::Interaction {
259        fn recurse<Message, Theme, Renderer>(
260            element: &mut overlay::Element<'_, Message, Theme, Renderer>,
261            layout: Layout<'_>,
262            cursor: mouse::Cursor,
263            viewport: &Rectangle,
264            renderer: &Renderer,
265        ) -> Option<mouse::Interaction>
266        where
267            Renderer: renderer::Renderer,
268        {
269            let mut layouts = layout.children();
270
271            let layout = layouts.next()?;
272            let cursor_position = cursor.position()?;
273
274            if !element.is_over(layout, renderer, cursor_position) {
275                return None;
276            }
277
278            Some(
279                element
280                    .overlay(layout, renderer)
281                    .zip(layouts.next())
282                    .and_then(|(mut overlay, layout)| {
283                        recurse(
284                            &mut overlay,
285                            layout,
286                            cursor,
287                            viewport,
288                            renderer,
289                        )
290                    })
291                    .unwrap_or_else(|| {
292                        element.mouse_interaction(
293                            layout, cursor, viewport, renderer,
294                        )
295                    }),
296            )
297        }
298
299        recurse(&mut self.overlay, layout, cursor, viewport, renderer)
300            .unwrap_or_default()
301    }
302
303    /// Returns true if the cursor is over the [`Nested`] overlay.
304    pub fn is_over(
305        &mut self,
306        layout: Layout<'_>,
307        renderer: &Renderer,
308        cursor_position: Point,
309    ) -> bool {
310        fn recurse<Message, Theme, Renderer>(
311            element: &mut overlay::Element<'_, Message, Theme, Renderer>,
312            layout: Layout<'_>,
313            renderer: &Renderer,
314            cursor_position: Point,
315        ) -> bool
316        where
317            Renderer: renderer::Renderer,
318        {
319            let mut layouts = layout.children();
320
321            if let Some(layout) = layouts.next() {
322                if element.is_over(layout, renderer, cursor_position) {
323                    return true;
324                }
325
326                if let Some((mut nested, nested_layout)) =
327                    element.overlay(layout, renderer).zip(layouts.next())
328                {
329                    recurse(
330                        &mut nested,
331                        nested_layout,
332                        renderer,
333                        cursor_position,
334                    )
335                } else {
336                    false
337                }
338            } else {
339                false
340            }
341        }
342
343        recurse(&mut self.overlay, layout, renderer, cursor_position)
344    }
345}