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, "{:.p$?}.at{:.p$?}", self.size, self.origin, p = f.precision().unwrap_or(0))
26 }
27 }
28}
29impl fmt::Display for Rect {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 write!(f, "{:.p$} at {:.p$}", self.size, self.origin, p = f.precision().unwrap_or(0))
32 }
33}
34impl std::str::FromStr for Rect {
35 type Err = ParseCompositeError;
36
37 fn from_str(s: &str) -> Result<Self, Self::Err> {
38 if let Some((size, origin)) = s.split_once(".at") {
39 Ok(Self::new(Point::from_str(origin)?, Size::from_str(size)?))
40 } else if let Some((size, origin)) = s.split_once(" at ") {
41 Ok(Self::new(Point::from_str(origin.trim())?, Size::from_str(size.trim())?))
42 } else {
43 Err(ParseCompositeError::UnknownFormat)
44 }
45 }
46}
47impl Rect {
48 pub fn new<O: Into<Point>, S: Into<Size>>(origin: O, size: S) -> Self {
53 Rect {
54 origin: origin.into(),
55 size: size.into(),
56 }
57 }
58
59 pub fn from_size<S: Into<Size>>(size: S) -> Self {
61 Self::new(Point::zero(), size)
62 }
63
64 pub fn zero() -> Self {
66 Self::new(Point::zero(), Size::zero())
67 }
68
69 pub fn fill() -> Self {
71 Self::from_size(Size::fill())
72 }
73
74 pub fn min(&self) -> Point {
78 self.origin.clone()
79 }
80
81 pub fn max(&self) -> Point {
86 self.origin.clone() + self.size.clone()
87 }
88
89 pub fn min_x(&self) -> Length {
91 self.origin.x.clone()
92 }
93 pub fn min_y(&self) -> Length {
95 self.origin.y.clone()
96 }
97
98 pub fn max_x(&self) -> Length {
100 self.origin.x.clone() + self.size.width.clone()
101 }
102 pub fn max_y(&self) -> Length {
104 self.origin.y.clone() + self.size.height.clone()
105 }
106
107 pub fn translate(&self, by: impl Into<Vector>) -> Self {
109 let mut r = self.clone();
110 r.origin += by.into();
111 r
112 }
113
114 pub fn is_default(&self) -> bool {
116 self.origin.is_default() && self.size.is_default()
117 }
118
119 pub fn has_default(&self) -> bool {
121 self.origin.has_default() || self.size.has_default()
122 }
123
124 pub fn replace_default(&mut self, overwrite: &Rect) {
126 self.origin.replace_default(&overwrite.origin);
127 self.size.replace_default(&overwrite.size);
128 }
129}
130impl super::Layout2d for Rect {
131 type Px = PxRect;
132
133 fn layout_dft(&self, default: Self::Px) -> Self::Px {
134 PxRect {
135 origin: self.origin.layout_dft(default.origin),
136 size: self.size.layout_dft(default.size),
137 }
138 }
139
140 fn affect_mask(&self) -> LayoutMask {
141 self.origin.affect_mask() | self.size.affect_mask()
142 }
143}
144impl_length_comp_conversions! {
145 fn from(x: X, y: Y, width: W, height: H) -> Rect {
146 Rect::new((x, y), (width, height))
147 }
148}
149impl_from_and_into_var! {
150 fn from(rect: PxRect) -> Rect {
152 Rect::new(rect.origin, rect.size)
153 }
154
155 fn from(rect: DipRect) -> Rect {
157 Rect::new(rect.origin, rect.size)
158 }
159
160 fn from(size: Size) -> Rect {
161 Rect::from_size(size)
162 }
163
164 fn from<O: Into<Point>, S: Into<Size>>((origin, size): (O, S)) -> Rect {
166 Rect::new(origin, size)
167 }
168}
169impl<S: Into<Factor2d>> ops::Mul<S> for Rect {
170 type Output = Self;
171
172 fn mul(mut self, rhs: S) -> Self {
173 self *= rhs;
174 self
175 }
176}
177impl<S: Into<Factor2d>> ops::Mul<S> for &Rect {
178 type Output = Rect;
179
180 fn mul(self, rhs: S) -> Self::Output {
181 self.clone() * rhs
182 }
183}
184impl<S: Into<Factor2d>> ops::MulAssign<S> for Rect {
185 fn mul_assign(&mut self, rhs: S) {
186 let rhs = rhs.into();
187 self.origin *= rhs;
188 self.size *= rhs;
189 }
190}
191impl<S: Into<Factor2d>> ops::Div<S> for Rect {
192 type Output = Self;
193
194 fn div(mut self, rhs: S) -> Self {
195 self /= rhs;
196 self
197 }
198}
199impl<S: Into<Factor2d>> ops::Div<S> for &Rect {
200 type Output = Rect;
201
202 fn div(self, rhs: S) -> Self::Output {
203 self.clone() / rhs
204 }
205}
206impl<S: Into<Factor2d>> ops::DivAssign<S> for Rect {
207 fn div_assign(&mut self, rhs: S) {
208 let rhs = rhs.into();
209 self.origin /= rhs;
210 self.size /= rhs;
211 }
212}
213impl ops::Add for Rect {
214 type Output = Self;
215
216 fn add(mut self, rhs: Self) -> Self {
217 self += rhs;
218 self
219 }
220}
221impl ops::AddAssign for Rect {
222 fn add_assign(&mut self, rhs: Self) {
223 self.origin += rhs.origin;
224 self.size += rhs.size;
225 }
226}
227impl ops::Sub for Rect {
228 type Output = Self;
229
230 fn sub(mut self, rhs: Self) -> Self {
231 self -= rhs;
232 self
233 }
234}
235impl ops::SubAssign for Rect {
236 fn sub_assign(&mut self, rhs: Self) {
237 self.origin -= rhs.origin;
238 self.size -= rhs.size;
239 }
240}
241
242pub trait RectFromTuplesBuilder {
252 fn at<X: Into<Length>, Y: Into<Length>>(self, x: X, y: Y) -> Rect;
254}
255impl<W: Into<Length>, H: Into<Length>> RectFromTuplesBuilder for (W, H) {
256 fn at<X: Into<Length>, Y: Into<Length>>(self, x: X, y: Y) -> Rect {
257 Rect::new((x, y), self)
258 }
259}