clay_layout/
layout.rs

1use crate::{bindings::*, Declaration};
2
3/// Defines different sizing behaviors for an element.
4#[derive(Debug, Clone, Copy)]
5#[repr(u8)]
6pub enum SizingType {
7    /// The element's size is determined by its content and constrained by min/max values.
8    Fit = Clay__SizingType_CLAY__SIZING_TYPE_FIT,
9    /// The element expands to fill available space within min/max constraints.
10    Grow = Clay__SizingType_CLAY__SIZING_TYPE_GROW,
11    /// The element's size is fixed to a percentage of its parent.
12    Percent = Clay__SizingType_CLAY__SIZING_TYPE_PERCENT,
13    /// The element's size is set to a fixed value.
14    Fixed = Clay__SizingType_CLAY__SIZING_TYPE_FIXED,
15}
16
17/// Represents different sizing strategies for layout elements.
18#[derive(Debug, Clone, Copy)]
19pub enum Sizing {
20    /// Fits the element’s width/height within a min and max constraint.
21    Fit(f32, f32),
22    /// Expands the element to fill available space within min/max constraints.
23    Grow(f32, f32),
24    /// Sets a fixed width/height.
25    Fixed(f32),
26    /// Sets width/height as a percentage of its parent. Value should be between `0.0` and `1.0`.
27    Percent(f32),
28}
29
30/// Converts a `Sizing` value into a `Clay_SizingAxis` representation.
31impl From<Sizing> for Clay_SizingAxis {
32    fn from(value: Sizing) -> Self {
33        match value {
34            Sizing::Fit(min, max) => Self {
35                type_: SizingType::Fit as _,
36                size: Clay_SizingAxis__bindgen_ty_1 {
37                    minMax: Clay_SizingMinMax { min, max },
38                },
39            },
40            Sizing::Grow(min, max) => Self {
41                type_: SizingType::Grow as _,
42                size: Clay_SizingAxis__bindgen_ty_1 {
43                    minMax: Clay_SizingMinMax { min, max },
44                },
45            },
46            Sizing::Fixed(size) => Self {
47                type_: SizingType::Fixed as _,
48                size: Clay_SizingAxis__bindgen_ty_1 {
49                    minMax: Clay_SizingMinMax {
50                        min: size,
51                        max: size,
52                    },
53                },
54            },
55            Sizing::Percent(percent) => Self {
56                type_: SizingType::Percent as _,
57                size: Clay_SizingAxis__bindgen_ty_1 { percent },
58            },
59        }
60    }
61}
62
63/// Represents padding values for each side of an element.
64#[derive(Debug, Default)]
65pub struct Padding {
66    /// Padding on the left side.
67    pub left: u16,
68    /// Padding on the right side.
69    pub right: u16,
70    /// Padding on the top side.
71    pub top: u16,
72    /// Padding on the bottom side.
73    pub bottom: u16,
74}
75
76impl Padding {
77    /// Creates a new `Padding` with individual values for each side.
78    pub fn new(left: u16, right: u16, top: u16, bottom: u16) -> Self {
79        Self {
80            left,
81            right,
82            top,
83            bottom,
84        }
85    }
86
87    /// Sets the same padding value for all sides.
88    pub fn all(value: u16) -> Self {
89        Self::new(value, value, value, value)
90    }
91
92    /// Sets the same padding for left and right sides.
93    /// Top and bottom are set to `0`.
94    pub fn horizontal(value: u16) -> Self {
95        Self::new(value, value, 0, 0)
96    }
97
98    /// Sets the same padding for top and bottom sides.
99    /// Left and right are set to `0`.
100    pub fn vertical(value: u16) -> Self {
101        Self::new(0, 0, value, value)
102    }
103}
104
105/// Represents horizontal alignment options for layout elements.
106#[derive(Debug, Clone, Copy)]
107#[repr(u8)]
108pub enum LayoutAlignmentX {
109    /// Aligns to the left.
110    Left = Clay_LayoutAlignmentX_CLAY_ALIGN_X_LEFT,
111    /// Centers the element.
112    Center = Clay_LayoutAlignmentX_CLAY_ALIGN_X_CENTER,
113    /// Aligns to the right.
114    Right = Clay_LayoutAlignmentX_CLAY_ALIGN_X_RIGHT,
115}
116
117/// Represents vertical alignment options for layout elements.
118#[derive(Debug, Clone, Copy)]
119#[repr(u8)]
120pub enum LayoutAlignmentY {
121    /// Aligns to the top.
122    Top = Clay_LayoutAlignmentY_CLAY_ALIGN_Y_TOP,
123    /// Centers the element.
124    Center = Clay_LayoutAlignmentY_CLAY_ALIGN_Y_CENTER,
125    /// Aligns to the bottom.
126    Bottom = Clay_LayoutAlignmentY_CLAY_ALIGN_Y_BOTTOM,
127}
128
129/// Controls child alignment within a layout.
130#[derive(Debug, Copy, Clone)]
131pub struct Alignment {
132    pub x: LayoutAlignmentX,
133    pub y: LayoutAlignmentY,
134}
135
136impl Alignment {
137    /// Creates a new alignment setting for a layout.
138    pub fn new(x: LayoutAlignmentX, y: LayoutAlignmentY) -> Self {
139        Self { x, y }
140    }
141}
142
143/// Defines the layout direction for arranging child elements.
144#[derive(Debug, Clone, Copy)]
145#[repr(u8)]
146pub enum LayoutDirection {
147    /// Arranges elements from left to right.
148    LeftToRight = Clay_LayoutDirection_CLAY_LEFT_TO_RIGHT,
149    /// Arranges elements from top to bottom.
150    TopToBottom = Clay_LayoutDirection_CLAY_TOP_TO_BOTTOM,
151}
152
153/// Builder for configuring layout properties in a `Declaration`.
154pub struct LayoutBuilder<
155    'declaration,
156    'render,
157    ImageElementData: 'render,
158    CustomElementData: 'render,
159> {
160    parent: &'declaration mut Declaration<'render, ImageElementData, CustomElementData>,
161}
162
163impl<'declaration, 'render, ImageElementData: 'render, CustomElementData: 'render>
164    LayoutBuilder<'declaration, 'render, ImageElementData, CustomElementData>
165{
166    /// Creates a new `LayoutBuilder` with the given parent `Declaration`.
167    #[inline]
168    pub fn new(
169        parent: &'declaration mut Declaration<'render, ImageElementData, CustomElementData>,
170    ) -> Self {
171        LayoutBuilder { parent }
172    }
173
174    /// Sets the width of the layout.
175    #[inline]
176    pub fn width(&mut self, width: Sizing) -> &mut Self {
177        self.parent.inner.layout.sizing.width = width.into();
178        self
179    }
180
181    /// Sets the height of the layout.
182    #[inline]
183    pub fn height(&mut self, height: Sizing) -> &mut Self {
184        self.parent.inner.layout.sizing.height = height.into();
185        self
186    }
187
188    /// Sets padding values for the layout.
189    #[inline]
190    pub fn padding(&mut self, padding: Padding) -> &mut Self {
191        self.parent.inner.layout.padding.left = padding.left;
192        self.parent.inner.layout.padding.right = padding.right;
193        self.parent.inner.layout.padding.top = padding.top;
194        self.parent.inner.layout.padding.bottom = padding.bottom;
195        self
196    }
197
198    /// Sets the spacing between child elements.
199    #[inline]
200    pub fn child_gap(&mut self, child_gap: u16) -> &mut Self {
201        self.parent.inner.layout.childGap = child_gap;
202        self
203    }
204
205    /// Sets the alignment of child elements.
206    #[inline]
207    pub fn child_alignment(&mut self, child_alignment: Alignment) -> &mut Self {
208        self.parent.inner.layout.childAlignment.x = child_alignment.x as _;
209        self.parent.inner.layout.childAlignment.y = child_alignment.y as _;
210        self
211    }
212
213    /// Sets the layout direction.
214    #[inline]
215    pub fn direction(&mut self, direction: LayoutDirection) -> &mut Self {
216        self.parent.inner.layout.layoutDirection = direction as _;
217        self
218    }
219
220    /// Returns the modified `Declaration`.
221    #[inline]
222    pub fn end(&mut self) -> &mut Declaration<'render, ImageElementData, CustomElementData> {
223        self.parent
224    }
225}
226
227/// Shorthand macro for [`Sizing::Fit`]. Defaults max to `f32::MAX` if omitted.
228#[macro_export]
229macro_rules! fit {
230    ($min:expr, $max:expr) => {
231        $crate::layout::Sizing::Fit($min, $max)
232    };
233    ($min:expr) => {
234        fit!($min, f32::MAX)
235    };
236    () => {
237        fit!(0.0)
238    };
239}
240
241/// Shorthand macro for [`Sizing::Grow`]. Defaults max to `f32::MAX` if omitted.
242#[macro_export]
243macro_rules! grow {
244    ($min:expr, $max:expr) => {
245        $crate::layout::Sizing::Grow($min, $max)
246    };
247    ($min:expr) => {
248        grow!($min, f32::MAX)
249    };
250    () => {
251        grow!(0.0)
252    };
253}
254
255/// Shorthand macro for [`Sizing::Fixed`].
256#[macro_export]
257macro_rules! fixed {
258    ($val:expr) => {
259        $crate::layout::Sizing::Fixed($val)
260    };
261}
262
263/// Shorthand macro for [`Sizing::Percent`].
264/// The value has to be in range `0.0..=1.0`.
265#[macro_export]
266macro_rules! percent {
267    ($percent:expr) => {{
268        const _: () = assert!(
269            $percent >= 0.0 && $percent <= 1.0,
270            "Percent value must be between 0.0 and 1.0 inclusive!"
271        );
272        $crate::layout::Sizing::Percent($percent)
273    }};
274}
275
276#[cfg(test)]
277mod test {
278    use super::*;
279    use crate::{fit, fixed, grow, percent};
280
281    #[test]
282    fn fit_macro() {
283        let both_args = fit!(12.0, 34.0);
284        assert!(matches!(both_args, Sizing::Fit(12.0, 34.0)));
285
286        let one_arg = fit!(12.0);
287        assert!(matches!(one_arg, Sizing::Fit(12.0, f32::MAX)));
288
289        let zero_args = fit!();
290        assert!(matches!(zero_args, Sizing::Fit(0.0, f32::MAX)));
291    }
292
293    #[test]
294    fn grow_macro() {
295        let both_args = grow!(12.0, 34.0);
296        assert!(matches!(both_args, Sizing::Grow(12.0, 34.0)));
297
298        let one_arg = grow!(12.0);
299        assert!(matches!(one_arg, Sizing::Grow(12.0, f32::MAX)));
300
301        let zero_args = grow!();
302        assert!(matches!(zero_args, Sizing::Grow(0.0, f32::MAX)));
303    }
304
305    #[test]
306    fn fixed_macro() {
307        let value = fixed!(123.0);
308        assert!(matches!(value, Sizing::Fixed(123.0)));
309    }
310
311    #[test]
312    fn percent_macro() {
313        let value = percent!(0.5);
314        assert!(matches!(value, Sizing::Percent(0.5)));
315    }
316}