altui_core/layout/
rect.rs1use std::cmp::{max, min};
2
3use crate::layout::{Direction, Margin};
4
5#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Default)]
8pub struct Rect {
9 pub x: u16,
10 pub y: u16,
11 pub width: u16,
12 pub height: u16,
13}
14
15impl Rect {
16 pub fn new(x: u16, y: u16, width: u16, height: u16) -> Rect {
19 let max_area = u16::max_value();
20 let (clipped_width, clipped_height) =
21 if u32::from(width) * u32::from(height) > u32::from(max_area) {
22 let aspect_ratio = f64::from(width) / f64::from(height);
23 let max_area_f = f64::from(max_area);
24 let height_f = (max_area_f / aspect_ratio).sqrt();
25 let width_f = height_f * aspect_ratio;
26 (width_f as u16, height_f as u16)
27 } else {
28 (width, height)
29 };
30 Rect {
31 x,
32 y,
33 width: clipped_width,
34 height: clipped_height,
35 }
36 }
37
38 pub fn area(self) -> u16 {
43 self.width * self.height
44 }
45
46 pub fn left(self) -> u16 {
48 self.x
49 }
50
51 pub fn right(self) -> u16 {
53 self.x.saturating_add(self.width)
54 }
55
56 pub fn top(self) -> u16 {
58 self.y
59 }
60
61 pub fn bottom(self) -> u16 {
63 self.y.saturating_add(self.height)
64 }
65
66 pub fn inner(self, margin: &Margin) -> Rect {
67 if self.width < 2 * margin.horizontal || self.height < 2 * margin.vertical {
68 Rect::default()
69 } else {
70 Rect {
71 x: self.x + margin.horizontal,
72 y: self.y + margin.vertical,
73 width: self.width - 2 * margin.horizontal,
74 height: self.height - 2 * margin.vertical,
75 }
76 }
77 }
78
79 pub fn union(self, other: Rect) -> Rect {
80 let x1 = min(self.x, other.x);
81 let y1 = min(self.y, other.y);
82 let x2 = max(self.x + self.width, other.x + other.width);
83 let y2 = max(self.y + self.height, other.y + other.height);
84 Rect {
85 x: x1,
86 y: y1,
87 width: x2 - x1,
88 height: y2 - y1,
89 }
90 }
91
92 pub fn intersection(self, other: Rect) -> Rect {
93 let x1 = max(self.x, other.x);
94 let y1 = max(self.y, other.y);
95 let x2 = min(self.x + self.width, other.x + other.width);
96 let y2 = min(self.y + self.height, other.y + other.height);
97 Rect {
98 x: x1,
99 y: y1,
100 width: x2 - x1,
101 height: y2 - y1,
102 }
103 }
104
105 pub fn intersects(self, other: Rect) -> bool {
106 self.x < other.x + other.width
107 && self.x + self.width > other.x
108 && self.y < other.y + other.height
109 && self.y + self.height > other.y
110 }
111
112 pub fn inhere(&self, x: u16, y: u16) -> bool {
113 x >= self.x && x < self.x + self.width && y >= self.y && y < self.y + self.height
114 }
115
116 #[inline(always)]
117 pub(crate) fn start(&self, direction: Direction) -> f64 {
118 match direction {
119 Direction::Horizontal => self.x as f64,
120 Direction::Vertical => self.y as f64,
121 }
122 }
123
124 #[inline(always)]
125 pub(crate) fn end(&self, direction: Direction) -> f64 {
126 match direction {
127 Direction::Horizontal => (self.x + self.width) as f64,
128 Direction::Vertical => (self.y + self.height) as f64,
129 }
130 }
131
132 #[inline(always)]
133 pub(crate) fn size(&self, direction: Direction) -> f64 {
134 match direction {
135 Direction::Horizontal => self.width as f64,
136 Direction::Vertical => self.height as f64,
137 }
138 }
139
140 #[inline(always)]
141 pub(crate) fn cross_start(&self, direction: Direction) -> f64 {
142 match direction {
143 Direction::Horizontal => self.y as f64,
144 Direction::Vertical => self.x as f64,
145 }
146 }
147
148 #[inline(always)]
149 pub(crate) fn cross_end(&self, direction: Direction) -> f64 {
150 match direction {
151 Direction::Horizontal => (self.y + self.height) as f64,
152 Direction::Vertical => (self.x + self.width) as f64,
153 }
154 }
155
156 #[inline(always)]
157 pub(crate) fn cross_size(&self, direction: Direction) -> f64 {
158 match direction {
159 Direction::Horizontal => self.height as f64,
160 Direction::Vertical => self.width as f64,
161 }
162 }
163}