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, "({:.p$?}, {:.p$?})", self.width, self.height, p = f.precision().unwrap_or(0))
26 }
27 }
28}
29impl fmt::Display for Size {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 write!(f, "({:.p$} × {:.p$})", self.width, self.height, p = f.precision().unwrap_or(0))
32 }
33}
34impl std::str::FromStr for Size {
35 type Err = ParseCompositeError;
36
37 fn from_str(s: &str) -> Result<Self, Self::Err> {
38 let mut parser = LengthCompositeParser::new_sep(s, &[',', '×'])?;
39 let a = parser.next()?;
40 if parser.has_ended() {
41 return Ok(Self::splat(a));
42 }
43 let b = parser.expect_last()?;
44 Ok(Self::new(a, b))
45 }
46}
47impl Size {
48 pub fn new<W: Into<Length>, H: Into<Length>>(width: W, height: H) -> Self {
50 Size {
51 width: width.into(),
52 height: height.into(),
53 }
54 }
55
56 pub fn splat(wh: impl Into<Length>) -> Self {
58 let wh = wh.into();
59 Size {
60 width: wh.clone(),
61 height: wh,
62 }
63 }
64
65 pub fn zero() -> Self {
67 Self::new(Length::zero(), Length::zero())
68 }
69
70 pub fn fill() -> Self {
74 Self::new(Length::fill(), Length::fill())
75 }
76
77 pub fn as_tuple(self) -> (Length, Length) {
79 (self.width, self.height)
80 }
81
82 pub fn as_array(self) -> [Length; 2] {
84 [self.width, self.height]
85 }
86
87 pub fn is_default(&self) -> bool {
89 self.width.is_default() && self.height.is_default()
90 }
91
92 pub fn has_default(&self) -> bool {
94 self.width.has_default() || self.height.has_default()
95 }
96
97 pub fn replace_default(&mut self, overwrite: &Size) {
99 self.width.replace_default(&overwrite.width);
100 self.height.replace_default(&overwrite.height);
101 }
102
103 pub fn as_vector(self) -> Vector {
105 Vector {
106 x: self.width,
107 y: self.height,
108 }
109 }
110}
111impl super::Layout2d for Size {
112 type Px = PxSize;
113
114 fn layout_dft(&self, default: Self::Px) -> Self::Px {
115 PxSize::new(self.width.layout_dft_x(default.width), self.height.layout_dft_y(default.height))
116 }
117
118 fn affect_mask(&self) -> LayoutMask {
119 self.width.affect_mask() | self.height.affect_mask()
120 }
121}
122impl_length_comp_conversions! {
123 fn from(width: W, height: H) -> Size {
124 Size::new(width, height)
125 }
126}
127impl_from_and_into_var! {
128 fn from(all: Length) -> Size {
130 Size::splat(all)
131 }
132
133 fn from(percent: FactorPercent) -> Size {
135 Size::splat(percent)
136 }
137 fn from(norm: Factor) -> Size {
139 Size::splat(norm)
140 }
141
142 fn from(f: f32) -> Size {
144 Size::splat(f)
145 }
146 fn from(i: i32) -> Size {
148 Size::splat(i)
149 }
150 fn from(size: PxSize) -> Size {
151 Size::new(size.width, size.height)
152 }
153 fn from(size: DipSize) -> Size {
154 Size::new(size.width, size.height)
155 }
156 fn from(v: Vector) -> Size {
157 v.as_size()
158 }
159 fn from(r: Rect) -> Size {
160 r.size
161 }
162}
163impl<S: Into<Size>> ops::Add<S> for Size {
164 type Output = Size;
165
166 fn add(self, rhs: S) -> Self::Output {
167 let rhs = rhs.into();
168
169 Size {
170 width: self.width + rhs.width,
171 height: self.height + rhs.height,
172 }
173 }
174}
175impl<S: Into<Size>> ops::AddAssign<S> for Size {
176 fn add_assign(&mut self, rhs: S) {
177 let rhs = rhs.into();
178 self.width += rhs.width;
179 self.height += rhs.height;
180 }
181}
182impl<S: Into<Size>> ops::Sub<S> for Size {
183 type Output = Size;
184
185 fn sub(self, rhs: S) -> Self::Output {
186 let rhs = rhs.into();
187
188 Size {
189 width: self.width - rhs.width,
190 height: self.height - rhs.height,
191 }
192 }
193}
194impl<S: Into<Size>> ops::SubAssign<S> for Size {
195 fn sub_assign(&mut self, rhs: S) {
196 let rhs = rhs.into();
197 self.width -= rhs.width;
198 self.height -= rhs.height;
199 }
200}
201impl<S: Into<Factor2d>> ops::Mul<S> for Size {
202 type Output = Self;
203
204 fn mul(mut self, rhs: S) -> Self {
205 self *= rhs;
206 self
207 }
208}
209impl<S: Into<Factor2d>> ops::Mul<S> for &Size {
210 type Output = Size;
211
212 fn mul(self, rhs: S) -> Self::Output {
213 self.clone() * rhs
214 }
215}
216impl<S: Into<Factor2d>> ops::MulAssign<S> for Size {
217 fn mul_assign(&mut self, rhs: S) {
218 let rhs = rhs.into();
219 self.width *= rhs.x;
220 self.height *= rhs.y;
221 }
222}
223impl<S: Into<Factor2d>> ops::Div<S> for Size {
224 type Output = Self;
225
226 fn div(mut self, rhs: S) -> Self {
227 self /= rhs;
228 self
229 }
230}
231impl<S: Into<Factor2d>> ops::Div<S> for &Size {
232 type Output = Size;
233
234 fn div(self, rhs: S) -> Self::Output {
235 self.clone() / rhs
236 }
237}
238impl<S: Into<Factor2d>> ops::DivAssign<S> for Size {
239 fn div_assign(&mut self, rhs: S) {
240 let rhs = rhs.into();
241 self.width /= rhs.x;
242 self.height /= rhs.y;
243 }
244}