Skip to main content

iced_widget/
stack.rs

1//! Display content on top of other content.
2use crate::core::layout;
3use crate::core::mouse;
4use crate::core::overlay;
5use crate::core::renderer;
6use crate::core::widget::{Operation, Tree};
7use crate::core::{Element, Event, Layout, Length, Rectangle, Shell, Size, Vector, Widget};
8
9/// A container that displays children on top of each other.
10///
11/// The first [`Element`] dictates the intrinsic [`Size`] of a [`Stack`] and
12/// will be displayed as the base layer. Every consecutive [`Element`] will be
13/// rendered on top; on its own layer.
14///
15/// You can use [`push_under`](Self::push_under) to push an [`Element`] under
16/// the current [`Stack`] without affecting its intrinsic [`Size`].
17///
18/// Keep in mind that too much layering will normally produce bad UX as well as
19/// introduce certain rendering overhead. Use this widget sparingly!
20pub struct Stack<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> {
21    width: Length,
22    height: Length,
23    children: Vec<Element<'a, Message, Theme, Renderer>>,
24    clip: bool,
25    base_layer: usize,
26}
27
28impl<'a, Message, Theme, Renderer> Stack<'a, Message, Theme, Renderer>
29where
30    Renderer: crate::core::Renderer,
31{
32    /// Creates an empty [`Stack`].
33    pub fn new() -> Self {
34        Self::from_vec(Vec::new())
35    }
36
37    /// Creates a [`Stack`] with the given capacity.
38    pub fn with_capacity(capacity: usize) -> Self {
39        Self::from_vec(Vec::with_capacity(capacity))
40    }
41
42    /// Creates a [`Stack`] with the given elements.
43    pub fn with_children(
44        children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,
45    ) -> Self {
46        let iterator = children.into_iter();
47
48        Self::with_capacity(iterator.size_hint().0).extend(iterator)
49    }
50
51    /// Creates a [`Stack`] from an already allocated [`Vec`].
52    ///
53    /// Keep in mind that the [`Stack`] will not inspect the [`Vec`], which means
54    /// it won't automatically adapt to the sizing strategy of its contents.
55    ///
56    /// If any of the children have a [`Length::Fill`] strategy, you will need to
57    /// call [`Stack::width`] or [`Stack::height`] accordingly.
58    pub fn from_vec(children: Vec<Element<'a, Message, Theme, Renderer>>) -> Self {
59        Self {
60            width: Length::Shrink,
61            height: Length::Shrink,
62            children,
63            clip: false,
64            base_layer: 0,
65        }
66    }
67
68    /// Sets the width of the [`Stack`].
69    pub fn width(mut self, width: impl Into<Length>) -> Self {
70        self.width = width.into();
71        self
72    }
73
74    /// Sets the height of the [`Stack`].
75    pub fn height(mut self, height: impl Into<Length>) -> Self {
76        self.height = height.into();
77        self
78    }
79
80    /// Adds an element on top of the [`Stack`].
81    pub fn push(mut self, child: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {
82        let child = child.into();
83        let child_size = child.as_widget().size_hint();
84
85        if !child_size.is_void() {
86            if self.children.is_empty() {
87                self.width = self.width.enclose(child_size.width);
88                self.height = self.height.enclose(child_size.height);
89            }
90
91            self.children.push(child);
92        }
93
94        self
95    }
96
97    /// Adds an element under the [`Stack`].
98    pub fn push_under(mut self, child: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {
99        self.children.insert(0, child.into());
100        self.base_layer += 1;
101        self
102    }
103
104    /// Extends the [`Stack`] with the given children.
105    pub fn extend(
106        self,
107        children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,
108    ) -> Self {
109        children.into_iter().fold(self, Self::push)
110    }
111
112    /// Sets whether the [`Stack`] should clip overflowing content.
113    ///
114    /// It has a slight performance overhead during presentation.
115    ///
116    /// By default, it is set to `false`.
117    pub fn clip(mut self, clip: bool) -> Self {
118        self.clip = clip;
119        self
120    }
121}
122
123impl<Message, Renderer> Default for Stack<'_, Message, Renderer>
124where
125    Renderer: crate::core::Renderer,
126{
127    fn default() -> Self {
128        Self::new()
129    }
130}
131
132impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
133    for Stack<'a, Message, Theme, Renderer>
134where
135    Renderer: crate::core::Renderer,
136{
137    fn children(&self) -> Vec<Tree> {
138        self.children.iter().map(Tree::new).collect()
139    }
140
141    fn diff(&self, tree: &mut Tree) {
142        tree.diff_children(&self.children);
143    }
144
145    fn size(&self) -> Size<Length> {
146        Size {
147            width: self.width,
148            height: self.height,
149        }
150    }
151
152    fn layout(
153        &mut self,
154        tree: &mut Tree,
155        renderer: &Renderer,
156        limits: &layout::Limits,
157    ) -> layout::Node {
158        let limits = limits.width(self.width).height(self.height);
159
160        if self.children.len() <= self.base_layer {
161            return layout::Node::new(limits.resolve(self.width, self.height, Size::ZERO));
162        }
163
164        let base = self.children[self.base_layer].as_widget_mut().layout(
165            &mut tree.children[self.base_layer],
166            renderer,
167            &limits,
168        );
169
170        let size = limits.resolve(self.width, self.height, base.size());
171        let limits = layout::Limits::new(Size::ZERO, size);
172
173        let (under, above) = self.children.split_at_mut(self.base_layer);
174        let (tree_under, tree_above) = tree.children.split_at_mut(self.base_layer);
175
176        let nodes = under
177            .iter_mut()
178            .zip(tree_under)
179            .map(|(layer, tree)| layer.as_widget_mut().layout(tree, renderer, &limits))
180            .chain(std::iter::once(base))
181            .chain(
182                above[1..]
183                    .iter_mut()
184                    .zip(&mut tree_above[1..])
185                    .map(|(layer, tree)| layer.as_widget_mut().layout(tree, renderer, &limits)),
186            )
187            .collect();
188
189        layout::Node::with_children(size, nodes)
190    }
191
192    fn operate(
193        &mut self,
194        tree: &mut Tree,
195        layout: Layout<'_>,
196        renderer: &Renderer,
197        operation: &mut dyn Operation,
198    ) {
199        operation.container(None, layout.bounds());
200        operation.traverse(&mut |operation| {
201            self.children
202                .iter_mut()
203                .zip(&mut tree.children)
204                .zip(layout.children())
205                .for_each(|((child, state), layout)| {
206                    child
207                        .as_widget_mut()
208                        .operate(state, layout, renderer, operation);
209                });
210        });
211    }
212
213    fn update(
214        &mut self,
215        tree: &mut Tree,
216        event: &Event,
217        layout: Layout<'_>,
218        mut cursor: mouse::Cursor,
219        renderer: &Renderer,
220        shell: &mut Shell<'_, Message>,
221        viewport: &Rectangle,
222    ) {
223        if self.children.is_empty() {
224            return;
225        }
226
227        let is_over = cursor.is_over(layout.bounds());
228        let end = self.children.len() - 1;
229
230        for (i, ((child, tree), layout)) in self
231            .children
232            .iter_mut()
233            .rev()
234            .zip(tree.children.iter_mut().rev())
235            .zip(layout.children().rev())
236            .enumerate()
237        {
238            child
239                .as_widget_mut()
240                .update(tree, event, layout, cursor, renderer, shell, viewport);
241
242            if shell.is_event_captured() {
243                return;
244            }
245
246            if i < end && is_over && !cursor.is_levitating() {
247                let interaction = child
248                    .as_widget()
249                    .mouse_interaction(tree, layout, cursor, viewport, renderer);
250
251                if interaction != mouse::Interaction::None {
252                    cursor = cursor.levitate();
253                }
254            }
255        }
256    }
257
258    fn mouse_interaction(
259        &self,
260        tree: &Tree,
261        layout: Layout<'_>,
262        cursor: mouse::Cursor,
263        viewport: &Rectangle,
264        renderer: &Renderer,
265    ) -> mouse::Interaction {
266        self.children
267            .iter()
268            .rev()
269            .zip(tree.children.iter().rev())
270            .zip(layout.children().rev())
271            .map(|((child, tree), layout)| {
272                child
273                    .as_widget()
274                    .mouse_interaction(tree, layout, cursor, viewport, renderer)
275            })
276            .find(|&interaction| interaction != mouse::Interaction::None)
277            .unwrap_or_default()
278    }
279
280    fn draw(
281        &self,
282        tree: &Tree,
283        renderer: &mut Renderer,
284        theme: &Theme,
285        style: &renderer::Style,
286        layout: Layout<'_>,
287        cursor: mouse::Cursor,
288        viewport: &Rectangle,
289    ) {
290        if let Some(clipped_viewport) = layout.bounds().intersection(viewport) {
291            let viewport = if self.clip {
292                &clipped_viewport
293            } else {
294                viewport
295            };
296
297            let layers_under = if cursor.is_over(layout.bounds()) {
298                self.children
299                    .iter()
300                    .rev()
301                    .zip(tree.children.iter().rev())
302                    .zip(layout.children().rev())
303                    .position(|((layer, tree), layout)| {
304                        let interaction = layer
305                            .as_widget()
306                            .mouse_interaction(tree, layout, cursor, viewport, renderer);
307
308                        interaction != mouse::Interaction::None
309                    })
310                    .map(|i| self.children.len() - i - 1)
311                    .unwrap_or_default()
312            } else {
313                0
314            };
315
316            let mut layers = self
317                .children
318                .iter()
319                .zip(&tree.children)
320                .zip(layout.children())
321                .enumerate();
322
323            let layers = layers.by_ref();
324
325            let mut draw_layer =
326                |i, layer: &Element<'a, Message, Theme, Renderer>, tree, layout, cursor| {
327                    if i > 0 {
328                        renderer.with_layer(*viewport, |renderer| {
329                            layer
330                                .as_widget()
331                                .draw(tree, renderer, theme, style, layout, cursor, viewport);
332                        });
333                    } else {
334                        layer
335                            .as_widget()
336                            .draw(tree, renderer, theme, style, layout, cursor, viewport);
337                    }
338                };
339
340            for (i, ((layer, tree), layout)) in layers.take(layers_under) {
341                draw_layer(i, layer, tree, layout, mouse::Cursor::Unavailable);
342            }
343
344            for (i, ((layer, tree), layout)) in layers {
345                draw_layer(i, layer, tree, layout, cursor);
346            }
347        }
348    }
349
350    fn overlay<'b>(
351        &'b mut self,
352        tree: &'b mut Tree,
353        layout: Layout<'b>,
354        renderer: &Renderer,
355        viewport: &Rectangle,
356        translation: Vector,
357    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
358        overlay::from_children(
359            &mut self.children,
360            tree,
361            layout,
362            renderer,
363            viewport,
364            translation,
365        )
366    }
367}
368
369impl<'a, Message, Theme, Renderer> From<Stack<'a, Message, Theme, Renderer>>
370    for Element<'a, Message, Theme, Renderer>
371where
372    Message: 'a,
373    Theme: 'a,
374    Renderer: crate::core::Renderer + 'a,
375{
376    fn from(stack: Stack<'a, Message, Theme, Renderer>) -> Self {
377        Self::new(stack)
378    }
379}