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#[derive(Clone, Default, PartialEq, serde::Serialize, serde::Deserialize, Transitionable)]
12pub struct SideOffsets {
13 pub top: Length,
15 pub right: Length,
17 pub bottom: Length,
19 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 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 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 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 pub fn zero() -> Self {
76 Self::new_all(Length::zero())
77 }
78
79 pub fn all_eq(&self) -> bool {
81 self.top == self.bottom && self.top == self.left && self.top == self.right
82 }
83
84 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 fn from(all: Length) -> SideOffsets {
108 SideOffsets::new_all(all)
109 }
110
111 fn from(percent: FactorPercent) -> SideOffsets {
113 SideOffsets::new_all(percent)
114 }
115 fn from(norm: Factor) -> SideOffsets {
117 SideOffsets::new_all(norm)
118 }
119
120 fn from(f: f32) -> SideOffsets {
122 SideOffsets::new_all(f)
123 }
124 fn from(i: i32) -> SideOffsets {
126 SideOffsets::new_all(i)
127 }
128
129 fn from(offsets: PxSideOffsets) -> SideOffsets {
131 SideOffsets::new(offsets.top, offsets.right, offsets.bottom, offsets.left)
132 }
133
134 fn from(offsets: DipSideOffsets) -> SideOffsets {
136 SideOffsets::new(offsets.top, offsets.right, offsets.bottom, offsets.left)
137 }
138}
139
140impl_length_comp_conversions! {
141 fn from(top_bottom: TB, left_right: LR) -> SideOffsets {
143 SideOffsets::new_vh(top_bottom, left_right)
144 }
145
146 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}