Skip to main content

iced_core/overlay/
group.rs

1use crate::event;
2use crate::mouse;
3use crate::overlay;
4use crate::renderer;
5use crate::widget;
6use crate::{Event, Shell};
7
8/// A container of nested overlays.
9pub struct Group<'a, Message, Theme, Renderer> {
10    children: Vec<overlay::Element<'a, Message, Theme, Renderer>>,
11}
12
13fn sort_overlays<'a, Message, Theme, Renderer>(
14    children: &mut [overlay::Element<'a, Message, Theme, Renderer>],
15) where
16    Renderer: renderer::Renderer,
17{
18    use std::cmp;
19
20    children.sort_by(|a, b| {
21        a.as_overlay()
22            .index()
23            .partial_cmp(&b.as_overlay().index())
24            .unwrap_or(cmp::Ordering::Equal)
25    });
26}
27
28impl<'a, Message, Theme, Renderer> Group<'a, Message, Theme, Renderer>
29where
30    Renderer: renderer::Renderer,
31{
32    /// Creates a [`Group`] container for the given overlays.
33    ///
34    /// The overlays are sorted by their
35    /// [`index`](crate::Overlay::index).
36    pub fn new(mut children: Vec<overlay::Element<'a, Message, Theme, Renderer>>) -> Self {
37        sort_overlays(&mut children);
38
39        Self { children }
40    }
41
42    /// Draws the [`Group`] overlay using the associated `Renderer`.
43    pub fn draw(
44        &mut self,
45        renderer: &mut Renderer,
46        theme: &Theme,
47        style: &renderer::Style,
48        cursor: mouse::Cursor,
49    ) {
50        fn recurse<Message, Theme, Renderer>(
51            children: &mut [overlay::Element<'_, Message, Theme, Renderer>],
52            renderer: &mut Renderer,
53            theme: &Theme,
54            style: &renderer::Style,
55            cursor: mouse::Cursor,
56        ) where
57            Renderer: renderer::Renderer,
58        {
59            for element in children {
60                // TODO: Get rid of cursor argument in `draw`
61                let is_over = cursor.position().is_some_and(|cursor_position| {
62                    let nested = element.as_overlay_mut().overlay(renderer);
63
64                    !nested.is_empty()
65                        && Group::new(nested)
66                            .mouse_interaction(mouse::Cursor::Available(cursor_position), renderer)
67                            != mouse::Interaction::None
68                });
69
70                element.as_overlay().draw(
71                    renderer,
72                    theme,
73                    style,
74                    if is_over {
75                        mouse::Cursor::Unavailable
76                    } else {
77                        cursor
78                    },
79                );
80
81                let mut nested = element.as_overlay_mut().overlay(renderer);
82
83                if !nested.is_empty() {
84                    sort_overlays(&mut nested);
85
86                    recurse(&mut nested, renderer, theme, style, cursor);
87                }
88            }
89        }
90
91        recurse(&mut self.children, renderer, theme, style, cursor);
92    }
93
94    /// Applies a [`widget::Operation`] to the [`Group`] overlay.
95    pub fn operate(&mut self, renderer: &Renderer, operation: &mut dyn widget::Operation) {
96        fn recurse<Message, Theme, Renderer>(
97            children: &mut [overlay::Element<'_, Message, Theme, Renderer>],
98            renderer: &Renderer,
99            operation: &mut dyn widget::Operation,
100        ) where
101            Renderer: renderer::Renderer,
102        {
103            for element in children {
104                let overlay = element.as_overlay_mut();
105
106                overlay.operate(renderer, operation);
107
108                let mut nested = overlay.overlay(renderer);
109
110                if !nested.is_empty() {
111                    sort_overlays(&mut nested);
112
113                    recurse(&mut nested, renderer, operation);
114                }
115            }
116        }
117
118        recurse(&mut self.children, renderer, operation);
119    }
120
121    /// Processes a runtime [`Event`].
122    pub fn update(
123        &mut self,
124        event: &Event,
125        cursor: mouse::Cursor,
126        renderer: &Renderer,
127        shell: &mut Shell<'_, Message>,
128    ) {
129        fn recurse<Message, Theme, Renderer>(
130            children: &mut [overlay::Element<'_, Message, Theme, Renderer>],
131            event: &Event,
132            cursor: mouse::Cursor,
133            renderer: &Renderer,
134            shell: &mut Shell<'_, Message>,
135        ) -> bool
136        where
137            Renderer: renderer::Renderer,
138        {
139            let mut is_over = false;
140
141            for element in children {
142                if shell.event_status() != event::Status::Ignored {
143                    return is_over;
144                }
145
146                let overlay = element.as_overlay_mut();
147
148                let nested = overlay.overlay(renderer);
149                let nested_is_over = (!nested.is_empty())
150                    .then_some(nested)
151                    .map(|mut nested| {
152                        sort_overlays(&mut nested);
153
154                        recurse(&mut nested, event, cursor, renderer, shell)
155                    })
156                    .unwrap_or_default();
157
158                if shell.event_status() != event::Status::Ignored {
159                    return nested_is_over || is_over;
160                }
161
162                let child_is_over = nested_is_over
163                    || cursor.position().is_some_and(|cursor_position| {
164                        overlay
165                            .mouse_interaction(mouse::Cursor::Available(cursor_position), renderer)
166                            != mouse::Interaction::None
167                    });
168
169                overlay.update(
170                    event,
171                    if nested_is_over {
172                        mouse::Cursor::Unavailable
173                    } else {
174                        cursor
175                    },
176                    renderer,
177                    shell,
178                );
179
180                is_over |= child_is_over;
181            }
182
183            is_over
184        }
185
186        let _ = recurse(&mut self.children, event, cursor, renderer, shell);
187    }
188
189    /// Returns the current [`mouse::Interaction`] of the [`Group`] overlay.
190    pub fn mouse_interaction(
191        &mut self,
192        cursor: mouse::Cursor,
193        renderer: &Renderer,
194    ) -> mouse::Interaction {
195        fn recurse<Message, Theme, Renderer>(
196            children: &mut [overlay::Element<'_, Message, Theme, Renderer>],
197            cursor: mouse::Cursor,
198            renderer: &Renderer,
199        ) -> mouse::Interaction
200        where
201            Renderer: renderer::Renderer,
202        {
203            children
204                .iter_mut()
205                .map(|element| {
206                    let overlay = element.as_overlay_mut();
207                    let interaction = overlay.mouse_interaction(cursor, renderer);
208
209                    let nested = overlay.overlay(renderer);
210                    let nested_interaction = (!nested.is_empty())
211                        .then_some(nested)
212                        .map(|mut nested| {
213                            sort_overlays(&mut nested);
214
215                            recurse(&mut nested, cursor, renderer)
216                        })
217                        .unwrap_or_default();
218
219                    nested_interaction.max(interaction)
220                })
221                .max()
222                .unwrap_or_default()
223        }
224
225        recurse(&mut self.children, cursor, renderer)
226    }
227}