anathema_default_widgets/stacks/
vstack.rs

1use std::ops::ControlFlow;
2
3use anathema_geometry::Size;
4use anathema_value_resolver::AttributeStorage;
5use anathema_widgets::error::Result;
6use anathema_widgets::layout::{Constraints, LayoutCtx, PositionCtx};
7use anathema_widgets::paint::{PaintCtx, SizePos};
8use anathema_widgets::{LayoutForEach, PaintChildren, PositionChildren, Widget, WidgetId};
9
10use super::Stack;
11use crate::layout::Axis;
12
13pub struct VStack(Stack);
14
15impl Default for VStack {
16    fn default() -> Self {
17        VStack(Stack(Axis::Vertical))
18    }
19}
20
21impl Widget for VStack {
22    fn layout<'bp>(
23        &mut self,
24        children: LayoutForEach<'_, 'bp>,
25        constraints: Constraints,
26        id: WidgetId,
27        ctx: &mut LayoutCtx<'_, 'bp>,
28    ) -> Result<Size> {
29        self.0.layout(children, constraints, id, ctx)
30    }
31
32    fn position<'bp>(
33        &mut self,
34        children: PositionChildren<'_, 'bp>,
35        attributes: WidgetId,
36        attribute_storage: &AttributeStorage<'bp>,
37        ctx: PositionCtx,
38    ) {
39        self.0.position(children, attributes, attribute_storage, ctx)
40    }
41
42    fn paint<'bp>(
43        &mut self,
44        mut children: PaintChildren<'_, 'bp>,
45        _id: WidgetId,
46        attribute_storage: &AttributeStorage<'bp>,
47        mut ctx: PaintCtx<'_, SizePos>,
48    ) {
49        _ = children.each(|child, children| {
50            let ctx = ctx.to_unsized();
51            child.paint(children, ctx, attribute_storage);
52            ControlFlow::Continue(())
53        });
54    }
55}
56
57#[cfg(test)]
58mod test {
59
60    use crate::testing::TestRunner;
61
62    #[test]
63    fn vstack() {
64        let tpl = "
65            vstack
66                border
67                    text state.value
68                for i in [2]
69                    border
70                        text i
71        ";
72
73        let expected_first = "
74            ╔═══╗
75            ║┌─┐║
76            ║│0│║
77            ║└─┘║
78            ║┌─┐║
79            ║│2│║
80            ║└─┘║
81            ╚═══╝
82        ";
83
84        let expected_second = "
85            ╔═══╗
86            ║┌─┐║
87            ║│7│║
88            ║└─┘║
89            ║┌─┐║
90            ║│2│║
91            ║└─┘║
92            ╚═══╝
93        ";
94
95        TestRunner::new(tpl, (3, 6))
96            .instance()
97            .render_assert(expected_first)
98            .with_state(|state| *state.value.to_mut() = 7)
99            .render_assert(expected_second);
100    }
101
102    #[test]
103    fn fixed_height() {
104        let tpl = "
105            vstack [height: 2]
106                for i in [0, 1]
107                    border
108                        text i
109        ";
110
111        let expected = "
112            ╔══╗
113            ║┌┐║
114            ║└┘║
115            ╚══╝
116        ";
117
118        TestRunner::new(tpl, (2, 2)).instance().render_assert(expected);
119    }
120
121    #[test]
122    fn fixed_width() {
123        let tpl = "
124            vstack [width: 7, height: 3]
125                border
126                    expand
127                        text 'a'
128        ";
129
130        let expected = "
131            ╔═══════╗
132            ║┌─────┐║
133            ║│a    │║
134            ║└─────┘║
135            ╚═══════╝
136        ";
137
138        TestRunner::new(tpl, (7, 3)).instance().render_assert(expected);
139    }
140
141    #[test]
142    fn bottom_up_vstack() {
143        let tpl = "
144            vstack [direction: 'back']
145                text 'b'
146                border
147                    text 'a'
148        ";
149
150        let expected = "
151            ╔══════╗
152            ║      ║
153            ║┌─┐   ║
154            ║│a│   ║
155            ║└─┘   ║
156            ║b     ║
157            ╚══════╝
158        ";
159
160        TestRunner::new(tpl, (6, 5)).instance().render_assert(expected);
161    }
162
163    #[test]
164    fn vstack_overflow() {
165        let tpl = "
166            vstack
167                text 'a'
168                text 'b'
169                text 'c'
170                text 'd'
171        ";
172
173        let expected = "
174            ╔══════╗
175            ║a     ║
176            ║b     ║
177            ╚══════╝
178        ";
179
180        let mut runner = TestRunner::new(tpl, (6, 2));
181        let mut runner = runner.instance();
182        runner.render_assert(expected);
183    }
184}