1 //! Taffy uses two coordinate systems to refer to grid lines (the gaps/gutters between rows/columns): 2 use super::super::types::TrackCounts; 3 use crate::geometry::Line; 4 use core::cmp::{max, Ordering}; 5 use 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)] 18 pub struct GridLine(i16); 19 20 impl From<i16> for GridLine { from(value: i16) -> Self21 fn from(value: i16) -> Self { 22 Self(value) 23 } 24 } 25 26 impl GridLine { 27 /// Returns the underlying i16 as_i16(self) -> i1628 pub fn as_i16(self) -> i16 { 29 self.0 30 } 31 32 /// Convert into OriginZero coordinates using the specified explicit track count into_origin_zero_line(self, explicit_track_count: u16) -> OriginZeroLine33 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)] 52 pub struct OriginZeroLine(pub i16); 53 54 // Add and Sub with Self 55 impl Add<OriginZeroLine> for OriginZeroLine { 56 type Output = Self; add(self, rhs: OriginZeroLine) -> Self::Output57 fn add(self, rhs: OriginZeroLine) -> Self::Output { 58 OriginZeroLine(self.0 + rhs.0) 59 } 60 } 61 impl Sub<OriginZeroLine> for OriginZeroLine { 62 type Output = Self; sub(self, rhs: OriginZeroLine) -> Self::Output63 fn sub(self, rhs: OriginZeroLine) -> Self::Output { 64 OriginZeroLine(self.0 - rhs.0) 65 } 66 } 67 68 // Add and Sub with u16 69 impl Add<u16> for OriginZeroLine { 70 type Output = Self; add(self, rhs: u16) -> Self::Output71 fn add(self, rhs: u16) -> Self::Output { 72 OriginZeroLine(self.0 + rhs as i16) 73 } 74 } 75 impl AddAssign<u16> for OriginZeroLine { add_assign(&mut self, rhs: u16)76 fn add_assign(&mut self, rhs: u16) { 77 self.0 += rhs as i16; 78 } 79 } 80 impl Sub<u16> for OriginZeroLine { 81 type Output = Self; sub(self, rhs: u16) -> Self::Output82 fn sub(self, rhs: u16) -> Self::Output { 83 OriginZeroLine(self.0 - rhs as i16) 84 } 85 } 86 87 impl OriginZeroLine { 88 /// Converts a grid line in OriginZero coordinates into the index of that same grid line in the GridTrackVec. into_track_vec_index(self, track_counts: TrackCounts) -> usize89 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. implied_negative_implicit_tracks(self) -> u16102 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. implied_positive_implicit_tracks(self, explicit_track_count: u16) -> u16111 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 120 impl Line<OriginZeroLine> { 121 /// The number of tracks between the start and end lines span(self) -> u16122 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. 128 pub trait GridCoordinate: Copy {} 129 impl GridCoordinate for GridLine {} 130 impl GridCoordinate for OriginZeroLine {} 131