geng_ui/layout_widgets/
column.rs

1use super::*;
2
3#[derive(Deref, DerefMut)]
4pub struct Column<'a> {
5    #[deref]
6    #[deref_mut]
7    children: Vec<Box<dyn Widget + 'a>>,
8}
9
10pub fn column<'a>(widgets: Vec<Box<dyn Widget + 'a>>) -> Column<'a> {
11    Column { children: widgets }
12}
13
14#[macro_export]
15macro_rules! column {
16    ($($x:expr),* $(,)?) => {
17        $crate::column(vec![$(Box::new($x)),*])
18    };
19}
20
21impl<'a> Widget for Column<'a> {
22    fn calc_constraints(&mut self, children: &ConstraintsContext) -> Constraints {
23        Constraints {
24            min_size: vec2(
25                self.children
26                    .iter()
27                    .map(|child| children.get_constraints(child.deref()).min_size.x)
28                    .max_by(|a, b| a.partial_cmp(b).unwrap())
29                    .unwrap_or(0.0),
30                self.children
31                    .iter()
32                    .map(|child| children.get_constraints(child.deref()).min_size.y)
33                    .sum(),
34            ),
35            flex: vec2(
36                self.children
37                    .iter()
38                    .map(|child| children.get_constraints(child.deref()).flex.x)
39                    .max_by(|a, b| a.partial_cmp(b).unwrap())
40                    .unwrap_or(0.0),
41                self.children
42                    .iter()
43                    .map(|child| children.get_constraints(child.deref()).flex.y)
44                    .sum(),
45            ),
46        }
47    }
48    fn layout_children(&mut self, cx: &mut LayoutContext) {
49        let total_flex = self
50            .children
51            .iter()
52            .map(|child| cx.get_constraints(child.deref()).flex.y)
53            .sum::<f64>();
54        let size_per_flex = if total_flex == 0.0 {
55            0.0
56        } else {
57            (cx.position.height()
58                - self
59                    .children
60                    .iter()
61                    .map(|child| cx.get_constraints(child.deref()).min_size.y)
62                    .sum::<f64>())
63                / total_flex
64        };
65        let mut pos = cx.position.max.y;
66        for child in &self.children {
67            let child = child.deref();
68            let height = cx.get_constraints(child).min_size.y
69                + cx.get_constraints(child).flex.y * size_per_flex;
70            pos -= height;
71            cx.set_position(
72                child,
73                Aabb2::point(vec2(cx.position.min.x, pos))
74                    .extend_positive(vec2(cx.position.width(), height)),
75            );
76        }
77    }
78    fn walk_children_mut<'b>(&mut self, f: &mut dyn FnMut(&mut dyn Widget)) {
79        for child in &mut self.children {
80            f(child.deref_mut());
81        }
82    }
83}
84
85mod ext {
86    use super::*;
87
88    macro_rules! impl_for_tuple {
89        ($($a:ident),*) => {
90            impl<'a, $($a: Widget + 'a),*> TupleExt<'a> for ($($a,)*) {
91                fn column(self) -> Column<'a> {
92                    let ($($a,)*) = self;
93                    super::column![$($a),*]
94                }
95            }
96        };
97    }
98    call_for_tuples!(impl_for_tuple);
99
100    pub trait TupleExt<'a> {
101        fn column(self) -> Column<'a>;
102    }
103}
104
105pub use ext::TupleExt as _;