taffy/compute/grid/types/
coordinates.rs

1//! Taffy uses two coordinate systems to refer to grid lines (the gaps/gutters between rows/columns):
2use super::super::types::TrackCounts;
3use crate::geometry::Line;
4use core::cmp::{max, Ordering};
5use core::ops::{Add, AddAssign, Sub};
6
7/// Represents a grid line position in "CSS Grid Line" coordinates
8///
9/// "CSS Grid Line" coordinates are those used in grid-row/grid-column in the CSS grid spec:
10///   - The line at left hand (or top) edge of the explicit grid is line 1
11///     (and counts up from there)
12///   - The line at the right hand (or bottom) edge of the explicit grid is -1
13///     (and counts down from there)
14///   - 0 is not a valid index
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17#[repr(transparent)]
18pub struct GridLine(i16);
19
20impl From<i16> for GridLine {
21    fn from(value: i16) -> Self {
22        Self(value)
23    }
24}
25
26impl GridLine {
27    /// Returns the underlying i16
28    pub fn as_i16(self) -> i16 {
29        self.0
30    }
31
32    /// Convert into OriginZero coordinates using the specified explicit track count
33    pub(crate) fn into_origin_zero_line(self, explicit_track_count: u16) -> OriginZeroLine {
34        let explicit_line_count = explicit_track_count + 1;
35        let oz_line = match self.0.cmp(&0) {
36            Ordering::Greater => self.0 - 1,
37            Ordering::Less => self.0 + explicit_line_count as i16,
38            Ordering::Equal => panic!("Grid line of zero is invalid"),
39        };
40        OriginZeroLine(oz_line)
41    }
42}
43
44/// Represents a grid line position in "OriginZero" coordinates
45///
46/// "OriginZero" coordinates are a normalized form:
47///   - The line at left hand (or top) edge of the explicit grid is line 0
48///   - The next line to the right (or down) is 1, and so on
49///   - The next line to the left (or up) is -1, and so on
50#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
51#[repr(transparent)]
52pub struct OriginZeroLine(pub i16);
53
54// Add and Sub with Self
55impl Add<OriginZeroLine> for OriginZeroLine {
56    type Output = Self;
57    fn add(self, rhs: OriginZeroLine) -> Self::Output {
58        OriginZeroLine(self.0 + rhs.0)
59    }
60}
61impl Sub<OriginZeroLine> for OriginZeroLine {
62    type Output = Self;
63    fn sub(self, rhs: OriginZeroLine) -> Self::Output {
64        OriginZeroLine(self.0 - rhs.0)
65    }
66}
67
68// Add and Sub with u16
69impl Add<u16> for OriginZeroLine {
70    type Output = Self;
71    fn add(self, rhs: u16) -> Self::Output {
72        OriginZeroLine(self.0 + rhs as i16)
73    }
74}
75impl AddAssign<u16> for OriginZeroLine {
76    fn add_assign(&mut self, rhs: u16) {
77        self.0 += rhs as i16;
78    }
79}
80impl Sub<u16> for OriginZeroLine {
81    type Output = Self;
82    fn sub(self, rhs: u16) -> Self::Output {
83        OriginZeroLine(self.0 - rhs as i16)
84    }
85}
86
87impl OriginZeroLine {
88    /// Converts a grid line in OriginZero coordinates into the index of that same grid line in the GridTrackVec.
89    pub(crate) fn into_track_vec_index(self, track_counts: TrackCounts) -> usize {
90        assert!(
91            self.0 >= -(track_counts.negative_implicit as i16),
92            "OriginZero grid line cannot be less than the number of negative grid lines"
93        );
94        assert!(
95            self.0 <= (track_counts.explicit + track_counts.positive_implicit) as i16,
96            "OriginZero grid line cannot be more than the number of positive grid lines"
97        );
98        2 * ((self.0 + track_counts.negative_implicit as i16) as usize)
99    }
100
101    /// The minimum number of negative implicit track there must be if a grid item starts at this line.
102    pub(crate) fn implied_negative_implicit_tracks(self) -> u16 {
103        if self.0 < 0 {
104            self.0.unsigned_abs()
105        } else {
106            0
107        }
108    }
109
110    /// The minimum number of positive implicit track there must be if a grid item end at this line.
111    pub(crate) fn implied_positive_implicit_tracks(self, explicit_track_count: u16) -> u16 {
112        if self.0 > explicit_track_count as i16 {
113            self.0 as u16 - explicit_track_count
114        } else {
115            0
116        }
117    }
118}
119
120impl Line<OriginZeroLine> {
121    /// The number of tracks between the start and end lines
122    pub(crate) fn span(self) -> u16 {
123        max(self.end.0 - self.start.0, 0) as u16
124    }
125}
126
127/// A trait for the different coordinates used to define grid lines.
128pub trait GridCoordinate: Copy {}
129impl GridCoordinate for GridLine {}
130impl GridCoordinate for OriginZeroLine {}