zng_layout/unit/
point.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::{DipPoint, Factor, Factor2d, FactorPercent, Layout1d, LayoutMask, Length, PxPoint, Size, Vector, impl_length_comp_conversions};
8
9/// 2D point in [`Length`] units.
10#[derive(Clone, Default, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, Transitionable)]
11pub struct Point {
12    /// *x* offset in length units.
13    pub x: Length,
14    /// *y* offset in length units.
15    pub y: Length,
16}
17impl fmt::Debug for Point {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        if f.alternate() {
20            f.debug_struct("Point").field("x", &self.x).field("y", &self.y).finish()
21        } else {
22            write!(f, "({:.p$?}, {:.p$?})", self.x, self.y, p = f.precision().unwrap_or(0))
23        }
24    }
25}
26impl fmt::Display for Point {
27    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28        write!(f, "({:.p$}, {:.p$}", self.x, self.y, p = f.precision().unwrap_or(0))
29    }
30}
31impl std::str::FromStr for Point {
32    type Err = ParseCompositeError;
33
34    fn from_str(s: &str) -> Result<Self, Self::Err> {
35        let mut parser = LengthCompositeParser::new(s)?;
36        let a = parser.next()?;
37        if parser.has_ended() {
38            return Ok(Self::splat(a));
39        }
40        let b = parser.expect_last()?;
41        Ok(Self::new(a, b))
42    }
43}
44impl Point {
45    /// New x, y from any [`Length`] unit.
46    pub fn new<X: Into<Length>, Y: Into<Length>>(x: X, y: Y) -> Self {
47        Point { x: x.into(), y: y.into() }
48    }
49
50    /// New x, y from single value of any [`Length`] unit.
51    pub fn splat(xy: impl Into<Length>) -> Self {
52        let xy = xy.into();
53        Point { x: xy.clone(), y: xy }
54    }
55
56    /// ***x:*** [`Length::zero`], ***y:*** [`Length::zero`].
57    pub fn zero() -> Self {
58        Self::new(Length::zero(), Length::zero())
59    }
60
61    /// Point at the top-middle of the available space.
62    ///
63    /// ***x:*** [`Length::half`], ***y:*** [`Length::zero`]
64    pub fn top() -> Self {
65        Self::new(Length::half(), Length::zero())
66    }
67
68    /// Point at the bottom-middle of the available space.
69    ///
70    /// ***x:*** [`Length::half`], ***y:*** [`Length::fill`]
71    pub fn bottom() -> Self {
72        Self::new(Length::half(), Length::fill())
73    }
74
75    /// Point at the middle-left of the available space.
76    ///
77    /// ***x:*** [`Length::zero`], ***y:*** [`Length::half`]
78    pub fn left() -> Self {
79        Self::new(Length::zero(), Length::half())
80    }
81
82    /// Point at the middle-right of the available space.
83    ///
84    /// ***x:*** [`Length::fill`], ***y:*** [`Length::half`]
85    pub fn right() -> Self {
86        Self::new(Length::fill(), Length::half())
87    }
88
89    /// Point at the top-left of the available space.
90    ///
91    /// ***x:*** [`Length::zero`], ***y:*** [`Length::zero`]
92    pub fn top_left() -> Self {
93        Self::zero()
94    }
95
96    /// Point at the top-right of the available space.
97    ///
98    /// ***x:*** [`Length::fill`], ***y:*** [`Length::zero`]
99    pub fn top_right() -> Self {
100        Self::new(Length::fill(), Length::zero())
101    }
102
103    /// Point at the bottom-left of the available space.
104    ///
105    /// ***x:*** [`Length::zero`], ***y:*** [`Length::fill`]
106    pub fn bottom_left() -> Self {
107        Self::new(Length::zero(), Length::fill())
108    }
109
110    /// Point at the bottom-right of the available space.
111    ///
112    /// ***x:*** [`Length::fill`], ***y:*** [`Length::fill`]
113    pub fn bottom_right() -> Self {
114        Self::new(Length::fill(), Length::fill())
115    }
116
117    /// Point at the center.
118    ///
119    /// ***x:*** [`Length::half`], ***y:*** [`Length::half`]
120    pub fn center() -> Self {
121        Self::new(Length::half(), Length::half())
122    }
123
124    /// Swap `x` and `y`.
125    pub fn yx(self) -> Self {
126        Point { y: self.x, x: self.y }
127    }
128
129    /// Returns `(x, y)`.
130    pub fn as_tuple(self) -> (Length, Length) {
131        (self.x, self.y)
132    }
133
134    /// Returns `[x, y]`.
135    pub fn as_array(self) -> [Length; 2] {
136        [self.x, self.y]
137    }
138
139    /// Returns `true` if all values are [`Length::Default`].
140    pub fn is_default(&self) -> bool {
141        self.x.is_default() && self.y.is_default()
142    }
143
144    /// Returns `true` if any value is [`Length::Default`].
145    pub fn has_default(&self) -> bool {
146        self.x.has_default() || self.y.has_default()
147    }
148
149    /// Replaces [`Length::Default`] values with `overwrite` values.
150    pub fn replace_default(&mut self, overwrite: &Point) {
151        self.x.replace_default(&overwrite.x);
152        self.y.replace_default(&overwrite.y);
153    }
154
155    /// Cast to [`Vector`].
156    pub fn as_vector(self) -> Vector {
157        Vector { x: self.x, y: self.y }
158    }
159}
160impl super::Layout2d for Point {
161    type Px = PxPoint;
162
163    fn layout_dft(&self, default: Self::Px) -> Self::Px {
164        PxPoint::new(self.x.layout_dft_x(default.x), self.y.layout_dft_y(default.y))
165    }
166
167    fn affect_mask(&self) -> LayoutMask {
168        self.x.affect_mask() | self.y.affect_mask()
169    }
170}
171impl_length_comp_conversions! {
172    fn from(x: X, y: Y) -> Point {
173        Point::new(x, y)
174    }
175}
176impl_from_and_into_var! {
177    /// Splat.
178    fn from(all: Length) -> Point {
179        Point::splat(all)
180    }
181    /// Splat relative length.
182    fn from(percent: FactorPercent) -> Point {
183        Point::splat(percent)
184    }
185    /// Splat relative length.
186    fn from(norm: Factor) -> Point {
187        Point::splat(norm)
188    }
189
190    /// Splat exact length.
191    fn from(f: f32) -> Point {
192        Point::splat(f)
193    }
194    /// Splat exact length.
195    fn from(i: i32) -> Point {
196        Point::splat(i)
197    }
198    fn from(p: PxPoint) -> Point {
199        Point::new(p.x, p.y)
200    }
201    fn from(p: DipPoint) -> Point {
202        Point::new(p.x, p.y)
203    }
204    fn from(v: Vector) -> Point {
205        v.as_point()
206    }
207}
208impl<V: Into<Vector>> ops::Add<V> for Point {
209    type Output = Self;
210
211    fn add(mut self, rhs: V) -> Self {
212        self += rhs;
213        self
214    }
215}
216impl<'a> ops::Add<&'a Vector> for &Point {
217    type Output = Point;
218
219    fn add(self, rhs: &'a Vector) -> Self::Output {
220        self.clone() + rhs.clone()
221    }
222}
223impl<'a> ops::Add<&'a Size> for &Point {
224    type Output = Point;
225
226    fn add(self, rhs: &'a Size) -> Self::Output {
227        self.clone() + rhs.clone()
228    }
229}
230impl<V: Into<Vector>> ops::AddAssign<V> for Point {
231    fn add_assign(&mut self, rhs: V) {
232        let rhs = rhs.into();
233        self.x += rhs.x;
234        self.y += rhs.y;
235    }
236}
237impl<'a> ops::AddAssign<&'a Vector> for Point {
238    fn add_assign(&mut self, rhs: &'a Vector) {
239        *self += rhs.clone();
240    }
241}
242impl<'a> ops::AddAssign<&'a Size> for Point {
243    fn add_assign(&mut self, rhs: &'a Size) {
244        *self += rhs.clone();
245    }
246}
247impl<V: Into<Vector>> ops::Sub<V> for Point {
248    type Output = Self;
249
250    fn sub(mut self, rhs: V) -> Self {
251        self -= rhs;
252        self
253    }
254}
255impl<'a> ops::Sub<&'a Vector> for &Point {
256    type Output = Point;
257
258    fn sub(self, rhs: &'a Vector) -> Self::Output {
259        self.clone() - rhs.clone()
260    }
261}
262impl<'a> ops::Sub<&'a Size> for &Point {
263    type Output = Point;
264
265    fn sub(self, rhs: &'a Size) -> Self::Output {
266        self.clone() - rhs.clone()
267    }
268}
269impl<V: Into<Vector>> ops::SubAssign<V> for Point {
270    fn sub_assign(&mut self, rhs: V) {
271        let rhs = rhs.into();
272        self.x -= rhs.x;
273        self.y -= rhs.y;
274    }
275}
276impl<'a> ops::SubAssign<&'a Vector> for Point {
277    fn sub_assign(&mut self, rhs: &'a Vector) {
278        *self -= rhs.clone();
279    }
280}
281impl<'a> ops::SubAssign<&'a Size> for Point {
282    fn sub_assign(&mut self, rhs: &'a Size) {
283        *self -= rhs.clone();
284    }
285}
286impl<S: Into<Factor2d>> ops::Mul<S> for Point {
287    type Output = Self;
288
289    fn mul(mut self, rhs: S) -> Self {
290        self *= rhs;
291        self
292    }
293}
294impl<S: Into<Factor2d>> ops::Mul<S> for &Point {
295    type Output = Point;
296
297    fn mul(self, rhs: S) -> Self::Output {
298        self.clone() * rhs
299    }
300}
301impl<S: Into<Factor2d>> ops::MulAssign<S> for Point {
302    fn mul_assign(&mut self, rhs: S) {
303        let rhs = rhs.into();
304        self.x *= rhs.x;
305        self.y *= rhs.y;
306    }
307}
308impl<S: Into<Factor2d>> ops::Div<S> for Point {
309    type Output = Self;
310
311    fn div(mut self, rhs: S) -> Self {
312        self /= rhs;
313        self
314    }
315}
316impl<S: Into<Factor2d>> ops::Div<S> for &Point {
317    type Output = Point;
318
319    fn div(self, rhs: S) -> Self::Output {
320        self.clone() / rhs
321    }
322}
323impl<S: Into<Factor2d>> ops::DivAssign<S> for Point {
324    fn div_assign(&mut self, rhs: S) {
325        let rhs = rhs.into();
326        self.x /= rhs.x;
327        self.y /= rhs.y;
328    }
329}
330impl ops::Neg for Point {
331    type Output = Self;
332
333    fn neg(self) -> Self {
334        Point { x: -self.x, y: -self.y }
335    }
336}
337
338impl ops::Neg for &Point {
339    type Output = Point;
340
341    fn neg(self) -> Self::Output {
342        -self.clone()
343    }
344}