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