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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#[derive(Debug, Clone, Copy)]
pub(crate) struct Padding {
    pub(crate) leading: f32,
    pub(crate) trailing: f32,
    pub(crate) top: f32,
    pub(crate) bottom: f32,
}

/// Alignment along the X axis
#[derive(Debug, Clone, Copy)]
pub enum XAlign {
    /// Aligns to the left in LTR layout
    Leading,
    /// Aligns to the horizontal center
    Center,
    /// Aligns to the right in LTR layout
    Trailing,
}

/// Alignment along the Y axis
#[derive(Debug, Clone, Copy)]
pub enum YAlign {
    /// Aligns to the top
    Top,
    /// Aligns to the vertical center
    Center,
    /// Aligns to the bottom
    Bottom,
}

/// An alignment along both the X and Y axis
#[derive(Debug, Clone, Copy)]
pub enum Align {
    /// Aligns to the top left in LTR layout
    TopLeading,
    /// Aligns to the top center
    TopCenter,
    /// Aligns to the top right in LTR layout
    TopTrailing,
    /// Aligns to the middle right in LTR layout
    CenterTrailing,
    /// Aligns to the bottom right in LTR layout
    BottomTrailing,
    /// Aligns to the bottom middle
    BottomCenter,
    /// Aligns to the bottom left in LTR layout
    BottomLeading,
    /// Aligns to the middle left in LTR layout
    CenterLeading,
    /// Aligns to the center in LTR layout - the default alignment
    CenterCenter,
}

/// An allocation of screen space as a rectangle
#[derive(Debug, Clone, Copy, Default)]
pub struct Area {
    /// Origin - usually the left-most X
    pub x: f32,
    /// Origin - usually the upper-most Y
    pub y: f32,
    /// Available width, starting at `x`
    pub width: f32,
    /// Available height, starting at `y`
    pub height: f32,
}

/// A builder for specifying size constraints. Used with `modifiers::size`.
/// Create a `Size::new()` & add constraints such as `Size::new().width(10.)`
#[derive(Debug, Clone, Copy)]
pub struct Size {
    pub(crate) width: Option<f32>,
    pub(crate) width_min: Option<f32>,
    pub(crate) width_max: Option<f32>,
    pub(crate) height: Option<f32>,
    pub(crate) height_min: Option<f32>,
    pub(crate) height_max: Option<f32>,
    pub(crate) x_align: XAlign,
    pub(crate) y_align: YAlign,
    pub(crate) x_relative: bool,
    pub(crate) y_relative: bool,
}

impl Default for Size {
    fn default() -> Self {
        Self::new()
    }
}

impl Size {
    /// Creates a default size object to add constraints to
    pub fn new() -> Self {
        Size {
            width: None,
            width_min: None,
            width_max: None,
            height: None,
            height_min: None,
            height_max: None,
            x_align: XAlign::Center,
            y_align: YAlign::Center,
            x_relative: false,
            y_relative: false,
        }
    }
    /// Specifies an explicit width for a node
    pub fn width(mut self, width: f32) -> Self {
        self.width = width.into();
        self.x_relative = false;
        self
    }
    /// Specifies an explicit height for a node
    pub fn height(mut self, height: f32) -> Self {
        self.height = height.into();
        self.y_relative = false;
        self
    }
    /// Specifies an explicit width for a node as a fraction of the available width
    pub fn width_relative(mut self, ratio: f32) -> Self {
        self.width = ratio.into();
        self.x_relative = true;
        self
    }
    /// Specifies an explicit height for a node as a fraction of the available height
    pub fn height_relative(mut self, ratio: f32) -> Self {
        self.height = ratio.into();
        self.y_relative = true;
        self
    }
    /// Specifies a lower bound on a node's width
    pub fn min_width(mut self, width: f32) -> Self {
        self.width_min = width.into();
        self
    }
    /// Specifies a lower bound on a node's height
    pub fn min_height(mut self, height: f32) -> Self {
        self.height_min = height.into();
        self
    }
    /// Specifies an upper bound on a node's width
    pub fn max_width(mut self, width: f32) -> Self {
        self.width_max = width.into();
        self
    }
    /// Specifies an upper bound on a node's height
    pub fn max_height(mut self, height: f32) -> Self {
        self.height_max = height.into();
        self
    }
    /// Specifies an alignment along the x axis.
    /// This will only have an effect if the node is constrained to be smaller than the area that is available
    /// Otherwise, there's no wiggle room!
    pub fn x_align(mut self, align: XAlign) -> Self {
        self.x_align = align;
        self
    }
    /// Specifies an alignment along the y axis.
    /// This will only have an effect if the node is constrained to be smaller than the area that is available
    /// Otherwise, there's no wiggle room!
    pub fn y_align(mut self, align: YAlign) -> Self {
        self.y_align = align;
        self
    }
    /// Specifies an alignment along both the x & y axis.
    /// This will only have an effect if the node is constrained along the axis to be smaller than the area that is available
    /// Otherwise, there's no wiggle room!
    pub fn align(mut self, align: Align) -> Self {
        match align {
            Align::TopLeading => {
                self.y_align = YAlign::Top;
                self.x_align = XAlign::Leading;
            }
            Align::TopCenter => {
                self.y_align = YAlign::Top;
                self.x_align = XAlign::Center;
            }
            Align::TopTrailing => {
                self.y_align = YAlign::Top;
                self.x_align = XAlign::Trailing;
            }
            Align::CenterTrailing => {
                self.y_align = YAlign::Center;
                self.x_align = XAlign::Trailing;
            }
            Align::BottomTrailing => {
                self.y_align = YAlign::Bottom;
                self.x_align = XAlign::Trailing;
            }
            Align::BottomCenter => {
                self.y_align = YAlign::Bottom;
                self.x_align = XAlign::Center;
            }
            Align::BottomLeading => {
                self.y_align = YAlign::Bottom;
                self.x_align = XAlign::Leading;
            }
            Align::CenterLeading => {
                self.y_align = YAlign::Center;
                self.x_align = XAlign::Leading;
            }
            Align::CenterCenter => {
                self.y_align = YAlign::Center;
                self.x_align = XAlign::Center;
            }
        }
        self
    }
}