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