zng_layout/unit/
size.rs

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/// 2D size in [`Length`] units.
10#[derive(Clone, Default, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, Transitionable)]
11pub struct Size {
12    /// *width* in length units.
13    pub width: Length,
14    /// *height* in length units.
15    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    /// New width, height from any [`Length`] unit.
53    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    /// New width, height from single value of any [`Length`] unit.
61    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    /// ***width:*** [`Length::zero`], ***height:*** [`Length::zero`]
70    pub fn zero() -> Self {
71        Self::new(Length::zero(), Length::zero())
72    }
73
74    /// Size that fills the available space.
75    ///
76    /// ***width:*** [`Length::fill`], ***height:*** [`Length::fill`]
77    pub fn fill() -> Self {
78        Self::new(Length::fill(), Length::fill())
79    }
80
81    /// Returns `(width, height)`.
82    pub fn as_tuple(self) -> (Length, Length) {
83        (self.width, self.height)
84    }
85
86    /// Returns `[width, height]`.
87    pub fn as_array(self) -> [Length; 2] {
88        [self.width, self.height]
89    }
90
91    /// Returns `true` if all values are [`Length::Default`].
92    pub fn is_default(&self) -> bool {
93        self.width.is_default() && self.height.is_default()
94    }
95
96    /// Returns `true` if any value is [`Length::Default`].
97    pub fn has_default(&self) -> bool {
98        self.width.has_default() || self.height.has_default()
99    }
100
101    /// Replaces [`Length::Default`] values with `overwrite` values.
102    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    /// Returns a vector of x: width and y: height.
108    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    /// Splat.
133    fn from(all: Length) -> Size {
134        Size::splat(all)
135    }
136
137    /// Splat relative length.
138    fn from(percent: FactorPercent) -> Size {
139        Size::splat(percent)
140    }
141    /// Splat relative length.
142    fn from(norm: Factor) -> Size {
143        Size::splat(norm)
144    }
145
146    /// Splat exact length.
147    fn from(f: f32) -> Size {
148        Size::splat(f)
149    }
150    /// Splat exact length.
151    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}