1use std::{fmt, mem, ops};
2
3use zng_var::{animation::Transitionable, impl_from_and_into_var};
4
5use crate::unit::{LengthCompositeParser, ParseCompositeError};
6
7use super::{Factor, Factor2d, FactorPercent, Layout1d, LayoutMask, Length, Px, PxVector, impl_length_comp_conversions};
8
9#[derive(Clone, Default, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, Transitionable)]
11pub struct GridSpacing {
12 pub column: Length,
14 pub row: Length,
16}
17impl GridSpacing {
18 pub fn new<C: Into<Length>, R: Into<Length>>(column: C, row: R) -> Self {
20 GridSpacing {
21 column: column.into(),
22 row: row.into(),
23 }
24 }
25
26 pub fn new_all<S: Into<Length>>(same: S) -> Self {
28 let same = same.into();
29 GridSpacing {
30 column: same.clone(),
31 row: same,
32 }
33 }
34}
35impl super::Layout2d for GridSpacing {
36 type Px = PxGridSpacing;
37
38 fn layout_dft(&self, default: Self::Px) -> Self::Px {
39 PxGridSpacing {
40 column: self.column.layout_dft_x(default.column),
41 row: self.row.layout_dft_y(default.row),
42 }
43 }
44
45 fn affect_mask(&self) -> LayoutMask {
46 self.column.affect_mask() | self.row.affect_mask()
47 }
48}
49impl_length_comp_conversions! {
50 fn from(column: C, row: R) -> GridSpacing {
51 GridSpacing::new(column, row)
52 }
53}
54impl_from_and_into_var! {
55 fn from(all: Length) -> GridSpacing {
57 GridSpacing::new_all(all)
58 }
59
60 fn from(percent: FactorPercent) -> GridSpacing {
62 GridSpacing::new_all(percent)
63 }
64 fn from(norm: Factor) -> GridSpacing {
66 GridSpacing::new_all(norm)
67 }
68
69 fn from(f: f32) -> GridSpacing {
71 GridSpacing::new_all(f)
72 }
73 fn from(i: i32) -> GridSpacing {
75 GridSpacing::new_all(i)
76 }
77
78 fn from(spacing: PxGridSpacing) -> GridSpacing {
80 GridSpacing::new(spacing.column, spacing.row)
81 }
82}
83impl fmt::Debug for GridSpacing {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 if f.alternate() {
86 f.debug_struct("GridSpacing")
87 .field("column", &self.column)
88 .field("row", &self.row)
89 .finish()
90 } else if self.column == self.row {
91 write!(f, "{:.p$?}", self.column, p = f.precision().unwrap_or(0))
92 } else {
93 write!(f, "({:.p$?}, {:.p$?})", self.column, self.row, p = f.precision().unwrap_or(0))
94 }
95 }
96}
97impl fmt::Display for GridSpacing {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 if self.column == self.row {
100 write!(f, "{:.p$}", self.column, p = f.precision().unwrap_or(0))
101 } else {
102 write!(f, "({:.p$}, {:.p$})", self.column, self.row, p = f.precision().unwrap_or(0))
103 }
104 }
105}
106impl std::str::FromStr for GridSpacing {
107 type Err = ParseCompositeError;
108
109 fn from_str(s: &str) -> Result<Self, Self::Err> {
110 let mut parser = LengthCompositeParser::new(s)?;
111 let a = parser.next()?;
112 if parser.has_ended() {
113 return Ok(Self::new_all(a));
114 }
115 let b = parser.expect_last()?;
116 Ok(Self::new(a, b))
117 }
118}
119impl<S: Into<Factor2d>> ops::Mul<S> for GridSpacing {
120 type Output = Self;
121
122 fn mul(self, rhs: S) -> Self {
123 let fct = rhs.into();
124
125 GridSpacing {
126 column: self.column * fct.x,
127 row: self.row * fct.y,
128 }
129 }
130}
131impl<S: Into<Factor2d>> ops::Mul<S> for &GridSpacing {
132 type Output = GridSpacing;
133
134 fn mul(self, rhs: S) -> Self::Output {
135 self.clone() * rhs
136 }
137}
138impl<S: Into<Factor2d>> ops::MulAssign<S> for GridSpacing {
139 fn mul_assign(&mut self, rhs: S) {
140 let column = mem::take(&mut self.column);
141 let row = mem::take(&mut self.row);
142 let fct = rhs.into();
143
144 self.column = column * fct.x;
145 self.row = row * fct.y;
146 }
147}
148impl<S: Into<Factor2d>> ops::Div<S> for GridSpacing {
149 type Output = Self;
150
151 fn div(self, rhs: S) -> Self {
152 let fct = rhs.into();
153
154 GridSpacing {
155 column: self.column / fct.x,
156 row: self.row / fct.y,
157 }
158 }
159}
160impl<S: Into<Factor2d>> ops::Div<S> for &GridSpacing {
161 type Output = GridSpacing;
162
163 fn div(self, rhs: S) -> Self::Output {
164 self.clone() / rhs
165 }
166}
167impl<S: Into<Factor2d>> ops::DivAssign<S> for GridSpacing {
168 fn div_assign(&mut self, rhs: S) {
169 let column = mem::take(&mut self.column);
170 let row = mem::take(&mut self.row);
171 let fct = rhs.into();
172
173 self.column = column / fct.x;
174 self.row = row / fct.y;
175 }
176}
177
178#[derive(Clone, Default, Copy, Debug, PartialEq, Eq, Hash)]
180pub struct PxGridSpacing {
181 pub column: Px,
183 pub row: Px,
185}
186impl PxGridSpacing {
187 pub fn new(column: Px, row: Px) -> Self {
189 Self { column, row }
190 }
191 pub fn zero() -> Self {
193 PxGridSpacing { column: Px(0), row: Px(0) }
194 }
195
196 pub fn to_vector(self) -> PxVector {
198 PxVector::new(self.column, self.row)
199 }
200}
201impl ops::Add for GridSpacing {
202 type Output = Self;
203
204 fn add(mut self, rhs: Self) -> Self {
205 self += rhs;
206 self
207 }
208}
209impl ops::AddAssign for GridSpacing {
210 fn add_assign(&mut self, rhs: Self) {
211 self.column += rhs.column;
212 self.row += rhs.row;
213 }
214}
215impl ops::Sub for GridSpacing {
216 type Output = Self;
217
218 fn sub(mut self, rhs: Self) -> Self {
219 self -= rhs;
220 self
221 }
222}
223impl ops::SubAssign for GridSpacing {
224 fn sub_assign(&mut self, rhs: Self) {
225 self.column -= rhs.column;
226 self.row -= rhs.row;
227 }
228}
229impl From<PxGridSpacing> for PxVector {
230 fn from(s: PxGridSpacing) -> Self {
231 s.to_vector()
232 }
233}
234impl From<PxVector> for PxGridSpacing {
235 fn from(s: PxVector) -> Self {
236 PxGridSpacing { column: s.x, row: s.y }
237 }
238}