anathema_default_widgets/
expand.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 crate::layout::{Axis, single_layout};
11
12#[derive(Debug, Default)]
13pub struct Expand;
14
15impl Widget for Expand {
16    fn layout<'bp>(
17        &mut self,
18        children: LayoutForEach<'_, 'bp>,
19        constraints: Constraints,
20        id: WidgetId,
21        ctx: &mut LayoutCtx<'_, 'bp>,
22    ) -> Result<Size> {
23        let mut size = single_layout(children, constraints, ctx)?;
24
25        let attributes = ctx.attribute_storage.get(id);
26        match attributes.get_as::<Axis>("axis") {
27            Some(Axis::Horizontal) => size.width = constraints.max_width(),
28            Some(Axis::Vertical) => size.height = constraints.max_height(),
29            None => {
30                size.width = constraints.max_width();
31                size.height = constraints.max_height();
32            }
33        }
34
35        Ok(size)
36    }
37
38    fn position<'bp>(
39        &mut self,
40        mut children: PositionChildren<'_, 'bp>,
41        _attributes: WidgetId,
42        attribute_storage: &AttributeStorage<'bp>,
43        ctx: PositionCtx,
44    ) {
45        _ = children.each(|node, children| {
46            node.position(children, ctx.pos, attribute_storage, ctx.viewport);
47            ControlFlow::Break(())
48        });
49    }
50
51    fn paint<'bp>(
52        &mut self,
53        mut children: PaintChildren<'_, 'bp>,
54        _: WidgetId,
55        attribute_storage: &AttributeStorage<'bp>,
56        mut ctx: PaintCtx<'_, SizePos>,
57    ) {
58        _ = children.each(|child, children| {
59            let ctx = ctx.to_unsized();
60            child.paint(children, ctx, attribute_storage);
61            ControlFlow::Break(())
62        });
63    }
64}
65
66#[cfg(test)]
67mod test {
68    use crate::testing::TestRunner;
69
70    #[test]
71    fn hstack_expand_nospace() {
72        let tpl = "
73        border
74            container [width:12]
75                hstack
76                    expand
77                    text 'this is text'
78        ";
79
80        let expected = "
81            ╔══════════════╗
82            ║┌────────────┐║
83            ║│this is text│║
84            ║│            │║
85            ║└────────────┘║
86            ╚══════════════╝
87        ";
88
89        let mut runner = TestRunner::new(tpl, (14, 4));
90        let mut runner = runner.instance();
91        runner.render_assert(expected);
92    }
93
94    #[test]
95    fn vstack_expand_nospace() {
96        let tpl = "
97        border
98            container [height:1]
99                vstack
100                    expand
101                    text 'this is text'
102        ";
103
104        let expected = "
105            ╔═════════════════╗
106            ║┌───────────────┐║
107            ║│this is text   │║
108            ║└───────────────┘║
109            ║                 ║
110            ╚═════════════════╝
111        ";
112
113        let mut runner = TestRunner::new(tpl, (17, 4));
114        let mut runner = runner.instance();
115        runner.render_assert(expected);
116    }
117}