1 //! Style types for representing lengths / sizes 2 3 use crate::geometry::{Rect, Size}; 4 use crate::style_helpers::{FromLength, FromPercent, TaffyAuto, TaffyMaxContent, TaffyMinContent, TaffyZero}; 5 use crate::util::sys::abs; 6 7 /// A unit of linear measurement 8 /// 9 /// This is commonly combined with [`Rect`], [`Point`](crate::geometry::Point) and [`Size<T>`]. 10 #[derive(Copy, Clone, PartialEq, Debug)] 11 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 12 pub enum LengthPercentage { 13 /// An absolute length in some abstract units. Users of Taffy may define what they correspond 14 /// to in their application (pixels, logical pixels, mm, etc) as they see fit. 15 Length(f32), 16 /// A percentage length relative to the size of the containing block. 17 /// 18 /// **NOTE: percentages are represented as a f32 value in the range [0.0, 1.0] NOT the range [0.0, 100.0]** 19 Percent(f32), 20 } 21 impl TaffyZero for LengthPercentage { 22 const ZERO: Self = Self::Length(0.0); 23 } 24 impl FromLength for LengthPercentage { from_length<Input: Into<f32> + Copy>(value: Input) -> Self25 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self { 26 Self::Length(value.into()) 27 } 28 } 29 impl FromPercent for LengthPercentage { from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self30 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self { 31 Self::Percent(percent.into()) 32 } 33 } 34 35 /// A unit of linear measurement 36 /// 37 /// This is commonly combined with [`Rect`], [`Point`](crate::geometry::Point) and [`Size<T>`]. 38 #[derive(Copy, Clone, PartialEq, Debug)] 39 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 40 pub enum LengthPercentageAuto { 41 /// An absolute length in some abstract units. Users of Taffy may define what they correspond 42 /// to in their application (pixels, logical pixels, mm, etc) as they see fit. 43 Length(f32), 44 /// A percentage length relative to the size of the containing block. 45 /// 46 /// **NOTE: percentages are represented as a f32 value in the range [0.0, 1.0] NOT the range [0.0, 100.0]** 47 Percent(f32), 48 /// The dimension should be automatically computed 49 Auto, 50 } 51 impl TaffyZero for LengthPercentageAuto { 52 const ZERO: Self = Self::Length(0.0); 53 } 54 impl TaffyAuto for LengthPercentageAuto { 55 const AUTO: Self = Self::Auto; 56 } 57 impl FromLength for LengthPercentageAuto { from_length<Input: Into<f32> + Copy>(value: Input) -> Self58 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self { 59 Self::Length(value.into()) 60 } 61 } 62 impl FromPercent for LengthPercentageAuto { from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self63 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self { 64 Self::Percent(percent.into()) 65 } 66 } 67 68 impl From<LengthPercentage> for LengthPercentageAuto { from(input: LengthPercentage) -> Self69 fn from(input: LengthPercentage) -> Self { 70 match input { 71 LengthPercentage::Length(value) => Self::Length(value), 72 LengthPercentage::Percent(value) => Self::Percent(value), 73 } 74 } 75 } 76 77 impl LengthPercentageAuto { 78 /// Returns: 79 /// - Some(length) for Length variants 80 /// - Some(resolved) using the provided context for Percent variants 81 /// - None for Auto variants 82 #[inline(always)] resolve_to_option(self, context: f32) -> Option<f32>83 pub fn resolve_to_option(self, context: f32) -> Option<f32> { 84 match self { 85 Self::Length(length) => Some(length), 86 Self::Percent(percent) => Some(context * percent), 87 Self::Auto => None, 88 } 89 } 90 91 /// Returns true if value is LengthPercentageAuto::Auto 92 #[inline(always)] is_auto(self) -> bool93 pub fn is_auto(self) -> bool { 94 self == Self::Auto 95 } 96 } 97 98 /// A unit of linear measurement 99 /// 100 /// This is commonly combined with [`Rect`], [`Point`](crate::geometry::Point) and [`Size<T>`]. 101 #[derive(Copy, Clone, PartialEq, Debug)] 102 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 103 pub enum Dimension { 104 /// An absolute length in some abstract units. Users of Taffy may define what they correspond 105 /// to in their application (pixels, logical pixels, mm, etc) as they see fit. 106 Length(f32), 107 /// A percentage length relative to the size of the containing block. 108 /// 109 /// **NOTE: percentages are represented as a f32 value in the range [0.0, 1.0] NOT the range [0.0, 100.0]** 110 Percent(f32), 111 /// The dimension should be automatically computed 112 Auto, 113 } 114 impl TaffyZero for Dimension { 115 const ZERO: Self = Self::Length(0.0); 116 } 117 impl TaffyAuto for Dimension { 118 const AUTO: Self = Self::Auto; 119 } 120 impl FromLength for Dimension { from_length<Input: Into<f32> + Copy>(value: Input) -> Self121 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self { 122 Self::Length(value.into()) 123 } 124 } 125 impl FromPercent for Dimension { from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self126 fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self { 127 Self::Percent(percent.into()) 128 } 129 } 130 131 impl From<LengthPercentage> for Dimension { from(input: LengthPercentage) -> Self132 fn from(input: LengthPercentage) -> Self { 133 match input { 134 LengthPercentage::Length(value) => Self::Length(value), 135 LengthPercentage::Percent(value) => Self::Percent(value), 136 } 137 } 138 } 139 140 impl From<LengthPercentageAuto> for Dimension { from(input: LengthPercentageAuto) -> Self141 fn from(input: LengthPercentageAuto) -> Self { 142 match input { 143 LengthPercentageAuto::Length(value) => Self::Length(value), 144 LengthPercentageAuto::Percent(value) => Self::Percent(value), 145 LengthPercentageAuto::Auto => Self::Auto, 146 } 147 } 148 } 149 150 impl Dimension { 151 /// Get Length value if value is Length variant 152 #[cfg(feature = "grid")] into_option(self) -> Option<f32>153 pub fn into_option(self) -> Option<f32> { 154 match self { 155 Dimension::Length(value) => Some(value), 156 _ => None, 157 } 158 } 159 } 160 161 impl Rect<Dimension> { 162 /// Create a new Rect with [`Dimension::Length`] 163 #[must_use] from_length(start: f32, end: f32, top: f32, bottom: f32) -> Self164 pub const fn from_length(start: f32, end: f32, top: f32, bottom: f32) -> Self { 165 Rect { 166 left: Dimension::Length(start), 167 right: Dimension::Length(end), 168 top: Dimension::Length(top), 169 bottom: Dimension::Length(bottom), 170 } 171 } 172 173 /// Create a new Rect with [`Dimension::Percent`] 174 #[must_use] from_percent(start: f32, end: f32, top: f32, bottom: f32) -> Self175 pub const fn from_percent(start: f32, end: f32, top: f32, bottom: f32) -> Self { 176 Rect { 177 left: Dimension::Percent(start), 178 right: Dimension::Percent(end), 179 top: Dimension::Percent(top), 180 bottom: Dimension::Percent(bottom), 181 } 182 } 183 } 184 185 /// The amount of space available to a node in a given axis 186 /// <https://www.w3.org/TR/css-sizing-3/#available> 187 #[derive(Copy, Clone, Debug, PartialEq)] 188 #[cfg_attr(feature = "serde", derive(Serialize))] 189 pub enum AvailableSpace { 190 /// The amount of space available is the specified number of pixels 191 Definite(f32), 192 /// The amount of space available is indefinite and the node should be laid out under a min-content constraint 193 MinContent, 194 /// The amount of space available is indefinite and the node should be laid out under a max-content constraint 195 MaxContent, 196 } 197 impl TaffyZero for AvailableSpace { 198 const ZERO: Self = Self::Definite(0.0); 199 } 200 impl TaffyMaxContent for AvailableSpace { 201 const MAX_CONTENT: Self = Self::MaxContent; 202 } 203 impl TaffyMinContent for AvailableSpace { 204 const MIN_CONTENT: Self = Self::MinContent; 205 } 206 impl FromLength for AvailableSpace { from_length<Input: Into<f32> + Copy>(value: Input) -> Self207 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self { 208 Self::Definite(value.into()) 209 } 210 } 211 212 impl AvailableSpace { 213 /// Returns true for definite values, else false is_definite(self) -> bool214 pub fn is_definite(self) -> bool { 215 matches!(self, AvailableSpace::Definite(_)) 216 } 217 218 /// Convert to Option 219 /// Definite values become Some(value). Constraints become None. into_option(self) -> Option<f32>220 pub fn into_option(self) -> Option<f32> { 221 match self { 222 AvailableSpace::Definite(value) => Some(value), 223 _ => None, 224 } 225 } 226 227 /// Return the definite value or a default value unwrap_or(self, default: f32) -> f32228 pub fn unwrap_or(self, default: f32) -> f32 { 229 self.into_option().unwrap_or(default) 230 } 231 232 /// Return the definite value. Panic is the value is not definite. 233 #[track_caller] unwrap(self) -> f32234 pub fn unwrap(self) -> f32 { 235 self.into_option().unwrap() 236 } 237 238 /// Return self if definite or a default value or(self, default: AvailableSpace) -> AvailableSpace239 pub fn or(self, default: AvailableSpace) -> AvailableSpace { 240 match self { 241 AvailableSpace::Definite(_) => self, 242 _ => default, 243 } 244 } 245 246 /// Return self if definite or a the result of the default value callback or_else(self, default_cb: impl FnOnce() -> AvailableSpace) -> AvailableSpace247 pub fn or_else(self, default_cb: impl FnOnce() -> AvailableSpace) -> AvailableSpace { 248 match self { 249 AvailableSpace::Definite(_) => self, 250 _ => default_cb(), 251 } 252 } 253 254 /// Return the definite value or the result of the default value callback unwrap_or_else(self, default_cb: impl FnOnce() -> f32) -> f32255 pub fn unwrap_or_else(self, default_cb: impl FnOnce() -> f32) -> f32 { 256 self.into_option().unwrap_or_else(default_cb) 257 } 258 259 /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self maybe_set(self, value: Option<f32>) -> AvailableSpace260 pub fn maybe_set(self, value: Option<f32>) -> AvailableSpace { 261 match value { 262 Some(value) => AvailableSpace::Definite(value), 263 None => self, 264 } 265 } 266 267 /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self map_definite_value(self, map_function: impl FnOnce(f32) -> f32) -> AvailableSpace268 pub fn map_definite_value(self, map_function: impl FnOnce(f32) -> f32) -> AvailableSpace { 269 match self { 270 AvailableSpace::Definite(value) => AvailableSpace::Definite(map_function(value)), 271 _ => self, 272 } 273 } 274 275 /// Compute free_space given the passed used_space compute_free_space(&self, used_space: f32) -> f32276 pub fn compute_free_space(&self, used_space: f32) -> f32 { 277 match self { 278 AvailableSpace::MaxContent => f32::INFINITY, 279 AvailableSpace::MinContent => 0.0, 280 AvailableSpace::Definite(available_space) => available_space - used_space, 281 } 282 } 283 284 /// Compare equality with another AvailableSpace, treating definite values 285 /// that are within f32::EPSILON of each other as equal is_roughly_equal(self, other: AvailableSpace) -> bool286 pub fn is_roughly_equal(self, other: AvailableSpace) -> bool { 287 use AvailableSpace::*; 288 match (self, other) { 289 (Definite(a), Definite(b)) => abs(a - b) < f32::EPSILON, 290 (MinContent, MinContent) => true, 291 (MaxContent, MaxContent) => true, 292 _ => false, 293 } 294 } 295 } 296 297 impl From<f32> for AvailableSpace { from(value: f32) -> Self298 fn from(value: f32) -> Self { 299 Self::Definite(value) 300 } 301 } 302 303 impl From<Option<f32>> for AvailableSpace { from(option: Option<f32>) -> Self304 fn from(option: Option<f32>) -> Self { 305 match option { 306 Some(value) => Self::Definite(value), 307 None => Self::MaxContent, 308 } 309 } 310 } 311 312 impl Size<AvailableSpace> { 313 /// Convert `Size<AvailableSpace>` into `Size<Option<f32>>` into_options(self) -> Size<Option<f32>>314 pub fn into_options(self) -> Size<Option<f32>> { 315 Size { width: self.width.into_option(), height: self.height.into_option() } 316 } 317 318 /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self maybe_set(self, value: Size<Option<f32>>) -> Size<AvailableSpace>319 pub fn maybe_set(self, value: Size<Option<f32>>) -> Size<AvailableSpace> { 320 Size { width: self.width.maybe_set(value.width), height: self.height.maybe_set(value.height) } 321 } 322 } 323