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, "({:.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    /// New width, height from any [`Length`] unit.
49    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    /// New width, height from single value of any [`Length`] unit.
57    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    /// ***width:*** [`Length::zero`], ***height:*** [`Length::zero`]
66    pub fn zero() -> Self {
67        Self::new(Length::zero(), Length::zero())
68    }
69
70    /// Size that fills the available space.
71    ///
72    /// ***width:*** [`Length::fill`], ***height:*** [`Length::fill`]
73    pub fn fill() -> Self {
74        Self::new(Length::fill(), Length::fill())
75    }
76
77    /// Returns `(width, height)`.
78    pub fn as_tuple(self) -> (Length, Length) {
79        (self.width, self.height)
80    }
81
82    /// Returns `[width, height]`.
83    pub fn as_array(self) -> [Length; 2] {
84        [self.width, self.height]
85    }
86
87    /// Returns `true` if all values are [`Length::Default`].
88    pub fn is_default(&self) -> bool {
89        self.width.is_default() && self.height.is_default()
90    }
91
92    /// Returns `true` if any value is [`Length::Default`].
93    pub fn has_default(&self) -> bool {
94        self.width.has_default() || self.height.has_default()
95    }
96
97    /// Replaces [`Length::Default`] values with `overwrite` values.
98    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    /// Returns a vector of x: width and y: height.
104    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    /// Splat.
129    fn from(all: Length) -> Size {
130        Size::splat(all)
131    }
132
133    /// Splat relative length.
134    fn from(percent: FactorPercent) -> Size {
135        Size::splat(percent)
136    }
137    /// Splat relative length.
138    fn from(norm: Factor) -> Size {
139        Size::splat(norm)
140    }
141
142    /// Splat exact length.
143    fn from(f: f32) -> Size {
144        Size::splat(f)
145    }
146    /// Splat exact length.
147    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}