1#[derive(Debug, Clone, Copy, PartialEq, Default)]
5pub struct Point {
6 pub x: f32,
7 pub y: f32,
8}
9
10impl Point {
11 pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
12
13 pub fn new(x: f32, y: f32) -> Self {
14 Self { x, y }
15 }
16
17 pub fn offset(self, dx: f32, dy: f32) -> Self {
18 Self {
19 x: self.x + dx,
20 y: self.y + dy,
21 }
22 }
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Default)]
27pub struct Size {
28 pub width: f32,
29 pub height: f32,
30}
31
32impl Size {
33 pub const ZERO: Self = Self {
34 width: 0.0,
35 height: 0.0,
36 };
37
38 pub fn new(width: f32, height: f32) -> Self {
39 Self { width, height }
40 }
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Default)]
45pub struct Rect {
46 pub x: f32,
47 pub y: f32,
48 pub width: f32,
49 pub height: f32,
50}
51
52impl Rect {
53 pub const ZERO: Self = Self {
54 x: 0.0,
55 y: 0.0,
56 width: 0.0,
57 height: 0.0,
58 };
59
60 pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
61 Self {
62 x,
63 y,
64 width,
65 height,
66 }
67 }
68
69 pub fn from_point_size(point: Point, size: Size) -> Self {
70 Self {
71 x: point.x,
72 y: point.y,
73 width: size.width,
74 height: size.height,
75 }
76 }
77
78 pub fn origin(&self) -> Point {
79 Point::new(self.x, self.y)
80 }
81
82 pub fn size(&self) -> Size {
83 Size::new(self.width, self.height)
84 }
85
86 pub fn right(&self) -> f32 {
87 self.x + self.width
88 }
89
90 pub fn bottom(&self) -> f32 {
91 self.y + self.height
92 }
93
94 pub fn contains(&self, point: Point) -> bool {
95 point.x >= self.x
96 && point.x <= self.right()
97 && point.y >= self.y
98 && point.y <= self.bottom()
99 }
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Default)]
104pub struct Edges {
105 pub top: f32,
106 pub right: f32,
107 pub bottom: f32,
108 pub left: f32,
109}
110
111impl Edges {
112 pub const ZERO: Self = Self {
113 top: 0.0,
114 right: 0.0,
115 bottom: 0.0,
116 left: 0.0,
117 };
118
119 pub fn new(top: f32, right: f32, bottom: f32, left: f32) -> Self {
120 Self {
121 top,
122 right,
123 bottom,
124 left,
125 }
126 }
127
128 pub fn all(value: f32) -> Self {
129 Self {
130 top: value,
131 right: value,
132 bottom: value,
133 left: value,
134 }
135 }
136
137 pub fn symmetric(vertical: f32, horizontal: f32) -> Self {
138 Self {
139 top: vertical,
140 right: horizontal,
141 bottom: vertical,
142 left: horizontal,
143 }
144 }
145
146 pub fn horizontal(&self) -> f32 {
148 self.left + self.right
149 }
150
151 pub fn vertical(&self) -> f32 {
153 self.top + self.bottom
154 }
155}
156
157#[derive(Debug, Clone, Copy, PartialEq)]
159pub enum AvailableSpace {
160 Definite(f32),
162 MinContent,
164 MaxContent,
166}
167
168impl AvailableSpace {
169 pub fn to_definite(self) -> Option<f32> {
170 match self {
171 AvailableSpace::Definite(v) => Some(v),
172 _ => None,
173 }
174 }
175
176 pub fn unwrap_or(self, default: f32) -> f32 {
177 match self {
178 AvailableSpace::Definite(v) => v,
179 _ => default,
180 }
181 }
182}
183
184impl Default for AvailableSpace {
185 fn default() -> Self {
186 AvailableSpace::Definite(0.0)
187 }
188}
189
190#[derive(Debug, Clone, Copy, PartialEq)]
192pub struct SizeConstraint {
193 pub available: AvailableSpace,
194 pub min: f32,
195 pub max: f32,
196}
197
198impl SizeConstraint {
199 pub fn new(available: AvailableSpace) -> Self {
200 Self {
201 available,
202 min: 0.0,
203 max: f32::INFINITY,
204 }
205 }
206
207 pub fn clamp(&self, value: f32) -> f32 {
208 value.max(self.min).min(self.max)
209 }
210}
211
212impl Default for SizeConstraint {
213 fn default() -> Self {
214 Self {
215 available: AvailableSpace::Definite(0.0),
216 min: 0.0,
217 max: f32::INFINITY,
218 }
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225
226 #[test]
227 fn test_point_offset() {
228 let p = Point::new(10.0, 20.0);
229 let q = p.offset(5.0, -3.0);
230 assert_eq!(q, Point::new(15.0, 17.0));
231 }
232
233 #[test]
234 fn test_edges_horizontal_vertical() {
235 let e = Edges::new(1.0, 2.0, 3.0, 4.0);
236 assert_eq!(e.horizontal(), 6.0);
237 assert_eq!(e.vertical(), 4.0);
238 }
239
240 #[test]
241 fn test_rect_contains() {
242 let r = Rect::new(10.0, 10.0, 100.0, 50.0);
243 assert!(r.contains(Point::new(50.0, 30.0)));
244 assert!(!r.contains(Point::new(5.0, 5.0)));
245 }
246
247 #[test]
248 fn test_size_constraint_clamp() {
249 let c = SizeConstraint {
250 available: AvailableSpace::Definite(100.0),
251 min: 20.0,
252 max: 80.0,
253 };
254 assert_eq!(c.clamp(50.0), 50.0);
255 assert_eq!(c.clamp(10.0), 20.0);
256 assert_eq!(c.clamp(100.0), 80.0);
257 }
258}