iris_ui/
geom.rs

1use core::fmt::{Display, Formatter};
2use core::ops::{Add, Sub};
3
4#[derive(Copy, Clone, PartialEq, Debug)]
5pub struct Size {
6    pub w: i32,
7    pub h: i32,
8}
9
10impl Size {
11    fn empty() -> Size {
12        Size { w: -99, h: -99 }
13    }
14}
15
16impl Size {
17    pub fn new(w: i32, h: i32) -> Size {
18        Size { w, h }
19    }
20    pub fn sub(&self, b: &Insets) -> Size {
21        Size {
22            w: self.w - b.left - b.right,
23            h: self.h - b.top - b.bottom,
24        }
25    }
26    pub fn add(&self, b: &Insets) -> Size {
27        Size {
28            w: self.w + b.left + b.right,
29            h: self.h + b.top + b.bottom,
30        }
31    }
32}
33impl Display for Size {
34    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
35        write!(f, "{}x{}", self.w, self.h)
36    }
37}
38impl Add<Size> for Size {
39    type Output = Size;
40
41    fn add(self, rhs: Size) -> Self::Output {
42        Self {
43            w: self.w + rhs.w,
44            h: self.h + rhs.h,
45        }
46    }
47}
48impl Add<Insets> for Size {
49    type Output = Size;
50
51    fn add(self, rhs: Insets) -> Self::Output {
52        Self {
53            w: self.w + rhs.left + rhs.right,
54            h: self.h + rhs.top + rhs.bottom,
55        }
56    }
57}
58impl Add<&Insets> for Size {
59    type Output = Size;
60
61    fn add(self, rhs: &Insets) -> Self::Output {
62        Self {
63            w: self.w + rhs.left + rhs.right,
64            h: self.h + rhs.top + rhs.bottom,
65        }
66    }
67}
68impl Sub<Insets> for Size {
69    type Output = Self;
70
71    fn sub(self, rhs: Insets) -> Self::Output {
72        Size {
73            w: self.w - rhs.left - rhs.right,
74            h: self.h - rhs.top - rhs.bottom,
75        }
76    }
77}
78
79#[derive(Copy, Clone, PartialEq, Debug, Default)]
80pub struct Insets {
81    pub left: i32,
82    pub right: i32,
83    pub top: i32,
84    pub bottom: i32,
85}
86
87impl Insets {
88    pub fn new(top: i32, right: i32, bottom: i32, left: i32) -> Insets {
89        Insets {
90            top,
91            right,
92            bottom,
93            left,
94        }
95    }
96    pub fn new_same(size: i32) -> Insets {
97        Insets {
98            top: size,
99            bottom: size,
100            left: size,
101            right: size,
102        }
103    }
104}
105
106#[derive(Copy, Clone, PartialEq, Debug)]
107pub struct Point {
108    pub x: i32,
109    pub y: i32,
110}
111
112impl Point {
113    pub(crate) fn negate(&self) -> Point {
114        Point {
115            x: -self.x,
116            y: -self.y,
117        }
118    }
119}
120
121impl Point {
122    pub(crate) fn subtract(&self, p0: &Point) -> Point {
123        Point {
124            x: self.x - p0.x,
125            y: self.y - p0.y,
126        }
127    }
128}
129
130impl Point {
131    pub fn new(x: i32, y: i32) -> Point {
132        Point { x, y }
133    }
134    pub fn zero() -> Point {
135        Point::new(0, 0)
136    }
137}
138impl Add<Point> for Point {
139    type Output = Point;
140
141    fn add(self, rhs: Point) -> Self::Output {
142        Point {
143            x: self.x + rhs.x,
144            y: self.y + rhs.y,
145        }
146    }
147}
148impl Sub<Point> for Point {
149    type Output = Point;
150
151    fn sub(self, rhs: Point) -> Self::Output {
152        Point {
153            x: self.x - rhs.x,
154            y: self.y - rhs.y,
155        }
156    }
157}
158impl Display for Point {
159    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
160        write!(f, "{},{}", self.x, self.y)
161    }
162}
163
164#[derive(Copy, Clone, Debug, PartialEq)]
165pub struct Bounds {
166    pub position: Point,
167    pub size: Size,
168}
169
170impl Bounds {
171    pub(crate) fn x(&self) -> i32 {
172        self.position.x
173    }
174    pub(crate) fn y(&self) -> i32 {
175        self.position.y
176    }
177    pub fn w(&self) -> i32 {
178        self.size.w
179    }
180    pub fn h(&self) -> i32 {
181        self.size.h
182    }
183}
184
185impl Bounds {
186    pub(crate) fn contract(&self, i: i32) -> Bounds {
187        Bounds {
188            position: Point {
189                x: self.position.x + i,
190                y: self.position.y + i,
191            },
192            size: Size {
193                w: self.size.w - i - i,
194                h: self.size.h - i - i,
195            },
196        }
197    }
198}
199
200impl Bounds {
201    pub fn new(x: i32, y: i32, w: i32, h: i32) -> Bounds {
202        Bounds {
203            position: Point::new(x, y),
204            size: Size::new(w, h),
205        }
206    }
207    pub fn new_from(position: Point, size: Size) -> Bounds {
208        Bounds { position, size }
209    }
210}
211impl Default for Bounds {
212    fn default() -> Self {
213        Bounds::new(0, 0, 100, 100)
214    }
215}
216impl Add<Point> for Bounds {
217    type Output = Bounds;
218
219    fn add(self, rhs: Point) -> Self::Output {
220        Bounds {
221            position: self.position + rhs,
222            size: self.size,
223        }
224    }
225}
226impl Sub<Point> for Bounds {
227    type Output = Bounds;
228
229    fn sub(self, rhs: Point) -> Self::Output {
230        Bounds {
231            position: self.position - rhs,
232            size: self.size,
233        }
234    }
235}
236impl Add<Insets> for Bounds {
237    type Output = Bounds;
238
239    fn add(self, rhs: Insets) -> Self::Output {
240        Bounds {
241            position: Point {
242                x: self.position.x - rhs.left,
243                y: self.position.y - rhs.top,
244            },
245            size: Size {
246                w: self.size.w + rhs.left + rhs.right,
247                h: self.size.h + rhs.top + rhs.bottom,
248            },
249        }
250    }
251}
252impl Sub<Insets> for Bounds {
253    type Output = Bounds;
254
255    fn sub(self, rhs: Insets) -> Self::Output {
256        Bounds {
257            position: Point {
258                x: self.position.x + rhs.left,
259                y: self.position.y + rhs.top,
260            },
261            size: Size {
262                w: self.size.w - rhs.left - rhs.right,
263                h: self.size.h - rhs.top - rhs.bottom,
264            },
265        }
266    }
267}
268impl Display for Bounds {
269    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
270        write!(
271            f,
272            "{},{} {}x{}",
273            self.position.x, self.position.y, self.size.w, self.size.h
274        )
275    }
276}
277impl Bounds {
278    pub fn union(&self, b: Bounds) -> Bounds {
279        if self.is_empty() {
280            return b;
281        }
282        if b.is_empty() {
283            return *self;
284        }
285        Bounds::from_xyxy2(
286            self.position.x.min(b.position.x),
287            self.position.y.min(b.position.y),
288            self.x2().max(b.x2()),
289            self.y2().max(b.y2()),
290        )
291    }
292    pub(crate) fn center(&self) -> Point {
293        Point::new(
294            self.position.x + self.size.w / 2,
295            self.position.y + self.size.h / 2,
296        )
297    }
298    fn from_xyxy2(x: i32, y: i32, x2: i32, y2: i32) -> Bounds {
299        Bounds {
300            position: Point::new(x, y),
301            size: Size::new(x2 - x, y2 - y),
302        }
303    }
304    pub fn x2(&self) -> i32 {
305        self.position.x + self.size.w
306    }
307    pub fn y2(&self) -> i32 {
308        self.position.y + self.size.h
309    }
310    pub fn center_at(&self, x: i32, y: i32) -> Bounds {
311        Bounds {
312            position: Point::new(x - self.size.w / 2, y - self.size.h / 2),
313            size: self.size,
314        }
315    }
316}
317
318impl Bounds {
319    pub fn new_empty() -> Bounds {
320        Bounds {
321            position: Point::zero(),
322            size: Size::empty(),
323        }
324    }
325}
326
327impl Bounds {
328    pub fn is_empty(&self) -> bool {
329        self.size.w < 1 || self.size.h < 1
330    }
331    pub fn contains(&self, pt: &Point) -> bool {
332        if self.position.x <= pt.x && self.position.y <= pt.y {
333            if self.position.x + self.size.w > pt.x && self.position.y + self.size.h > pt.y {
334                return true;
335            }
336        }
337        false
338    }
339}
340
341#[cfg(test)]
342mod tests {
343    use crate::geom::{Bounds, Insets, Point, Size};
344    use alloc::format;
345
346    #[test]
347    fn points() {
348        let p1 = Point::new(20, 30);
349        let p2 = Point::new(40, 50);
350        assert_eq!(p1 + p2, Point::new(60, 80));
351        assert_eq!(p1 - p2, Point::new(-20, -20));
352        assert_eq!(format!("{}", Point::new(20, 30)), "20,30");
353    }
354    #[test]
355    fn sizes() {
356        let a = Size::new(10, 10);
357        let b = Size::new(10, 10);
358        let c = Size::new(20, 20);
359        assert_eq!(a + b, c);
360        let d = Insets::new_same(10);
361        assert_eq!(a + d, Size::new(30, 30));
362        assert_eq!(format!("{}", Size::new(10, 20)), "10x20");
363    }
364    #[test]
365    fn bounds() {
366        let a = Bounds::new(10, 20, 30, 40);
367        let pt = Point::new(1, 1);
368        assert_eq!(format!("{}", a), "10,20 30x40");
369        assert_eq!(a + pt, Bounds::new(11, 21, 30, 40));
370        assert_eq!(a - pt, Bounds::new(9, 19, 30, 40));
371        assert_eq!(
372            Bounds::new_from(Point::new(5, 6), Size::new(7, 8)),
373            Bounds::new(5, 6, 7, 8)
374        );
375    }
376
377    #[test]
378    fn test_geometry() {
379        let bounds = Bounds::new(0, 0, 100, 100);
380        assert_eq!(bounds.contains(&Point::new(10, 10)), true);
381        assert_eq!(bounds.contains(&Point::new(-1, -1)), false);
382
383        let b2 = Bounds::new(140, 180, 80, 30);
384        let b3 = Bounds::new(140, 180, 80, 30);
385        // INFO - union Bounds { x: 140, y: 180, w: 80, h: 30 } Bounds { x: 140, y: 180, w: 80, h: 30 }
386        assert_eq!(b2.union(b3), b2.clone());
387    }
388    #[test]
389    fn test_point() {
390        let pt1 = Point::new(8, 9);
391        let pt2 = Point::new(10, 11);
392        let pt3 = pt1 + pt2;
393        assert_eq!(pt3, Point::new(18, 20));
394        let bounds = Bounds::new(1, 2, 3, 4);
395        assert_eq!(bounds.position, Point::new(1, 2));
396
397        let pt4 = pt1 - pt2;
398        assert_eq!(pt4, Point::new(-2, -2));
399    }
400}