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
use super::*;

pub struct Align<T> {
    core: WidgetCore,
    align: Vec2<f64>,
    maintain_aspect: bool,
    flex: Vec2<Option<f64>>,
    child: T,
}

mod ext {
    use super::*;

    pub trait WidgetExt: Widget + Sized {
        fn align(self, align: Vec2<f64>) -> Align<Self> {
            Align {
                core: WidgetCore::void(),
                align,
                maintain_aspect: false,
                flex: vec2(None, None),
                child: self,
            }
        }
        fn flex_align(self, flex: Vec2<Option<f64>>, align: Vec2<f64>) -> Align<Self> {
            Align {
                core: WidgetCore::void(),
                align,
                maintain_aspect: false,
                flex,
                child: self,
            }
        }
        fn maintain_aspect(self, align: Vec2<f64>) -> Align<Self> {
            Align {
                core: WidgetCore::void(),
                align,
                maintain_aspect: true,
                flex: vec2(None, None),
                child: self,
            }
        }
    }

    impl<T: Widget> WidgetExt for T {}
}

pub use ext::WidgetExt as _;

impl<T: Widget> Widget for Align<T> {
    fn core(&self) -> &WidgetCore {
        &self.core
    }
    fn core_mut(&mut self) -> &mut WidgetCore {
        &mut self.core
    }
    fn calc_constraints(&mut self) {
        self.core.constraints = self.child.core().constraints;
        if let Some(flex) = self.flex.x {
            self.core.constraints.flex.x = flex;
        }
        if let Some(flex) = self.flex.y {
            self.core.constraints.flex.y = flex;
        }
    }
    fn layout_children(&mut self) {
        let size = self.core().position.size();
        let mut child_size = vec2(
            if self.child.core().constraints.flex.x == 0.0 {
                partial_min(self.child.core().constraints.min_size.x, size.x)
            } else {
                size.x
            },
            if self.child.core().constraints.flex.y == 0.0 {
                partial_min(self.child.core().constraints.min_size.y, size.y)
            } else {
                size.y
            },
        );
        if self.maintain_aspect && self.child.core().constraints.min_size != vec2(0.0, 0.0) {
            let aspect =
                self.child.core().constraints.min_size.x / self.child.core().constraints.min_size.y;
            if child_size.y * aspect > child_size.x {
                child_size.y = child_size.x / aspect;
            }
            if child_size.y < child_size.x / aspect {
                child_size.x = child_size.y * aspect;
            }
        }
        self.child.core_mut().position = AABB::pos_size(
            self.core().position.bottom_left()
                + vec2(
                    (size.x - child_size.x) * self.align.x,
                    (size.y - child_size.y) * self.align.y,
                ),
            child_size,
        );
    }
    fn walk_children_mut<'a>(&mut self, mut f: Box<dyn FnMut(&mut dyn Widget) + 'a>) {
        f(&mut self.child);
    }
}