1use std::{fmt, ops};
2
3use zng_var::{animation::Transitionable, impl_from_and_into_var};
4
5use crate::unit::{LengthCompositeParser, ParseCompositeError};
6
7use super::{DipSize, Factor, Factor2d, FactorPercent, Layout1d, LayoutMask, Length, PxSize, Rect, Vector, impl_length_comp_conversions};
8
9#[derive(Clone, Default, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, Transitionable)]
11pub struct Size {
12 pub width: Length,
14 pub height: Length,
16}
17impl fmt::Debug for Size {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 if f.alternate() {
20 f.debug_struct("Size")
21 .field("width", &self.width)
22 .field("height", &self.height)
23 .finish()
24 } else {
25 write!(f, "({:?}, {:?})", self.width, self.height)
26 }
27 }
28}
29impl fmt::Display for Size {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 if let Some(p) = f.precision() {
32 write!(f, "{:.p$} × {:.p$}", self.width, self.height, p = p)
33 } else {
34 write!(f, "{} × {}", self.width, self.height)
35 }
36 }
37}
38impl std::str::FromStr for Size {
39 type Err = ParseCompositeError;
40
41 fn from_str(s: &str) -> Result<Self, Self::Err> {
42 let mut parser = LengthCompositeParser::new_sep(s, &[',', '×'])?;
43 let a = parser.next()?;
44 if parser.has_ended() {
45 return Ok(Self::splat(a));
46 }
47 let b = parser.expect_last()?;
48 Ok(Self::new(a, b))
49 }
50}
51impl Size {
52 pub fn new<W: Into<Length>, H: Into<Length>>(width: W, height: H) -> Self {
54 Size {
55 width: width.into(),
56 height: height.into(),
57 }
58 }
59
60 pub fn splat(wh: impl Into<Length>) -> Self {
62 let wh = wh.into();
63 Size {
64 width: wh.clone(),
65 height: wh,
66 }
67 }
68
69 pub fn zero() -> Self {
71 Self::new(Length::zero(), Length::zero())
72 }
73
74 pub fn fill() -> Self {
78 Self::new(Length::fill(), Length::fill())
79 }
80
81 pub fn as_tuple(self) -> (Length, Length) {
83 (self.width, self.height)
84 }
85
86 pub fn as_array(self) -> [Length; 2] {
88 [self.width, self.height]
89 }
90
91 pub fn is_default(&self) -> bool {
93 self.width.is_default() && self.height.is_default()
94 }
95
96 pub fn has_default(&self) -> bool {
98 self.width.has_default() || self.height.has_default()
99 }
100
101 pub fn replace_default(&mut self, overwrite: &Size) {
103 self.width.replace_default(&overwrite.width);
104 self.height.replace_default(&overwrite.height);
105 }
106
107 pub fn as_vector(self) -> Vector {
109 Vector {
110 x: self.width,
111 y: self.height,
112 }
113 }
114}
115impl super::Layout2d for Size {
116 type Px = PxSize;
117
118 fn layout_dft(&self, default: Self::Px) -> Self::Px {
119 PxSize::new(self.width.layout_dft_x(default.width), self.height.layout_dft_y(default.height))
120 }
121
122 fn affect_mask(&self) -> LayoutMask {
123 self.width.affect_mask() | self.height.affect_mask()
124 }
125}
126impl_length_comp_conversions! {
127 fn from(width: W, height: H) -> Size {
128 Size::new(width, height)
129 }
130}
131impl_from_and_into_var! {
132 fn from(all: Length) -> Size {
134 Size::splat(all)
135 }
136
137 fn from(percent: FactorPercent) -> Size {
139 Size::splat(percent)
140 }
141 fn from(norm: Factor) -> Size {
143 Size::splat(norm)
144 }
145
146 fn from(f: f32) -> Size {
148 Size::splat(f)
149 }
150 fn from(i: i32) -> Size {
152 Size::splat(i)
153 }
154 fn from(size: PxSize) -> Size {
155 Size::new(size.width, size.height)
156 }
157 fn from(size: DipSize) -> Size {
158 Size::new(size.width, size.height)
159 }
160 fn from(v: Vector) -> Size {
161 v.as_size()
162 }
163 fn from(r: Rect) -> Size {
164 r.size
165 }
166}
167impl<S: Into<Size>> ops::Add<S> for Size {
168 type Output = Size;
169
170 fn add(self, rhs: S) -> Self::Output {
171 let rhs = rhs.into();
172
173 Size {
174 width: self.width + rhs.width,
175 height: self.height + rhs.height,
176 }
177 }
178}
179impl<S: Into<Size>> ops::AddAssign<S> for Size {
180 fn add_assign(&mut self, rhs: S) {
181 let rhs = rhs.into();
182 self.width += rhs.width;
183 self.height += rhs.height;
184 }
185}
186impl<S: Into<Size>> ops::Sub<S> for Size {
187 type Output = Size;
188
189 fn sub(self, rhs: S) -> Self::Output {
190 let rhs = rhs.into();
191
192 Size {
193 width: self.width - rhs.width,
194 height: self.height - rhs.height,
195 }
196 }
197}
198impl<S: Into<Size>> ops::SubAssign<S> for Size {
199 fn sub_assign(&mut self, rhs: S) {
200 let rhs = rhs.into();
201 self.width -= rhs.width;
202 self.height -= rhs.height;
203 }
204}
205impl<S: Into<Factor2d>> ops::Mul<S> for Size {
206 type Output = Self;
207
208 fn mul(mut self, rhs: S) -> Self {
209 self *= rhs;
210 self
211 }
212}
213impl<S: Into<Factor2d>> ops::Mul<S> for &Size {
214 type Output = Size;
215
216 fn mul(self, rhs: S) -> Self::Output {
217 self.clone() * rhs
218 }
219}
220impl<S: Into<Factor2d>> ops::MulAssign<S> for Size {
221 fn mul_assign(&mut self, rhs: S) {
222 let rhs = rhs.into();
223 self.width *= rhs.x;
224 self.height *= rhs.y;
225 }
226}
227impl<S: Into<Factor2d>> ops::Div<S> for Size {
228 type Output = Self;
229
230 fn div(mut self, rhs: S) -> Self {
231 self /= rhs;
232 self
233 }
234}
235impl<S: Into<Factor2d>> ops::Div<S> for &Size {
236 type Output = Size;
237
238 fn div(self, rhs: S) -> Self::Output {
239 self.clone() / rhs
240 }
241}
242impl<S: Into<Factor2d>> ops::DivAssign<S> for Size {
243 fn div_assign(&mut self, rhs: S) {
244 let rhs = rhs.into();
245 self.width /= rhs.x;
246 self.height /= rhs.y;
247 }
248}