zng_layout/unit/
side_offsets.rs

1use std::{fmt, ops};
2
3use zng_unit::DipSideOffsets;
4use zng_var::{animation::Transitionable, impl_from_and_into_var};
5
6use super::{Factor, FactorPercent, FactorSideOffsets, Layout1d, LayoutMask, Length, PxSideOffsets, impl_length_comp_conversions};
7
8/// 2D size offsets in [`Length`] units.
9///
10/// This unit defines spacing around all four sides of a box, a widget margin can be defined using a value of this type.
11#[derive(Clone, Default, PartialEq, serde::Serialize, serde::Deserialize, Transitionable)]
12pub struct SideOffsets {
13    /// Spacing above, in length units.
14    pub top: Length,
15    /// Spacing to the right, in length units.
16    pub right: Length,
17    /// Spacing bellow, in length units.
18    pub bottom: Length,
19    /// Spacing to the left ,in length units.
20    pub left: Length,
21}
22impl fmt::Debug for SideOffsets {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        if f.alternate() {
25            f.debug_struct("SideOffsets")
26                .field("top", &self.top)
27                .field("right", &self.right)
28                .field("bottom", &self.bottom)
29                .field("left", &self.left)
30                .finish()
31        } else if self.all_eq() {
32            write!(f, "{:?}", self.top)
33        } else if self.dimensions_eq() {
34            write!(f, "({:?}, {:?})", self.top, self.left)
35        } else {
36            write!(f, "({:?}, {:?}, {:?}, {:?})", self.top, self.right, self.bottom, self.left)
37        }
38    }
39}
40impl SideOffsets {
41    /// New top, right, bottom left offsets. From any [`Length`] type.
42    pub fn new<T: Into<Length>, R: Into<Length>, B: Into<Length>, L: Into<Length>>(top: T, right: R, bottom: B, left: L) -> Self {
43        SideOffsets {
44            top: top.into(),
45            right: right.into(),
46            bottom: bottom.into(),
47            left: left.into(),
48        }
49    }
50
51    /// Top-bottom and left-right equal. From any [`Length`] type.
52    pub fn new_vh<TB: Into<Length>, LR: Into<Length>>(top_bottom: TB, left_right: LR) -> Self {
53        let top_bottom = top_bottom.into();
54        let left_right = left_right.into();
55        SideOffsets {
56            top: top_bottom.clone(),
57            bottom: top_bottom,
58            left: left_right.clone(),
59            right: left_right,
60        }
61    }
62
63    /// All sides equal. From any [`Length`] type.
64    pub fn new_all<T: Into<Length>>(all_sides: T) -> Self {
65        let all_sides = all_sides.into();
66        SideOffsets {
67            top: all_sides.clone(),
68            right: all_sides.clone(),
69            bottom: all_sides.clone(),
70            left: all_sides,
71        }
72    }
73
74    /// All sides [zero](Length::zero).
75    pub fn zero() -> Self {
76        Self::new_all(Length::zero())
77    }
78
79    /// If all sides are equal.
80    pub fn all_eq(&self) -> bool {
81        self.top == self.bottom && self.top == self.left && self.top == self.right
82    }
83
84    /// If top and bottom are equal; and left and right are equal.
85    pub fn dimensions_eq(&self) -> bool {
86        self.top == self.bottom && self.left == self.right
87    }
88}
89impl super::Layout2d for SideOffsets {
90    type Px = PxSideOffsets;
91
92    fn layout_dft(&self, default: Self::Px) -> Self::Px {
93        PxSideOffsets::new(
94            self.top.layout_dft_y(default.top),
95            self.right.layout_dft_x(default.right),
96            self.bottom.layout_dft_y(default.bottom),
97            self.left.layout_dft_x(default.left),
98        )
99    }
100
101    fn affect_mask(&self) -> LayoutMask {
102        self.top.affect_mask() | self.right.affect_mask() | self.bottom.affect_mask() | self.left.affect_mask()
103    }
104}
105impl_from_and_into_var! {
106    /// All sides equal.
107    fn from(all: Length) -> SideOffsets {
108        SideOffsets::new_all(all)
109    }
110
111    /// All sides equal relative length.
112    fn from(percent: FactorPercent) -> SideOffsets {
113        SideOffsets::new_all(percent)
114    }
115    /// All sides equal relative length.
116    fn from(norm: Factor) -> SideOffsets {
117        SideOffsets::new_all(norm)
118    }
119
120    /// All sides equal exact length.
121    fn from(f: f32) -> SideOffsets {
122        SideOffsets::new_all(f)
123    }
124    /// All sides equal exact length.
125    fn from(i: i32) -> SideOffsets {
126        SideOffsets::new_all(i)
127    }
128
129    /// From exact lengths.
130    fn from(offsets: PxSideOffsets) -> SideOffsets {
131        SideOffsets::new(offsets.top, offsets.right, offsets.bottom, offsets.left)
132    }
133
134    // From exact lengths.
135    fn from(offsets: DipSideOffsets) -> SideOffsets {
136        SideOffsets::new(offsets.top, offsets.right, offsets.bottom, offsets.left)
137    }
138}
139
140impl_length_comp_conversions! {
141    /// (top-bottom, left-right)
142    fn from(top_bottom: TB, left_right: LR) -> SideOffsets {
143        SideOffsets::new_vh(top_bottom, left_right)
144    }
145
146    /// (top, right, bottom, left)
147    fn from(top: T, right: R, bottom: B, left: L) -> SideOffsets {
148        SideOffsets::new(top, right, bottom, left)
149    }
150}
151
152impl ops::Add for SideOffsets {
153    type Output = Self;
154
155    fn add(mut self, rhs: Self) -> Self {
156        self += rhs;
157        self
158    }
159}
160impl ops::AddAssign for SideOffsets {
161    fn add_assign(&mut self, rhs: Self) {
162        self.top += rhs.top;
163        self.right += rhs.right;
164        self.bottom += rhs.bottom;
165        self.left += rhs.left;
166    }
167}
168impl ops::Sub for SideOffsets {
169    type Output = Self;
170
171    fn sub(mut self, rhs: Self) -> Self {
172        self -= rhs;
173        self
174    }
175}
176impl ops::SubAssign for SideOffsets {
177    fn sub_assign(&mut self, rhs: Self) {
178        self.top -= rhs.top;
179        self.right -= rhs.right;
180        self.bottom -= rhs.bottom;
181        self.left -= rhs.left;
182    }
183}
184impl<S: Into<FactorSideOffsets>> ops::Mul<S> for SideOffsets {
185    type Output = Self;
186
187    fn mul(mut self, rhs: S) -> Self {
188        self *= rhs;
189        self
190    }
191}
192impl<S: Into<FactorSideOffsets>> ops::Mul<S> for &SideOffsets {
193    type Output = SideOffsets;
194
195    fn mul(self, rhs: S) -> Self::Output {
196        self.clone() * rhs
197    }
198}
199impl<S: Into<FactorSideOffsets>> ops::MulAssign<S> for SideOffsets {
200    fn mul_assign(&mut self, rhs: S) {
201        let rhs = rhs.into();
202        self.top *= rhs.top;
203        self.right *= rhs.right;
204        self.bottom *= rhs.bottom;
205        self.left *= rhs.left;
206    }
207}
208impl<S: Into<FactorSideOffsets>> ops::Div<S> for SideOffsets {
209    type Output = Self;
210
211    fn div(mut self, rhs: S) -> Self {
212        self /= rhs;
213        self
214    }
215}
216impl<S: Into<FactorSideOffsets>> ops::Div<S> for &SideOffsets {
217    type Output = SideOffsets;
218
219    fn div(self, rhs: S) -> Self::Output {
220        self.clone() / rhs
221    }
222}
223impl<S: Into<FactorSideOffsets>> ops::DivAssign<S> for SideOffsets {
224    fn div_assign(&mut self, rhs: S) {
225        let rhs = rhs.into();
226        self.top /= rhs.top;
227        self.right /= rhs.right;
228        self.bottom /= rhs.bottom;
229        self.left /= rhs.left;
230    }
231}