1use crate::align::{AlignX, AlignY};
2use crate::engine;
3
4#[derive(Debug, Clone, Copy, Default)]
6pub struct CornerRadius {
7 pub top_left: f32,
8 pub top_right: f32,
9 pub bottom_left: f32,
10 pub bottom_right: f32,
11}
12
13impl CornerRadius {
14 pub fn is_zero(&self) -> bool {
16 self.top_left == 0.0
17 && self.top_right == 0.0
18 && self.bottom_left == 0.0
19 && self.bottom_right == 0.0
20 }
21}
22
23impl From<f32> for CornerRadius {
24 fn from(value: f32) -> Self {
26 Self {
27 top_left: value,
28 top_right: value,
29 bottom_left: value,
30 bottom_right: value,
31 }
32 }
33}
34
35impl From<(f32, f32, f32, f32)> for CornerRadius {
36 fn from((tl, tr, br, bl): (f32, f32, f32, f32)) -> Self {
38 Self {
39 top_left: tl,
40 top_right: tr,
41 bottom_left: bl,
42 bottom_right: br,
43 }
44 }
45}
46
47#[derive(Debug, Clone, Copy)]
49#[repr(u8)]
50pub enum SizingType {
51 Fit,
53 Grow,
55 Percent,
57 Fixed,
59}
60
61#[derive(Debug, Clone, Copy)]
63pub enum Sizing {
64 Fit(f32, f32),
66 Grow(f32, f32),
68 Fixed(f32),
70 Percent(f32),
72}
73
74impl From<Sizing> for engine::SizingAxis {
76 fn from(value: Sizing) -> Self {
77 match value {
78 Sizing::Fit(min, max) => Self {
79 type_: engine::SizingType::Fit,
80 min_max: engine::SizingMinMax { min, max },
81 percent: 0.0,
82 },
83 Sizing::Grow(min, max) => Self {
84 type_: engine::SizingType::Grow,
85 min_max: engine::SizingMinMax { min, max },
86 percent: 0.0,
87 },
88 Sizing::Fixed(size) => Self {
89 type_: engine::SizingType::Fixed,
90 min_max: engine::SizingMinMax {
91 min: size,
92 max: size,
93 },
94 percent: 0.0,
95 },
96 Sizing::Percent(percent) => Self {
97 type_: engine::SizingType::Percent,
98 min_max: engine::SizingMinMax { min: 0.0, max: 0.0 },
99 percent,
100 },
101 }
102 }
103}
104
105#[derive(Debug, Default)]
107pub struct Padding {
108 pub left: u16,
110 pub right: u16,
112 pub top: u16,
114 pub bottom: u16,
116}
117
118impl Padding {
119 pub fn new(left: u16, right: u16, top: u16, bottom: u16) -> Self {
121 Self {
122 left,
123 right,
124 top,
125 bottom,
126 }
127 }
128
129 pub fn all(value: u16) -> Self {
131 Self::new(value, value, value, value)
132 }
133
134 pub fn horizontal(value: u16) -> Self {
137 Self::new(value, value, 0, 0)
138 }
139
140 pub fn vertical(value: u16) -> Self {
143 Self::new(0, 0, value, value)
144 }
145}
146
147impl From<u16> for Padding {
148 fn from(value: u16) -> Self {
150 Self::all(value)
151 }
152}
153
154impl From<(u16, u16, u16, u16)> for Padding {
155 fn from((top, right, bottom, left): (u16, u16, u16, u16)) -> Self {
157 Self { left, right, top, bottom }
158 }
159}
160
161#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
163#[repr(u8)]
164pub enum LayoutDirection {
165 #[default]
167 LeftToRight,
168 TopToBottom,
170}
171
172pub struct LayoutBuilder {
175 pub(crate) config: engine::LayoutConfig,
176}
177
178impl LayoutBuilder {
179 #[inline]
181 pub fn gap(&mut self, gap: u16) -> &mut Self {
182 self.config.child_gap = gap;
183 self
184 }
185
186 #[inline]
188 pub fn align(&mut self, x: AlignX, y: AlignY) -> &mut Self {
189 self.config.child_alignment.x = x;
190 self.config.child_alignment.y = y;
191 self
192 }
193
194 #[inline]
196 pub fn direction(&mut self, direction: LayoutDirection) -> &mut Self {
197 self.config.layout_direction = direction;
198 self
199 }
200
201 #[inline]
203 pub fn padding(&mut self, padding: impl Into<Padding>) -> &mut Self {
204 let padding = padding.into();
205 self.config.padding.left = padding.left;
206 self.config.padding.right = padding.right;
207 self.config.padding.top = padding.top;
208 self.config.padding.bottom = padding.bottom;
209 self
210 }
211}
212
213#[macro_export]
215macro_rules! fit {
216 ($min:expr, $max:expr) => {
217 $crate::layout::Sizing::Fit($min, $max)
218 };
219 ($min:expr) => {
220 fit!($min, f32::MAX)
221 };
222 () => {
223 fit!(0.0)
224 };
225}
226
227#[macro_export]
229macro_rules! grow {
230 ($min:expr, $max:expr) => {
231 $crate::layout::Sizing::Grow($min, $max)
232 };
233 ($min:expr) => {
234 grow!($min, f32::MAX)
235 };
236 () => {
237 grow!(0.0)
238 };
239}
240
241#[macro_export]
243macro_rules! fixed {
244 ($val:expr) => {
245 $crate::layout::Sizing::Fixed($val)
246 };
247}
248
249#[macro_export]
252macro_rules! percent {
253 ($percent:expr) => {{
254 const _: () = assert!(
255 $percent >= 0.0 && $percent <= 1.0,
256 "Percent value must be between 0.0 and 1.0 inclusive!"
257 );
258 $crate::layout::Sizing::Percent($percent)
259 }};
260}
261
262#[cfg(test)]
263mod test {
264 use super::*;
265
266 #[test]
267 fn fit_macro() {
268 let both_args = fit!(12.0, 34.0);
269 assert!(matches!(both_args, Sizing::Fit(12.0, 34.0)));
270
271 let one_arg = fit!(12.0);
272 assert!(matches!(one_arg, Sizing::Fit(12.0, f32::MAX)));
273
274 let zero_args = fit!();
275 assert!(matches!(zero_args, Sizing::Fit(0.0, f32::MAX)));
276 }
277
278 #[test]
279 fn grow_macro() {
280 let both_args = grow!(12.0, 34.0);
281 assert!(matches!(both_args, Sizing::Grow(12.0, 34.0)));
282
283 let one_arg = grow!(12.0);
284 assert!(matches!(one_arg, Sizing::Grow(12.0, f32::MAX)));
285
286 let zero_args = grow!();
287 assert!(matches!(zero_args, Sizing::Grow(0.0, f32::MAX)));
288 }
289
290 #[test]
291 fn fixed_macro() {
292 let value = fixed!(123.0);
293 assert!(matches!(value, Sizing::Fixed(123.0)));
294 }
295
296 #[test]
297 fn percent_macro() {
298 let value = percent!(0.5);
299 assert!(matches!(value, Sizing::Percent(0.5)));
300 }
301}