geng_ui/layout_widgets/
column.rs1use 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 _;