1use core::fmt;
4
5use crate::{
6 impl_option, impl_vec, impl_vec_clone, impl_vec_debug, impl_vec_mut, impl_vec_partialeq,
7 impl_vec_partialord,
8};
9
10#[derive(Copy, Default, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
12#[repr(C)]
13pub struct LayoutPoint {
14 pub x: isize,
15 pub y: isize,
16}
17
18impl fmt::Debug for LayoutPoint {
19 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
20 write!(f, "{}", self)
21 }
22}
23impl fmt::Display for LayoutPoint {
24 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25 write!(f, "({}, {})", self.x, self.y)
26 }
27}
28
29impl LayoutPoint {
30 #[inline(always)]
31 pub const fn new(x: isize, y: isize) -> Self {
32 Self { x, y }
33 }
34 #[inline(always)]
35 pub const fn zero() -> Self {
36 Self::new(0, 0)
37 }
38}
39
40impl_option!(
41 LayoutPoint,
42 OptionLayoutPoint,
43 [Debug, Copy, Clone, PartialEq, PartialOrd]
44);
45
46#[derive(Copy, Default, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
48#[repr(C)]
49pub struct LayoutSize {
50 pub width: isize,
51 pub height: isize,
52}
53
54impl fmt::Debug for LayoutSize {
55 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56 write!(f, "{}", self)
57 }
58}
59impl fmt::Display for LayoutSize {
60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61 write!(f, "{}x{}", self.width, self.height)
62 }
63}
64
65impl LayoutSize {
66 #[inline(always)]
67 pub const fn new(width: isize, height: isize) -> Self {
68 Self { width, height }
69 }
70 #[inline(always)]
71 pub const fn zero() -> Self {
72 Self::new(0, 0)
73 }
74 #[inline]
75 pub fn round(width: f32, height: f32) -> Self {
76 Self {
77 width: libm::roundf(width) as isize,
78 height: libm::roundf(height) as isize,
79 }
80 }
81}
82
83impl_option!(
84 LayoutSize,
85 OptionLayoutSize,
86 [Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash]
87);
88
89#[derive(Copy, Clone, PartialEq, PartialOrd)]
91#[repr(C)]
92pub struct LayoutRect {
93 pub origin: LayoutPoint,
94 pub size: LayoutSize,
95}
96
97impl_option!(
98 LayoutRect,
99 OptionLayoutRect,
100 [Debug, Copy, Clone, PartialEq, PartialOrd]
101);
102impl_vec!(
103 LayoutRect,
104 LayoutRectVec,
105 LayoutRectVecDestructor,
106 LayoutRectVecDestructorType
107);
108impl_vec_clone!(LayoutRect, LayoutRectVec, LayoutRectVecDestructor);
109impl_vec_debug!(LayoutRect, LayoutRectVec);
110impl_vec_mut!(LayoutRect, LayoutRectVec);
111impl_vec_partialeq!(LayoutRect, LayoutRectVec);
112impl_vec_partialord!(LayoutRect, LayoutRectVec);
113
114impl fmt::Debug for LayoutRect {
115 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116 write!(f, "{}", self)
117 }
118}
119impl fmt::Display for LayoutRect {
120 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121 write!(f, "{} @ {}", self.size, self.origin)
122 }
123}
124
125impl LayoutRect {
126 #[inline(always)]
127 pub const fn new(origin: LayoutPoint, size: LayoutSize) -> Self {
128 Self { origin, size }
129 }
130 #[inline(always)]
131 pub const fn zero() -> Self {
132 Self::new(LayoutPoint::zero(), LayoutSize::zero())
133 }
134 #[inline(always)]
135 pub const fn max_x(&self) -> isize {
136 self.origin.x + self.size.width
137 }
138 #[inline(always)]
139 pub const fn min_x(&self) -> isize {
140 self.origin.x
141 }
142 #[inline(always)]
143 pub const fn max_y(&self) -> isize {
144 self.origin.y + self.size.height
145 }
146 #[inline(always)]
147 pub const fn min_y(&self) -> isize {
148 self.origin.y
149 }
150 #[inline(always)]
151 pub const fn width(&self) -> isize {
152 self.max_x() - self.min_x()
153 }
154 #[inline(always)]
155 pub const fn height(&self) -> isize {
156 self.max_y() - self.min_y()
157 }
158
159 pub const fn contains(&self, other: &LayoutPoint) -> bool {
160 self.min_x() <= other.x
161 && other.x < self.max_x()
162 && self.min_y() <= other.y
163 && other.y < self.max_y()
164 }
165
166 pub fn contains_f32(&self, other_x: f32, other_y: f32) -> bool {
167 self.min_x() as f32 <= other_x
168 && other_x < self.max_x() as f32
169 && self.min_y() as f32 <= other_y
170 && other_y < self.max_y() as f32
171 }
172
173 #[inline]
177 pub const fn hit_test(&self, other: &LayoutPoint) -> Option<LayoutPoint> {
178 let dx_left_edge = other.x - self.min_x();
179 let dx_right_edge = self.max_x() - other.x;
180 let dy_top_edge = other.y - self.min_y();
181 let dy_bottom_edge = self.max_y() - other.y;
182 if dx_left_edge > 0 && dx_right_edge > 0 && dy_top_edge > 0 && dy_bottom_edge > 0 {
183 Some(LayoutPoint::new(dx_left_edge, dy_top_edge))
184 } else {
185 None
186 }
187 }
188
189 #[inline]
191 pub fn union<I: Iterator<Item = Self>>(mut rects: I) -> Option<Self> {
192 let first = rects.next()?;
193
194 let mut max_width = first.size.width;
195 let mut max_height = first.size.height;
196 let mut min_x = first.origin.x;
197 let mut min_y = first.origin.y;
198
199 while let Some(Self {
200 origin: LayoutPoint { x, y },
201 size: LayoutSize { width, height },
202 }) = rects.next()
203 {
204 let cur_lower_right_x = x + width;
205 let cur_lower_right_y = y + height;
206 max_width = max_width.max(cur_lower_right_x - min_x);
207 max_height = max_height.max(cur_lower_right_y - min_y);
208 min_x = min_x.min(x);
209 min_y = min_y.min(y);
210 }
211
212 Some(Self {
213 origin: LayoutPoint { x: min_x, y: min_y },
214 size: LayoutSize {
215 width: max_width,
216 height: max_height,
217 },
218 })
219 }
220
221 #[inline]
223 pub fn get_scroll_rect<I: Iterator<Item = Self>>(&self, children: I) -> Option<Self> {
224 let children_union = Self::union(children)?;
225 Self::union([*self, children_union].iter().map(|r| *r))
226 }
227
228 #[inline(always)]
230 pub const fn contains_rect(&self, b: &LayoutRect) -> bool {
231 let a = self;
232
233 let a_x = a.origin.x;
234 let a_y = a.origin.y;
235 let a_width = a.size.width;
236 let a_height = a.size.height;
237
238 let b_x = b.origin.x;
239 let b_y = b.origin.y;
240 let b_width = b.size.width;
241 let b_height = b.size.height;
242
243 b_x >= a_x
244 && b_y >= a_y
245 && b_x + b_width <= a_x + a_width
246 && b_y + b_height <= a_y + a_height
247 }
248}