1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use super::*;

#[derive(Deref, DerefMut)]
pub struct Row<'a> {
    #[deref]
    #[deref_mut]
    children: Vec<Box<dyn Widget + 'a>>,
}

pub fn row<'a>(widgets: Vec<Box<dyn Widget + 'a>>) -> Row<'a> {
    Row { children: widgets }
}

#[macro_export]
macro_rules! row {
    ($($x:expr),* $(,)?) => {
        $crate::row(vec![$(Box::new($x)),*])
    };
}

impl<'a> Widget for Row<'a> {
    fn calc_constraints(&mut self, children: &ConstraintsContext) -> Constraints {
        Constraints {
            min_size: vec2(
                self.children
                    .iter()
                    .map(|child| children.get_constraints(child.deref()).min_size.x)
                    .sum(),
                self.children
                    .iter()
                    .map(|child| children.get_constraints(child.deref()).min_size.y)
                    .max_by(|a, b| a.partial_cmp(b).unwrap())
                    .unwrap_or(0.0),
            ),
            flex: vec2(
                self.children
                    .iter()
                    .map(|child| children.get_constraints(child.deref()).flex.x)
                    .sum(),
                self.children
                    .iter()
                    .map(|child| children.get_constraints(child.deref()).flex.y)
                    .max_by(|a, b| a.partial_cmp(b).unwrap())
                    .unwrap_or(0.0),
            ),
        }
    }
    fn layout_children(&mut self, cx: &mut LayoutContext) {
        let total_flex = self
            .children
            .iter()
            .map(|child| cx.get_constraints(child.deref()).flex.x)
            .sum::<f64>();
        let size_per_flex = if total_flex == 0.0 {
            0.0
        } else {
            (cx.position.width()
                - self
                    .children
                    .iter()
                    .map(|child| cx.get_constraints(child.deref()).min_size.x)
                    .sum::<f64>())
                / total_flex
        };
        let mut pos = cx.position.min.x;
        for child in &self.children {
            let child = child.deref();
            let width = cx.get_constraints(child).min_size.x
                + cx.get_constraints(child).flex.x * size_per_flex;
            cx.set_position(
                child,
                Aabb2::point(vec2(pos, cx.position.min.y))
                    .extend_positive(vec2(width, cx.position.height())),
            );
            pos += width;
        }
    }
    fn walk_children_mut<'b>(&mut self, f: &mut dyn FnMut(&mut dyn Widget)) {
        for child in &mut self.children {
            f(child.deref_mut());
        }
    }
}

mod ext {
    use super::*;

    macro_rules! impl_for_tuple {
        ($($a:ident),*) => {
            impl<'a, $($a: Widget + 'a),*> TupleExt<'a> for ($($a,)*) {
                fn row(self) -> Row<'a> {
                    let ($($a,)*) = self;
                    row![$($a),*]
                }
            }
        };
    }
    call_for_tuples!(impl_for_tuple);

    pub trait TupleExt<'a> {
        fn row(self) -> Row<'a>;
    }
}

pub use ext::TupleExt as _;