Skip to main content

ui_layout/
geometry.rs

1#[derive(Debug, Clone, Copy, Default, PartialEq)]
2pub struct Rect {
3    pub x: f32,
4    pub y: f32,
5    pub width: f32,
6    pub height: f32,
7}
8
9#[derive(Debug, Clone, Default)]
10pub struct BoxModel {
11    pub border_box: Rect,
12    pub padding_box: Rect,
13    pub content_box: Rect,
14    /// Scrollable content size
15    pub children_box: Rect,
16}
17
18#[derive(Debug, Clone, Default)]
19pub enum LayoutBoxes {
20    #[default]
21    None,
22    Single(BoxModel),
23    Multiple(Vec<BoxModel>),
24}
25
26impl Rect {
27    pub fn right(&self) -> f32 {
28        self.x + self.width
29    }
30
31    pub fn bottom(&self) -> f32 {
32        self.y + self.height
33    }
34
35    pub fn size(&self) -> (f32, f32) {
36        (self.width, self.height)
37    }
38
39    fn shift(&mut self, dx: f32, dy: f32) {
40        self.x += dx;
41        self.y += dy;
42    }
43}
44
45impl BoxModel {
46    /// Translates the entire box by the given offset.
47    fn shift(&mut self, dx: f32, dy: f32) {
48        self.border_box.shift(dx, dy);
49        self.padding_box.shift(dx, dy);
50        self.content_box.shift(dx, dy);
51        self.children_box.shift(dx, dy);
52    }
53
54    /// Returns the width based on border-box dimensions.
55    pub fn width(&self) -> f32 {
56        self.border_box.width
57    }
58
59    /// Returns the height based on border-box dimensions.
60    pub fn height(&self) -> f32 {
61        self.border_box.height
62    }
63}
64
65impl LayoutBoxes {
66    pub(crate) fn shift(&mut self, dx: f32, dy: f32) {
67        match self {
68            LayoutBoxes::None => {}
69            LayoutBoxes::Single(b) => b.shift(dx, dy),
70            LayoutBoxes::Multiple(list) => {
71                for b in list {
72                    b.shift(dx, dy);
73                }
74            }
75        }
76    }
77
78    /// Returns the maximum width among all boxes.
79    pub fn width(&self) -> f32 {
80        match self {
81            LayoutBoxes::None => 0.0,
82            LayoutBoxes::Single(b) => b.width(),
83            LayoutBoxes::Multiple(list) => list.iter().map(|b| b.width()).fold(0.0, f32::max),
84        }
85    }
86
87    /// Returns the total height (sum of all boxes).
88    pub fn height(&self) -> f32 {
89        match self {
90            LayoutBoxes::None => 0.0,
91            LayoutBoxes::Single(b) => b.height(),
92            LayoutBoxes::Multiple(list) => list.iter().map(|b| b.height()).sum(),
93        }
94    }
95
96    pub fn is_empty(&self) -> bool {
97        match self {
98            LayoutBoxes::None => true,
99            LayoutBoxes::Single(_) => false,
100            LayoutBoxes::Multiple(v) => v.is_empty(),
101        }
102    }
103
104    pub fn len(&self) -> usize {
105        match self {
106            LayoutBoxes::None => 0,
107            LayoutBoxes::Single(_) => 1,
108            LayoutBoxes::Multiple(v) => v.len(),
109        }
110    }
111
112    /// Returns an iterator over references to the contained [`BoxModel`]s.
113    ///
114    /// The iteration order is:
115    /// - empty for [`LayoutBoxes::None`]
116    /// - a single element for [`LayoutBoxes::Single`]
117    /// - the order of elements in the inner vector for [`LayoutBoxes::Multiple`]
118    ///
119    /// This method provides a convenient way to iterate over all boxes
120    /// regardless of the internal representation.
121    pub fn iter(&self) -> impl Iterator<Item = &BoxModel> {
122        self.into_iter()
123    }
124
125    /// Returns an iterator over mutable references to the contained [`BoxModel`]s.
126    ///
127    /// The iteration order is:
128    /// - empty for [`LayoutBoxes::None`]
129    /// - a single element for [`LayoutBoxes::Single`]
130    /// - the order of elements in the inner vector for [`LayoutBoxes::Multiple`]
131    ///
132    /// This allows in-place modification of all boxes in a uniform way.
133    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut BoxModel> {
134        self.into_iter()
135    }
136}
137
138// =============================================
139//   Implementing IntoIterator for LayoutBoxes
140// =============================================
141
142impl<'a> IntoIterator for &'a LayoutBoxes {
143    type Item = &'a BoxModel;
144    type IntoIter = std::slice::Iter<'a, BoxModel>;
145
146    fn into_iter(self) -> Self::IntoIter {
147        match self {
148            LayoutBoxes::None => [].iter(),
149            LayoutBoxes::Single(b) => std::slice::from_ref(b).iter(),
150            LayoutBoxes::Multiple(list) => list.iter(),
151        }
152    }
153}
154
155impl<'a> IntoIterator for &'a mut LayoutBoxes {
156    type Item = &'a mut BoxModel;
157    type IntoIter = std::slice::IterMut<'a, BoxModel>;
158
159    fn into_iter(self) -> Self::IntoIter {
160        match self {
161            LayoutBoxes::None => [].iter_mut(),
162            LayoutBoxes::Single(b) => std::slice::from_mut(b).iter_mut(),
163            LayoutBoxes::Multiple(list) => list.iter_mut(),
164        }
165    }
166}
167
168impl IntoIterator for LayoutBoxes {
169    type Item = BoxModel;
170    type IntoIter = std::vec::IntoIter<BoxModel>;
171
172    fn into_iter(self) -> Self::IntoIter {
173        match self {
174            LayoutBoxes::None => Vec::new().into_iter(),
175            LayoutBoxes::Single(b) => vec![b].into_iter(),
176            LayoutBoxes::Multiple(list) => list.into_iter(),
177        }
178    }
179}