geng_ui/layout_widgets/
align.rs

1use super::*;
2
3pub struct Align<T> {
4    align: vec2<f64>,
5    maintain_aspect: bool,
6    flex: vec2<Option<f64>>,
7    child: T,
8}
9
10impl<T, R: AsRef<T>> AsRef<T> for Align<R> {
11    fn as_ref(&self) -> &T {
12        self.child.as_ref()
13    }
14}
15
16impl<T, R: AsMut<T>> AsMut<T> for Align<R> {
17    fn as_mut(&mut self) -> &mut T {
18        self.child.as_mut()
19    }
20}
21
22mod ext {
23    use super::*;
24
25    pub trait WidgetExt: Widget + Sized {
26        fn align(self, align: vec2<f64>) -> Align<Self> {
27            Align {
28                align,
29                maintain_aspect: false,
30                flex: vec2(None, None),
31                child: self,
32            }
33        }
34        fn center(self) -> Align<Self> {
35            self.align(vec2(0.5, 0.5))
36        }
37        fn flex_align(self, flex: vec2<Option<f64>>, align: vec2<f64>) -> Align<Self> {
38            Align {
39                align,
40                maintain_aspect: false,
41                flex,
42                child: self,
43            }
44        }
45        fn maintain_aspect(self, align: vec2<f64>) -> Align<Self> {
46            Align {
47                align,
48                maintain_aspect: true,
49                flex: vec2(None, None),
50                child: self,
51            }
52        }
53    }
54
55    impl<T: Widget> WidgetExt for T {}
56}
57
58pub use ext::WidgetExt as _;
59
60impl<T: Widget> Widget for Align<T> {
61    fn calc_constraints(&mut self, children: &ConstraintsContext) -> Constraints {
62        let mut result = children.get_constraints(&self.child);
63        if let Some(flex) = self.flex.x {
64            result.flex.x = flex;
65        }
66        if let Some(flex) = self.flex.y {
67            result.flex.y = flex;
68        }
69        result
70    }
71    fn layout_children(&mut self, cx: &mut LayoutContext) {
72        let size = cx.position.size();
73        let child_constraints = cx.get_constraints(&self.child);
74        let mut child_size = vec2(
75            if child_constraints.flex.x == 0.0 {
76                partial_min(child_constraints.min_size.x, size.x)
77            } else {
78                size.x
79            },
80            if child_constraints.flex.y == 0.0 {
81                partial_min(child_constraints.min_size.y, size.y)
82            } else {
83                size.y
84            },
85        );
86        if self.maintain_aspect && child_constraints.min_size != vec2(0.0, 0.0) {
87            let aspect = child_constraints.min_size.x / child_constraints.min_size.y;
88            if child_size.y * aspect > child_size.x {
89                child_size.y = child_size.x / aspect;
90            }
91            if child_size.y < child_size.x / aspect {
92                child_size.x = child_size.y * aspect;
93            }
94        }
95        cx.set_position(
96            &self.child,
97            Aabb2::point(
98                cx.position.bottom_left()
99                    + vec2(
100                        (size.x - child_size.x) * self.align.x,
101                        (size.y - child_size.y) * self.align.y,
102                    ),
103            )
104            .extend_positive(child_size),
105        );
106    }
107    fn walk_children_mut<'a>(&mut self, f: &mut dyn FnMut(&mut dyn Widget)) {
108        f(&mut self.child);
109    }
110}