Skip to main content

ui_layout/
style.rs

1#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
2pub enum Display {
3    Flex {
4        flex_direction: FlexDirection,
5    },
6    #[default]
7    Block,
8    Inline,
9    None,
10}
11
12#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
13pub enum FlexDirection {
14    Row,
15    #[default]
16    Column,
17}
18
19#[derive(Debug, Clone, PartialEq)]
20pub enum Length {
21    Px(f32),
22    Percent(f32),
23    Vw(f32),
24    Vh(f32),
25    Auto,
26    // calc
27    Add(Box<Length>, Box<Length>),
28    Sub(Box<Length>, Box<Length>),
29    Mul(Box<Length>, f32),
30    Div(Box<Length>, f32),
31
32    Min(Box<Length>, Box<Length>),
33    Max(Box<Length>, Box<Length>),
34    Clamp {
35        min: Box<Length>,
36        val: Box<Length>,
37        max: Box<Length>,
38    },
39}
40
41impl Default for Length {
42    fn default() -> Self {
43        Length::Px(0.0)
44    }
45}
46
47impl Length {
48    /// Resolves a length value to pixels.
49    ///
50    /// If the containing block is `auto`, percentages are treated as `auto` for layout purposes.
51    /// This version uses a single viewport value (for backward compatibility with axis-based layout).
52    pub fn resolve_with(
53        &self,
54        containing_block: Option<f32>,
55        viewport_width: f32,
56        viewport_height: f32,
57    ) -> Option<f32> {
58        match self {
59            Length::Auto => None,
60            Length::Px(v) => Some(*v),
61            Length::Percent(p) => containing_block.map(|cb| cb * *p / 100.0),
62            Length::Vw(v) => Some(viewport_width * *v / 100.0),
63            Length::Vh(v) => Some(viewport_height * *v / 100.0),
64            Length::Add(a, b) => Some(
65                a.resolve_with(containing_block, viewport_width, viewport_height)?
66                    + b.resolve_with(containing_block, viewport_width, viewport_height)?,
67            ),
68            Length::Sub(a, b) => Some(
69                a.resolve_with(containing_block, viewport_width, viewport_height)?
70                    - b.resolve_with(containing_block, viewport_width, viewport_height)?,
71            ),
72            Length::Mul(a, n) => {
73                Some(a.resolve_with(containing_block, viewport_width, viewport_height)? * n)
74            }
75            Length::Div(a, n) => {
76                if *n == 0.0 {
77                    None
78                } else {
79                    Some(a.resolve_with(containing_block, viewport_width, viewport_height)? / n)
80                }
81            }
82            Length::Min(a, b) => Some(
83                a.resolve_with(containing_block, viewport_width, viewport_height)?
84                    .min(b.resolve_with(containing_block, viewport_width, viewport_height)?),
85            ),
86            Length::Max(a, b) => Some(
87                a.resolve_with(containing_block, viewport_width, viewport_height)?
88                    .max(b.resolve_with(containing_block, viewport_width, viewport_height)?),
89            ),
90            Length::Clamp { min, val, max } => {
91                let v = val.resolve_with(containing_block, viewport_width, viewport_height)?;
92                let min_v = min.resolve_with(containing_block, viewport_width, viewport_height)?;
93                let max_v = max.resolve_with(containing_block, viewport_width, viewport_height)?;
94
95                Some(v.clamp(min_v, max_v))
96            }
97        }
98    }
99}
100
101#[derive(Debug, Clone, PartialEq)]
102pub struct ItemStyle {
103    pub flex_grow: f32,
104    pub flex_shrink: f32,
105    pub flex_basis: Length,
106    pub align_self: Option<AlignItems>,
107}
108
109impl Default for ItemStyle {
110    fn default() -> Self {
111        ItemStyle {
112            flex_grow: 0.0,
113            flex_shrink: 1.0,
114            flex_basis: Length::Auto,
115            align_self: None,
116        }
117    }
118}
119
120#[derive(Debug, Clone, PartialEq)]
121pub struct SizeStyle {
122    pub width: Length,
123    pub height: Length,
124    pub min_width: Length,
125    pub max_width: Length,
126    pub min_height: Length,
127    pub max_height: Length,
128}
129
130impl Default for SizeStyle {
131    fn default() -> Self {
132        SizeStyle {
133            width: Length::Auto,
134            height: Length::Auto,
135            min_width: Length::Auto,
136            max_width: Length::Auto,
137            min_height: Length::Auto,
138            max_height: Length::Auto,
139        }
140    }
141}
142
143#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
144pub enum BoxSizing {
145    #[default]
146    ContentBox,
147    BorderBox,
148}
149
150#[derive(Debug, Clone, Default, PartialEq)]
151pub struct Spacing {
152    pub margin_top: Length,
153    pub margin_bottom: Length,
154    pub margin_left: Length,
155    pub margin_right: Length,
156
157    pub border_top: Length,
158    pub border_bottom: Length,
159    pub border_left: Length,
160    pub border_right: Length,
161
162    pub padding_top: Length,
163    pub padding_bottom: Length,
164    pub padding_left: Length,
165    pub padding_right: Length,
166}
167
168#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
169pub enum JustifyContent {
170    #[default]
171    Start,
172    Center,
173    End,
174    SpaceBetween,
175    SpaceAround,
176    SpaceEvenly,
177}
178
179#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
180pub enum AlignItems {
181    Start,
182    Center,
183    End,
184    #[default]
185    Stretch,
186}
187
188#[derive(Debug, Clone, Default, PartialEq)]
189pub struct Style {
190    pub display: Display,
191    pub item_style: ItemStyle,
192    pub size: SizeStyle,
193    pub box_sizing: BoxSizing,
194    pub spacing: Spacing,
195
196    pub justify_content: JustifyContent,
197    pub align_items: AlignItems,
198    pub column_gap: Length,
199    pub row_gap: Length,
200}
201
202// =======================
203
204use std::ops::{Add, Sub};
205
206impl Add for Length {
207    type Output = Length;
208
209    fn add(self, rhs: Length) -> Length {
210        Length::Add(Box::new(self), Box::new(rhs))
211    }
212}
213
214impl Sub for Length {
215    type Output = Length;
216
217    fn sub(self, rhs: Length) -> Length {
218        Length::Sub(Box::new(self), Box::new(rhs))
219    }
220}