1#[derive(Debug, Clone, Copy)]
3pub enum Size {
4 Shrink,
6 Exact(f32),
8 Fill(u32),
11}
12
13#[allow(missing_docs)]
15#[derive(Clone, Copy, Debug)]
16pub enum Align {
17 Begin,
18 Center,
19 End,
20}
21
22#[allow(missing_docs)]
24#[derive(Clone, Copy, Debug)]
25pub enum Direction {
26 TopToBottom,
27 LeftToRight,
28 RightToLeft,
29 BottomToTop,
30}
31
32#[allow(missing_docs)]
34#[derive(Clone, Copy, Debug)]
35pub struct Rectangle {
36 pub left: f32,
37 pub top: f32,
38 pub right: f32,
39 pub bottom: f32,
40}
41
42impl Size {
43 pub fn resolve(self, available_space: f32, available_parts: u32) -> f32 {
45 match self {
46 Size::Shrink => 0.0,
47 Size::Exact(wanted) => wanted,
48 Size::Fill(parts) => (available_space * parts as f32) / available_parts as f32,
49 }
50 }
51
52 pub fn parts(&self) -> u32 {
54 match self {
55 Size::Fill(parts) => *parts,
56 _ => 0,
57 }
58 }
59
60 pub fn min_size(&self) -> f32 {
62 match self {
63 Size::Exact(wanted) => *wanted,
64 _ => 0.0,
65 }
66 }
67}
68
69impl Align {
70 pub fn resolve_start(self, space: f32, available_space: f32) -> f32 {
72 match self {
73 Align::Begin => 0.0,
74 Align::Center => (available_space - space) * 0.5,
75 Align::End => available_space - space,
76 }
77 }
78}
79
80impl Rectangle {
81 pub fn to_device_coordinates(self, viewport: Rectangle) -> Rectangle {
85 let center = (
86 (viewport.left + viewport.right) * 0.5,
87 (viewport.top + viewport.bottom) * 0.5,
88 );
89 let size = (
90 (viewport.right - viewport.left) * 0.5,
91 (viewport.top - viewport.bottom) * -0.5,
92 );
93 Rectangle {
94 left: (self.left - center.0) / size.0,
95 top: (self.top - center.1) / size.1,
96 right: (self.right - center.0) / size.0,
97 bottom: (self.bottom - center.1) / size.1,
98 }
99 }
100
101 pub fn zero() -> Rectangle {
103 Rectangle {
104 left: 0.0,
105 right: 0.0,
106 top: 0.0,
107 bottom: 0.0,
108 }
109 }
110
111 pub fn from_wh(w: f32, h: f32) -> Rectangle {
113 Rectangle {
114 left: 0.0,
115 right: w,
116 top: 0.0,
117 bottom: h,
118 }
119 }
120
121 pub fn from_xywh(x: f32, y: f32, w: f32, h: f32) -> Rectangle {
123 Rectangle {
124 left: x,
125 right: x + w,
126 top: y,
127 bottom: y + h,
128 }
129 }
130
131 pub fn point_inside(&self, x: f32, y: f32) -> bool {
133 x >= self.left && x < self.right && y >= self.top && y < self.bottom
134 }
135
136 pub fn intersect(&self, other: &Rectangle) -> Option<Rectangle> {
139 let result = Rectangle {
140 left: self.left.max(other.left),
141 top: self.top.max(other.top),
142 right: self.right.min(other.right),
143 bottom: self.bottom.min(other.bottom),
144 };
145 if result.left < result.right && result.top < result.bottom {
146 Some(result)
147 } else {
148 None
149 }
150 }
151
152 pub fn pt(&self, x: f32, y: f32) -> [f32; 2] {
154 [
155 self.left + (self.right - self.left) * x,
156 self.top + (self.bottom - self.top) * y,
157 ]
158 }
159
160 pub fn round(self) -> Rectangle {
162 Rectangle {
163 left: self.left.round(),
164 top: self.top.round(),
165 right: self.right.round(),
166 bottom: self.bottom.round(),
167 }
168 }
169
170 pub(crate) fn sub(&self, lerps: Rectangle) -> Rectangle {
171 Rectangle {
172 left: self.left + (self.right - self.left) * lerps.left,
173 right: self.left + (self.right - self.left) * lerps.right,
174 top: self.top + (self.bottom - self.top) * lerps.top,
175 bottom: self.top + (self.bottom - self.top) * lerps.bottom,
176 }
177 }
178
179 pub fn translate(&self, x: f32, y: f32) -> Rectangle {
181 Rectangle {
182 left: self.left + x,
183 top: self.top + y,
184 right: self.right + x,
185 bottom: self.bottom + y,
186 }
187 }
188
189 pub fn grow(&self, w: f32, h: f32) -> Rectangle {
191 Rectangle {
192 left: self.left,
193 top: self.top,
194 right: self.right + w,
195 bottom: self.bottom + h,
196 }
197 }
198
199 pub fn inset(&self, x: f32, y: f32) -> Option<Rectangle> {
201 if self.width() > y * 2.0 && self.height() > x * 2.0 {
202 Some(Rectangle {
203 left: self.left + x,
204 top: self.top + y,
205 right: self.right - x,
206 bottom: self.bottom - y,
207 })
208 } else {
209 None
210 }
211 }
212
213 pub fn outset(&self, x: f32, y: f32) -> Rectangle {
215 Rectangle {
216 left: self.left - x,
217 top: self.top - y,
218 right: self.right + x,
219 bottom: self.bottom + y,
220 }
221 }
222
223 pub fn size(&self) -> Rectangle {
225 Rectangle {
226 left: 0.0,
227 top: 0.0,
228 right: self.width(),
229 bottom: self.height(),
230 }
231 }
232
233 pub fn width(&self) -> f32 {
235 self.right - self.left
236 }
237
238 pub fn height(&self) -> f32 {
240 self.bottom - self.top
241 }
242
243 pub fn after_margin(self, margin: Rectangle) -> Rectangle {
245 Rectangle {
246 left: self.left - margin.left,
247 top: self.top - margin.top,
248 right: self.right + margin.right,
249 bottom: self.bottom + margin.bottom,
250 }
251 }
252
253 pub fn after_padding(self, padding: Rectangle) -> Rectangle {
255 Rectangle {
256 left: self.left + padding.left,
257 top: self.top + padding.top,
258 right: self.right - padding.right,
259 bottom: self.bottom - padding.bottom,
260 }
261 }
262
263 pub fn union(self, other: Rectangle) -> Rectangle {
265 Rectangle {
266 left: self.left.min(other.left),
267 right: self.right.max(other.right),
268 top: self.top.min(other.top),
269 bottom: self.bottom.max(other.bottom),
270 }
271 }
272}
273
274impl From<[f32; 4]> for Rectangle {
275 fn from(a: [f32; 4]) -> Rectangle {
276 Rectangle {
277 left: a[0],
278 top: a[1],
279 right: a[2],
280 bottom: a[3],
281 }
282 }
283}
284
285impl From<f32> for Size {
286 fn from(value: f32) -> Size {
287 Size::Exact(value)
288 }
289}