1use std::{fmt, ops};
2
3use zng_var::{animation::Transitionable, impl_from_and_into_var};
4
5use super::{Factor2d, LayoutMask, Length, Point, Px, PxPoint, PxRect};
6
7#[derive(Clone, Default, PartialEq, serde::Serialize, serde::Deserialize, Transitionable)]
9pub struct Line {
10 pub start: Point,
12 pub end: Point,
14}
15impl fmt::Debug for Line {
16 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17 if f.alternate() {
18 f.debug_struct("Line").field("start", &self.start).field("end", &self.end).finish()
19 } else {
20 write!(f, "{:?}.to{:?}", self.start, self.end)
21 }
22 }
23}
24impl fmt::Display for Line {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 if let Some(p) = f.precision() {
27 write!(f, "{:.p$} to {:.p$}", self.start, self.end, p = p)
28 } else {
29 write!(f, "{} to {}", self.start, self.end)
30 }
31 }
32}
33impl Line {
34 pub fn new<S: Into<Point>, E: Into<Point>>(start: S, end: E) -> Self {
38 Line {
39 start: start.into(),
40 end: end.into(),
41 }
42 }
43
44 pub fn zero() -> Line {
46 Line {
47 start: Point::zero(),
48 end: Point::zero(),
49 }
50 }
51
52 pub fn to_top() -> Line {
54 Line {
55 start: Point::bottom(),
56 end: Point::top(),
57 }
58 }
59
60 pub fn to_bottom() -> Line {
62 Line {
63 start: Point::top(),
64 end: Point::bottom(),
65 }
66 }
67
68 pub fn to_right() -> Line {
70 Line {
71 start: Point::left(),
72 end: Point::right(),
73 }
74 }
75
76 pub fn to_left() -> Line {
78 Line {
79 start: Point::right(),
80 end: Point::left(),
81 }
82 }
83
84 pub fn to_top_left() -> Line {
86 Line {
87 start: Point::bottom_right(),
88 end: Point::top_left(),
89 }
90 }
91
92 pub fn to_top_right() -> Line {
94 Line {
95 start: Point::bottom_left(),
96 end: Point::top_right(),
97 }
98 }
99
100 pub fn to_bottom_left() -> Line {
102 Line {
103 start: Point::top_right(),
104 end: Point::bottom_left(),
105 }
106 }
107
108 pub fn to_bottom_right() -> Line {
110 Line {
111 start: Point::top_left(),
112 end: Point::bottom_right(),
113 }
114 }
115}
116impl super::Layout2d for Line {
117 type Px = PxLine;
118
119 fn layout_dft(&self, default: Self::Px) -> Self::Px {
120 PxLine {
121 start: self.start.layout_dft(default.start),
122 end: self.end.layout_dft(default.end),
123 }
124 }
125
126 fn affect_mask(&self) -> LayoutMask {
127 self.start.affect_mask() | self.end.affect_mask()
128 }
129}
130impl_from_and_into_var! {
131 fn from(line: PxLine) -> Line {
133 Line::new(line.start, line.end)
134 }
135}
136
137#[derive(Clone, Default, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
139pub struct PxLine {
140 pub start: PxPoint,
142 pub end: PxPoint,
144}
145impl PxLine {
146 pub fn new(start: PxPoint, end: PxPoint) -> Self {
148 Self { start, end }
149 }
150
151 pub fn zero() -> Self {
153 Self::new(PxPoint::zero(), PxPoint::zero())
154 }
155
156 pub fn length(self) -> Px {
158 let s = self.start.cast::<f32>();
159 let e = self.end.cast::<f32>();
160 Px(s.distance_to(e).round() as i32)
161 }
162
163 pub fn bounds(self) -> PxRect {
165 PxRect::from_points([self.start, self.end])
166 }
167
168 pub fn normalize(self) -> PxLine {
170 let start = self.start.min(self.end);
171 let end = self.start.max(self.end);
172 PxLine { start, end }
173 }
174}
175
176pub trait LineFromTuplesBuilder {
186 fn to<X2: Into<Length>, Y2: Into<Length>>(self, x2: X2, y2: Y2) -> Line;
188}
189impl<X1: Into<Length>, Y1: Into<Length>> LineFromTuplesBuilder for (X1, Y1) {
190 fn to<X2: Into<Length>, Y2: Into<Length>>(self, x2: X2, y2: Y2) -> Line {
191 Line::new(self, (x2, y2))
192 }
193}
194
195impl<S: Into<Factor2d>> ops::Mul<S> for Line {
196 type Output = Self;
197
198 fn mul(mut self, rhs: S) -> Self {
199 self *= rhs;
200 self
201 }
202}
203impl<S: Into<Factor2d>> ops::Mul<S> for &Line {
204 type Output = Line;
205
206 fn mul(self, rhs: S) -> Self::Output {
207 self.clone() * rhs
208 }
209}
210impl<S: Into<Factor2d>> ops::MulAssign<S> for Line {
211 fn mul_assign(&mut self, rhs: S) {
212 let rhs = rhs.into();
213 self.start *= rhs;
214 self.end *= rhs;
215 }
216}
217impl<S: Into<Factor2d>> ops::Div<S> for Line {
218 type Output = Self;
219
220 fn div(mut self, rhs: S) -> Self {
221 self /= rhs;
222 self
223 }
224}
225impl<S: Into<Factor2d>> ops::Div<S> for &Line {
226 type Output = Line;
227
228 fn div(self, rhs: S) -> Self::Output {
229 self.clone() / rhs
230 }
231}
232impl<S: Into<Factor2d>> ops::DivAssign<S> for Line {
233 fn div_assign(&mut self, rhs: S) {
234 let rhs = rhs.into();
235 self.start /= rhs;
236 self.end /= rhs;
237 }
238}
239
240impl ops::Add for Line {
241 type Output = Self;
242
243 fn add(mut self, rhs: Self) -> Self {
244 self += rhs;
245 self
246 }
247}
248impl ops::AddAssign for Line {
249 fn add_assign(&mut self, rhs: Self) {
250 self.start += rhs.start;
251 self.end += rhs.end;
252 }
253}
254impl ops::Sub for Line {
255 type Output = Self;
256
257 fn sub(mut self, rhs: Self) -> Self {
258 self -= rhs;
259 self
260 }
261}
262impl ops::SubAssign for Line {
263 fn sub_assign(&mut self, rhs: Self) {
264 self.start -= rhs.start;
265 self.end -= rhs.end;
266 }
267}