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/// 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        shell: &mut Shell<'_, Message>,
158    ) {
159        fn recurse<Message, Theme, Renderer>(
160            element: &mut overlay::Element<'_, Message, Theme, Renderer>,
161            layout: Layout<'_>,
162            event: &Event,
163            cursor: mouse::Cursor,
164            renderer: &Renderer,
165            shell: &mut Shell<'_, Message>,
166        ) -> bool
167        where
168            Renderer: renderer::Renderer,
169        {
170            let mut layouts = layout.children();
171
172            if let Some(layout) = layouts.next() {
173                let overlay = element.as_overlay_mut();
174
175                let nested_is_over = if let Some((mut nested, nested_layout)) =
176                    overlay.overlay(layout, renderer).zip(layouts.next())
177                {
178                    recurse(&mut nested, nested_layout, event, cursor, renderer, shell)
179                } else {
180                    false
181                };
182
183                if shell.event_status() == event::Status::Ignored {
184                    let is_over = nested_is_over
185                        || cursor
186                            .position()
187                            .map(|cursor_position| {
188                                overlay.mouse_interaction(
189                                    layout,
190                                    mouse::Cursor::Available(cursor_position),
191                                    renderer,
192                                ) != mouse::Interaction::None
193                            })
194                            .unwrap_or_default();
195
196                    overlay.update(
197                        event,
198                        layout,
199                        if nested_is_over {
200                            mouse::Cursor::Unavailable
201                        } else {
202                            cursor
203                        },
204                        renderer,
205                        shell,
206                    );
207
208                    is_over
209                } else {
210                    nested_is_over
211                }
212            } else {
213                false
214            }
215        }
216
217        let _ = recurse(&mut self.overlay, layout, event, cursor, renderer, shell);
218    }
219
220    /// Returns the current [`mouse::Interaction`] of the [`Nested`] overlay.
221    pub fn mouse_interaction(
222        &mut self,
223        layout: Layout<'_>,
224        cursor: mouse::Cursor,
225        renderer: &Renderer,
226    ) -> mouse::Interaction {
227        fn recurse<Message, Theme, Renderer>(
228            element: &mut overlay::Element<'_, Message, Theme, Renderer>,
229            layout: Layout<'_>,
230            cursor: mouse::Cursor,
231            renderer: &Renderer,
232        ) -> Option<mouse::Interaction>
233        where
234            Renderer: renderer::Renderer,
235        {
236            let mut layouts = layout.children();
237
238            let layout = layouts.next()?;
239            let overlay = element.as_overlay_mut();
240
241            Some(
242                overlay
243                    .overlay(layout, renderer)
244                    .zip(layouts.next())
245                    .and_then(|(mut overlay, layout)| {
246                        recurse(&mut overlay, layout, cursor, renderer)
247                    })
248                    .unwrap_or_else(|| overlay.mouse_interaction(layout, cursor, renderer)),
249            )
250        }
251
252        recurse(&mut self.overlay, layout, cursor, renderer).unwrap_or_default()
253    }
254}