1use std::{fmt, ops};
2
3use zng_var::{animation::Transitionable, impl_from_and_into_var};
4
5use crate::unit::ParseCompositeError;
6
7use super::{DipRect, Factor2d, LayoutMask, Length, Point, PxRect, Size, Vector, impl_length_comp_conversions};
8
9#[derive(Clone, Default, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, Transitionable)]
11pub struct Rect {
12 pub origin: Point,
14 pub size: Size,
16}
17impl fmt::Debug for Rect {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 if f.alternate() {
20 f.debug_struct("Rect")
21 .field("origin", &self.origin)
22 .field("size", &self.size)
23 .finish()
24 } else {
25 write!(f, "{:?}.at{:?}", self.origin, self.size)
26 }
27 }
28}
29impl fmt::Display for Rect {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 if let Some(p) = f.precision() {
32 write!(f, "{:.p$} {:.p$}", self.origin, self.size, p = p)
33 } else {
34 write!(f, "{} at {}", self.origin, self.size)
35 }
36 }
37}
38impl std::str::FromStr for Rect {
39 type Err = ParseCompositeError;
40
41 fn from_str(s: &str) -> Result<Self, Self::Err> {
42 if let Some((size, origin)) = s.split_once(".at") {
43 Ok(Self::new(Point::from_str(origin)?, Size::from_str(size)?))
44 } else if let Some((size, origin)) = s.split_once(" at ") {
45 Ok(Self::new(Point::from_str(origin.trim())?, Size::from_str(size.trim())?))
46 } else {
47 Err(ParseCompositeError::UnknownFormat)
48 }
49 }
50}
51impl Rect {
52 pub fn new<O: Into<Point>, S: Into<Size>>(origin: O, size: S) -> Self {
57 Rect {
58 origin: origin.into(),
59 size: size.into(),
60 }
61 }
62
63 pub fn from_size<S: Into<Size>>(size: S) -> Self {
65 Self::new(Point::zero(), size)
66 }
67
68 pub fn zero() -> Self {
70 Self::new(Point::zero(), Size::zero())
71 }
72
73 pub fn fill() -> Self {
75 Self::from_size(Size::fill())
76 }
77
78 pub fn min(&self) -> Point {
82 self.origin.clone()
83 }
84
85 pub fn max(&self) -> Point {
90 self.origin.clone() + self.size.clone()
91 }
92
93 pub fn min_x(&self) -> Length {
95 self.origin.x.clone()
96 }
97 pub fn min_y(&self) -> Length {
99 self.origin.y.clone()
100 }
101
102 pub fn max_x(&self) -> Length {
104 self.origin.x.clone() + self.size.width.clone()
105 }
106 pub fn max_y(&self) -> Length {
108 self.origin.y.clone() + self.size.height.clone()
109 }
110
111 pub fn translate(&self, by: impl Into<Vector>) -> Self {
113 let mut r = self.clone();
114 r.origin += by.into();
115 r
116 }
117
118 pub fn is_default(&self) -> bool {
120 self.origin.is_default() && self.size.is_default()
121 }
122
123 pub fn has_default(&self) -> bool {
125 self.origin.has_default() || self.size.has_default()
126 }
127
128 pub fn replace_default(&mut self, overwrite: &Rect) {
130 self.origin.replace_default(&overwrite.origin);
131 self.size.replace_default(&overwrite.size);
132 }
133}
134impl super::Layout2d for Rect {
135 type Px = PxRect;
136
137 fn layout_dft(&self, default: Self::Px) -> Self::Px {
138 PxRect {
139 origin: self.origin.layout_dft(default.origin),
140 size: self.size.layout_dft(default.size),
141 }
142 }
143
144 fn affect_mask(&self) -> LayoutMask {
145 self.origin.affect_mask() | self.size.affect_mask()
146 }
147}
148impl_length_comp_conversions! {
149 fn from(x: X, y: Y, width: W, height: H) -> Rect {
150 Rect::new((x, y), (width, height))
151 }
152}
153impl_from_and_into_var! {
154 fn from(rect: PxRect) -> Rect {
156 Rect::new(rect.origin, rect.size)
157 }
158
159 fn from(rect: DipRect) -> Rect {
161 Rect::new(rect.origin, rect.size)
162 }
163
164 fn from(size: Size) -> Rect {
165 Rect::from_size(size)
166 }
167
168 fn from<O: Into<Point>, S: Into<Size>>((origin, size): (O, S)) -> Rect {
170 Rect::new(origin, size)
171 }
172}
173impl<S: Into<Factor2d>> ops::Mul<S> for Rect {
174 type Output = Self;
175
176 fn mul(mut self, rhs: S) -> Self {
177 self *= rhs;
178 self
179 }
180}
181impl<S: Into<Factor2d>> ops::Mul<S> for &Rect {
182 type Output = Rect;
183
184 fn mul(self, rhs: S) -> Self::Output {
185 self.clone() * rhs
186 }
187}
188impl<S: Into<Factor2d>> ops::MulAssign<S> for Rect {
189 fn mul_assign(&mut self, rhs: S) {
190 let rhs = rhs.into();
191 self.origin *= rhs;
192 self.size *= rhs;
193 }
194}
195impl<S: Into<Factor2d>> ops::Div<S> for Rect {
196 type Output = Self;
197
198 fn div(mut self, rhs: S) -> Self {
199 self /= rhs;
200 self
201 }
202}
203impl<S: Into<Factor2d>> ops::Div<S> for &Rect {
204 type Output = Rect;
205
206 fn div(self, rhs: S) -> Self::Output {
207 self.clone() / rhs
208 }
209}
210impl<S: Into<Factor2d>> ops::DivAssign<S> for Rect {
211 fn div_assign(&mut self, rhs: S) {
212 let rhs = rhs.into();
213 self.origin /= rhs;
214 self.size /= rhs;
215 }
216}
217impl ops::Add for Rect {
218 type Output = Self;
219
220 fn add(mut self, rhs: Self) -> Self {
221 self += rhs;
222 self
223 }
224}
225impl ops::AddAssign for Rect {
226 fn add_assign(&mut self, rhs: Self) {
227 self.origin += rhs.origin;
228 self.size += rhs.size;
229 }
230}
231impl ops::Sub for Rect {
232 type Output = Self;
233
234 fn sub(mut self, rhs: Self) -> Self {
235 self -= rhs;
236 self
237 }
238}
239impl ops::SubAssign for Rect {
240 fn sub_assign(&mut self, rhs: Self) {
241 self.origin -= rhs.origin;
242 self.size -= rhs.size;
243 }
244}
245
246pub trait RectFromTuplesBuilder {
256 fn at<X: Into<Length>, Y: Into<Length>>(self, x: X, y: Y) -> Rect;
258}
259impl<W: Into<Length>, H: Into<Length>> RectFromTuplesBuilder for (W, H) {
260 fn at<X: Into<Length>, Y: Into<Length>>(self, x: X, y: Y) -> Rect {
261 Rect::new((x, y), self)
262 }
263}