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    pub fn from_vec(children: Vec<Element<'a, Message, Theme, Renderer>>) -> Self {
53        Self {
54            width: Length::Fit,
55            height: Length::Fit,
56            children,
57            clip: false,
58            base_layer: 0,
59        }
60    }
61
62    /// Sets the width of the [`Stack`].
63    pub fn width(mut self, width: impl Into<Length>) -> Self {
64        self.width = width.into();
65        self
66    }
67
68    /// Sets the height of the [`Stack`].
69    pub fn height(mut self, height: impl Into<Length>) -> Self {
70        self.height = height.into();
71        self
72    }
73
74    /// Adds an element on top of the [`Stack`].
75    pub fn push(mut self, child: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {
76        let child = child.into();
77
78        if !child.as_widget().is_void() {
79            self.children.push(child);
80        }
81
82        self
83    }
84
85    /// Adds an element under the [`Stack`].
86    pub fn push_under(mut self, child: impl Into<Element<'a, Message, Theme, Renderer>>) -> Self {
87        self.children.insert(0, child.into());
88        self.base_layer += 1;
89        self
90    }
91
92    /// Extends the [`Stack`] with the given children.
93    pub fn extend(
94        self,
95        children: impl IntoIterator<Item = Element<'a, Message, Theme, Renderer>>,
96    ) -> Self {
97        children.into_iter().fold(self, Self::push)
98    }
99
100    /// Sets whether the [`Stack`] should clip overflowing content.
101    ///
102    /// It has a slight performance overhead during presentation.
103    ///
104    /// By default, it is set to `false`.
105    pub fn clip(mut self, clip: bool) -> Self {
106        self.clip = clip;
107        self
108    }
109}
110
111impl<Message, Renderer> Default for Stack<'_, Message, Renderer>
112where
113    Renderer: crate::core::Renderer,
114{
115    fn default() -> Self {
116        Self::new()
117    }
118}
119
120impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
121    for Stack<'a, Message, Theme, Renderer>
122where
123    Renderer: crate::core::Renderer,
124{
125    fn diff(&mut self, tree: &mut Tree) {
126        tree.diff_children(&mut self.children);
127
128        if let Some(base) = self.children.get(self.base_layer) {
129            let size = base.as_widget().size();
130
131            self.width = self.width.cross(size.width);
132            self.height = self.height.cross(size.height);
133        }
134    }
135
136    fn size(&self) -> Size<Length> {
137        Size {
138            width: self.width,
139            height: self.height,
140        }
141    }
142
143    fn layout(
144        &mut self,
145        tree: &mut Tree,
146        renderer: &Renderer,
147        limits: &layout::Limits,
148    ) -> layout::Node {
149        let limits = limits.width(self.width).height(self.height);
150
151        if self.children.len() <= self.base_layer {
152            return layout::Node::new(limits.resolve(self.width, self.height, Size::ZERO));
153        }
154
155        let base = self.children[self.base_layer].as_widget_mut().layout(
156            &mut tree.children[self.base_layer],
157            renderer,
158            &limits,
159        );
160
161        let size = limits.resolve(self.width, self.height, base.size());
162        let limits = layout::Limits::new(Size::ZERO, size);
163
164        let (under, above) = self.children.split_at_mut(self.base_layer);
165        let (tree_under, tree_above) = tree.children.split_at_mut(self.base_layer);
166
167        let nodes = under
168            .iter_mut()
169            .zip(tree_under)
170            .map(|(layer, tree)| layer.as_widget_mut().layout(tree, renderer, &limits))
171            .chain(std::iter::once(base))
172            .chain(
173                above[1..]
174                    .iter_mut()
175                    .zip(&mut tree_above[1..])
176                    .map(|(layer, tree)| layer.as_widget_mut().layout(tree, renderer, &limits)),
177            )
178            .collect();
179
180        layout::Node::with_children(size, nodes)
181    }
182
183    fn operate(
184        &mut self,
185        tree: &mut Tree,
186        layout: Layout<'_>,
187        renderer: &Renderer,
188        operation: &mut dyn Operation,
189    ) {
190        operation.container(None, layout.bounds());
191        operation.traverse(&mut |operation| {
192            self.children
193                .iter_mut()
194                .zip(&mut tree.children)
195                .zip(layout.children())
196                .for_each(|((child, state), layout)| {
197                    child
198                        .as_widget_mut()
199                        .operate(state, layout, renderer, operation);
200                });
201        });
202    }
203
204    fn update(
205        &mut self,
206        tree: &mut Tree,
207        event: &Event,
208        layout: Layout<'_>,
209        mut cursor: mouse::Cursor,
210        renderer: &Renderer,
211        shell: &mut Shell<'_, Message>,
212        viewport: &Rectangle,
213    ) {
214        if self.children.is_empty() {
215            return;
216        }
217
218        let is_over = cursor.is_over(layout.bounds());
219        let end = self.children.len() - 1;
220
221        for (i, ((child, tree), layout)) in self
222            .children
223            .iter_mut()
224            .rev()
225            .zip(tree.children.iter_mut().rev())
226            .zip(layout.children().rev())
227            .enumerate()
228        {
229            child
230                .as_widget_mut()
231                .update(tree, event, layout, cursor, renderer, shell, viewport);
232
233            if shell.is_event_captured() {
234                return;
235            }
236
237            if i < end && is_over && !cursor.is_levitating() {
238                let interaction = child
239                    .as_widget()
240                    .mouse_interaction(tree, layout, cursor, viewport, renderer);
241
242                if interaction != mouse::Interaction::None {
243                    cursor = cursor.levitate();
244                }
245            }
246        }
247    }
248
249    fn mouse_interaction(
250        &self,
251        tree: &Tree,
252        layout: Layout<'_>,
253        cursor: mouse::Cursor,
254        viewport: &Rectangle,
255        renderer: &Renderer,
256    ) -> mouse::Interaction {
257        self.children
258            .iter()
259            .rev()
260            .zip(tree.children.iter().rev())
261            .zip(layout.children().rev())
262            .map(|((child, tree), layout)| {
263                child
264                    .as_widget()
265                    .mouse_interaction(tree, layout, cursor, viewport, renderer)
266            })
267            .find(|&interaction| interaction != mouse::Interaction::None)
268            .unwrap_or_default()
269    }
270
271    fn draw(
272        &self,
273        tree: &Tree,
274        renderer: &mut Renderer,
275        theme: &Theme,
276        style: &renderer::Style,
277        layout: Layout<'_>,
278        cursor: mouse::Cursor,
279        viewport: &Rectangle,
280    ) {
281        if let Some(clipped_viewport) = layout.bounds().intersection(viewport) {
282            let viewport = if self.clip {
283                &clipped_viewport
284            } else {
285                viewport
286            };
287
288            let layers_under = if cursor.is_over(layout.bounds()) {
289                self.children
290                    .iter()
291                    .rev()
292                    .zip(tree.children.iter().rev())
293                    .zip(layout.children().rev())
294                    .position(|((layer, tree), layout)| {
295                        let interaction = layer
296                            .as_widget()
297                            .mouse_interaction(tree, layout, cursor, viewport, renderer);
298
299                        interaction != mouse::Interaction::None
300                    })
301                    .map(|i| self.children.len() - i - 1)
302                    .unwrap_or_default()
303            } else {
304                0
305            };
306
307            let mut layers = self
308                .children
309                .iter()
310                .zip(&tree.children)
311                .zip(layout.children())
312                .enumerate();
313
314            let layers = layers.by_ref();
315
316            let mut draw_layer =
317                |i, layer: &Element<'a, Message, Theme, Renderer>, tree, layout, cursor| {
318                    if i > 0 {
319                        renderer.with_layer(*viewport, |renderer| {
320                            layer
321                                .as_widget()
322                                .draw(tree, renderer, theme, style, layout, cursor, viewport);
323                        });
324                    } else {
325                        layer
326                            .as_widget()
327                            .draw(tree, renderer, theme, style, layout, cursor, viewport);
328                    }
329                };
330
331            for (i, ((layer, tree), layout)) in layers.take(layers_under) {
332                draw_layer(i, layer, tree, layout, mouse::Cursor::Unavailable);
333            }
334
335            for (i, ((layer, tree), layout)) in layers {
336                draw_layer(i, layer, tree, layout, cursor);
337            }
338        }
339    }
340
341    fn overlay<'b>(
342        &'b mut self,
343        tree: &'b mut Tree,
344        layout: Layout<'b>,
345        renderer: &Renderer,
346        viewport: &Rectangle,
347        translation: Vector,
348    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
349        overlay::from_children(
350            &mut self.children,
351            tree,
352            layout,
353            renderer,
354            viewport,
355            translation,
356        )
357    }
358}
359
360impl<'a, Message, Theme, Renderer> From<Stack<'a, Message, Theme, Renderer>>
361    for Element<'a, Message, Theme, Renderer>
362where
363    Message: 'a,
364    Theme: 'a,
365    Renderer: crate::core::Renderer + 'a,
366{
367    fn from(stack: Stack<'a, Message, Theme, Renderer>) -> Self {
368        Self::new(stack)
369    }
370}