taffy/
style_helpers.rs

1//! Helper functions which it make it easier to create instances of types in the `style` and `geometry` modules.
2use crate::{
3    geometry::{Line, Point, Rect, Size},
4    style::LengthPercentage,
5};
6
7#[cfg(feature = "grid")]
8use crate::{
9    geometry::MinMax,
10    style::{
11        GridTrackRepetition, MaxTrackSizingFunction, MinTrackSizingFunction, NonRepeatedTrackSizingFunction,
12        TrackSizingFunction,
13    },
14    util::sys::Vec,
15};
16#[cfg(feature = "grid")]
17use core::fmt::Debug;
18
19/// Returns an auto-repeated track definition
20#[cfg(feature = "grid")]
21pub fn repeat<Input>(repetition_kind: Input, track_list: Vec<NonRepeatedTrackSizingFunction>) -> TrackSizingFunction
22where
23    Input: TryInto<GridTrackRepetition>,
24    <Input as TryInto<GridTrackRepetition>>::Error: Debug,
25{
26    TrackSizingFunction::Repeat(repetition_kind.try_into().unwrap(), track_list)
27}
28
29#[cfg(feature = "grid")]
30/// Returns a grid template containing `count` evenly sized tracks
31pub fn evenly_sized_tracks(count: u16) -> Vec<TrackSizingFunction> {
32    use crate::util::sys::new_vec_with_capacity;
33    let mut repeated_tracks = new_vec_with_capacity(1);
34    repeated_tracks.push(flex(1.0f32));
35    let mut tracks = new_vec_with_capacity(1);
36    tracks.push(repeat(count, repeated_tracks));
37    tracks
38}
39
40/// Specifies a grid line to place a grid item between in CSS Grid Line coordinates:
41///  - Positive indices count upwards from the start (top or left) of the explicit grid
42///  - Negative indices count downwards from the end (bottom or right) of the explicit grid
43///  - ZERO IS INVALID index, and will be treated as a GridPlacement::Auto.
44pub fn line<T: TaffyGridLine>(index: i16) -> T {
45    T::from_line_index(index)
46}
47/// Trait to abstract over grid line values
48pub trait TaffyGridLine {
49    /// Converts an i16 into Self
50    fn from_line_index(index: i16) -> Self;
51}
52
53/// Returns a GridPlacement::Span
54pub fn span<T: TaffyGridSpan>(span: u16) -> T {
55    T::from_span(span)
56}
57/// Trait to abstract over grid span values
58pub trait TaffyGridSpan {
59    /// Converts an iu6 into Self
60    fn from_span(span: u16) -> Self;
61}
62
63/// Returns a MinMax with min value of min and max value of max
64#[cfg(feature = "grid")]
65pub fn minmax<Output>(min: MinTrackSizingFunction, max: MaxTrackSizingFunction) -> Output
66where
67    Output: From<MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>>,
68{
69    MinMax { min, max }.into()
70}
71
72/// Shorthand for minmax(0, Nfr). Probably what you want if you want exactly evenly sized tracks.
73#[cfg(feature = "grid")]
74pub fn flex<Input, Output>(flex_fraction: Input) -> Output
75where
76    Input: Into<f32> + Copy,
77    Output: From<MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>>,
78{
79    MinMax { min: zero(), max: fr(flex_fraction.into()) }.into()
80}
81
82/// Returns the zero value for that type
83pub const fn zero<T: TaffyZero>() -> T {
84    T::ZERO
85}
86
87/// Trait to abstract over zero values
88pub trait TaffyZero {
89    /// The zero value for type implementing TaffyZero
90    const ZERO: Self;
91}
92impl TaffyZero for f32 {
93    const ZERO: f32 = 0.0;
94}
95impl<T: TaffyZero> TaffyZero for Option<T> {
96    const ZERO: Option<T> = Some(T::ZERO);
97}
98impl<T: TaffyZero> TaffyZero for Point<T> {
99    const ZERO: Point<T> = Point { x: T::ZERO, y: T::ZERO };
100}
101impl<T: TaffyZero> Point<T> {
102    /// Returns a Point where both the x and y values are the zero value of the contained type
103    /// (e.g. 0.0, Some(0.0), or Dimension::Length(0.0))
104    pub const fn zero() -> Self {
105        zero::<Self>()
106    }
107}
108impl<T: TaffyZero> TaffyZero for Line<T> {
109    const ZERO: Line<T> = Line { start: T::ZERO, end: T::ZERO };
110}
111impl<T: TaffyZero> Line<T> {
112    /// Returns a Line where both the start and end values are the zero value of the contained type
113    /// (e.g. 0.0, Some(0.0), or Dimension::Length(0.0))
114    pub const fn zero() -> Self {
115        zero::<Self>()
116    }
117}
118impl<T: TaffyZero> TaffyZero for Size<T> {
119    const ZERO: Size<T> = Size { width: T::ZERO, height: T::ZERO };
120}
121impl<T: TaffyZero> Size<T> {
122    /// Returns a Size where both the width and height values are the zero value of the contained type
123    /// (e.g. 0.0, Some(0.0), or Dimension::Length(0.0))
124    pub const fn zero() -> Self {
125        zero::<Self>()
126    }
127}
128impl<T: TaffyZero> TaffyZero for Rect<T> {
129    const ZERO: Rect<T> = Rect { left: T::ZERO, right: T::ZERO, top: T::ZERO, bottom: T::ZERO };
130}
131impl<T: TaffyZero> Rect<T> {
132    /// Returns a Rect where the left, right, top, and bottom values are all the zero value of the contained type
133    /// (e.g. 0.0, Some(0.0), or Dimension::Length(0.0))
134    pub const fn zero() -> Self {
135        zero::<Self>()
136    }
137}
138
139/// Returns the auto value for that type
140pub const fn auto<T: TaffyAuto>() -> T {
141    T::AUTO
142}
143
144/// Trait to abstract over auto values
145pub trait TaffyAuto {
146    /// The auto value for type implementing TaffyAuto
147    const AUTO: Self;
148}
149impl<T: TaffyAuto> TaffyAuto for Option<T> {
150    const AUTO: Option<T> = Some(T::AUTO);
151}
152impl<T: TaffyAuto> TaffyAuto for Point<T> {
153    const AUTO: Point<T> = Point { x: T::AUTO, y: T::AUTO };
154}
155impl<T: TaffyAuto> Point<T> {
156    /// Returns a Point where both the x and y values are the auto value of the contained type
157    /// (e.g. Dimension::Auto or LengthPercentageAuto::Auto)
158    pub const fn auto() -> Self {
159        auto::<Self>()
160    }
161}
162impl<T: TaffyAuto> TaffyAuto for Line<T> {
163    const AUTO: Line<T> = Line { start: T::AUTO, end: T::AUTO };
164}
165impl<T: TaffyAuto> Line<T> {
166    /// Returns a Line where both the start and end values are the auto value of the contained type
167    /// (e.g. Dimension::Auto or LengthPercentageAuto::Auto)
168    pub const fn auto() -> Self {
169        auto::<Self>()
170    }
171}
172impl<T: TaffyAuto> TaffyAuto for Size<T> {
173    const AUTO: Size<T> = Size { width: T::AUTO, height: T::AUTO };
174}
175impl<T: TaffyAuto> Size<T> {
176    /// Returns a Size where both the width and height values are the auto value of the contained type
177    /// (e.g. Dimension::Auto or LengthPercentageAuto::Auto)
178    pub const fn auto() -> Self {
179        auto::<Self>()
180    }
181}
182impl<T: TaffyAuto> TaffyAuto for Rect<T> {
183    const AUTO: Rect<T> = Rect { left: T::AUTO, right: T::AUTO, top: T::AUTO, bottom: T::AUTO };
184}
185impl<T: TaffyAuto> Rect<T> {
186    /// Returns a Rect where the left, right, top, and bottom values are all the auto value of the contained type
187    /// (e.g. Dimension::Auto or LengthPercentageAuto::Auto)
188    pub const fn auto() -> Self {
189        auto::<Self>()
190    }
191}
192
193/// Returns the auto value for that type
194pub const fn min_content<T: TaffyMinContent>() -> T {
195    T::MIN_CONTENT
196}
197
198/// Trait to abstract over min_content values
199pub trait TaffyMinContent {
200    /// The min_content value for type implementing TaffyZero
201    const MIN_CONTENT: Self;
202}
203impl<T: TaffyMinContent> TaffyMinContent for Option<T> {
204    const MIN_CONTENT: Option<T> = Some(T::MIN_CONTENT);
205}
206impl<T: TaffyMinContent> TaffyMinContent for Point<T> {
207    const MIN_CONTENT: Point<T> = Point { x: T::MIN_CONTENT, y: T::MIN_CONTENT };
208}
209impl<T: TaffyMinContent> Point<T> {
210    /// Returns a Point where both the x and y values are the min_content value of the contained type
211    /// (e.g. Dimension::Auto or LengthPercentageAuto::Auto)
212    pub const fn min_content() -> Self {
213        min_content::<Self>()
214    }
215}
216impl<T: TaffyMinContent> TaffyMinContent for Line<T> {
217    const MIN_CONTENT: Line<T> = Line { start: T::MIN_CONTENT, end: T::MIN_CONTENT };
218}
219impl<T: TaffyMinContent> Line<T> {
220    /// Returns a Line where both the start and end values are the min_content value of the contained type
221    /// (e.g. Dimension::Auto or LengthPercentageAuto::Auto)
222    pub const fn min_content() -> Self {
223        min_content::<Self>()
224    }
225}
226impl<T: TaffyMinContent> TaffyMinContent for Size<T> {
227    const MIN_CONTENT: Size<T> = Size { width: T::MIN_CONTENT, height: T::MIN_CONTENT };
228}
229impl<T: TaffyMinContent> Size<T> {
230    /// Returns a Size where both the width and height values are the min_content value of the contained type
231    /// (e.g. Dimension::Auto or LengthPercentageAuto::Auto)
232    pub const fn min_content() -> Self {
233        min_content::<Self>()
234    }
235}
236impl<T: TaffyMinContent> TaffyMinContent for Rect<T> {
237    const MIN_CONTENT: Rect<T> =
238        Rect { left: T::MIN_CONTENT, right: T::MIN_CONTENT, top: T::MIN_CONTENT, bottom: T::MIN_CONTENT };
239}
240impl<T: TaffyMinContent> Rect<T> {
241    /// Returns a Rect where the left, right, top, and bottom values are all the min_content value of the contained type
242    /// (e.g. Dimension::Auto or LengthPercentageAuto::Auto)
243    pub const fn min_content() -> Self {
244        min_content::<Self>()
245    }
246}
247
248/// Returns the auto value for that type
249pub const fn max_content<T: TaffyMaxContent>() -> T {
250    T::MAX_CONTENT
251}
252
253/// Trait to abstract over max_content values
254pub trait TaffyMaxContent {
255    /// The max_content value for type implementing TaffyZero
256    const MAX_CONTENT: Self;
257}
258impl<T: TaffyMaxContent> TaffyMaxContent for Option<T> {
259    const MAX_CONTENT: Option<T> = Some(T::MAX_CONTENT);
260}
261impl<T: TaffyMaxContent> TaffyMaxContent for Point<T> {
262    const MAX_CONTENT: Point<T> = Point { x: T::MAX_CONTENT, y: T::MAX_CONTENT };
263}
264impl<T: TaffyMaxContent> Point<T> {
265    /// Returns a Point where both the x and y values are the max_content value of the contained type
266    /// (e.g. Dimension::Auto or LengthPercentageAuto::Auto)
267    pub const fn max_content() -> Self {
268        max_content::<Self>()
269    }
270}
271impl<T: TaffyMaxContent> TaffyMaxContent for Line<T> {
272    const MAX_CONTENT: Line<T> = Line { start: T::MAX_CONTENT, end: T::MAX_CONTENT };
273}
274impl<T: TaffyMaxContent> Line<T> {
275    /// Returns a Line where both the start and end values are the max_content value of the contained type
276    /// (e.g. Dimension::Auto or LengthPercentageAuto::Auto)
277    pub const fn max_content() -> Self {
278        max_content::<Self>()
279    }
280}
281impl<T: TaffyMaxContent> TaffyMaxContent for Size<T> {
282    const MAX_CONTENT: Size<T> = Size { width: T::MAX_CONTENT, height: T::MAX_CONTENT };
283}
284impl<T: TaffyMaxContent> Size<T> {
285    /// Returns a Size where both the width and height values are the max_content value of the contained type
286    /// (e.g. Dimension::Auto or LengthPercentageAuto::Auto)
287    pub const fn max_content() -> Self {
288        max_content::<Self>()
289    }
290}
291impl<T: TaffyMaxContent> TaffyMaxContent for Rect<T> {
292    const MAX_CONTENT: Rect<T> =
293        Rect { left: T::MAX_CONTENT, right: T::MAX_CONTENT, top: T::MAX_CONTENT, bottom: T::MAX_CONTENT };
294}
295impl<T: TaffyMaxContent> Rect<T> {
296    /// Returns a Rect where the left, right, top, and bottom values are all the max_content value of the contained type
297    /// (e.g. Dimension::Auto or LengthPercentageAuto::Auto)
298    pub const fn max_content() -> Self {
299        max_content::<Self>()
300    }
301}
302
303/// Returns a value of the inferred type which represent a `fit-content(…)` value
304/// with the given argument.
305pub fn fit_content<T: TaffyFitContent>(argument: LengthPercentage) -> T {
306    T::fit_content(argument)
307}
308
309/// Trait to create `fit-content(…)` values from plain numbers
310pub trait TaffyFitContent {
311    /// Converts a LengthPercentage into Self
312    fn fit_content(argument: LengthPercentage) -> Self;
313}
314impl<T: TaffyFitContent> TaffyFitContent for Point<T> {
315    fn fit_content(argument: LengthPercentage) -> Self {
316        Point { x: T::fit_content(argument), y: T::fit_content(argument) }
317    }
318}
319impl<T: TaffyFitContent> Point<T> {
320    /// Returns a Point with x and y set to the same `fit-content(…)` value
321    /// with the given argument.
322    pub fn fit_content(argument: LengthPercentage) -> Self {
323        fit_content(argument)
324    }
325}
326impl<T: TaffyFitContent> TaffyFitContent for Line<T> {
327    fn fit_content(argument: LengthPercentage) -> Self {
328        Line { start: T::fit_content(argument), end: T::fit_content(argument) }
329    }
330}
331impl<T: TaffyFitContent> Line<T> {
332    /// Returns a Line with start and end set to the same `fit-content(…)` value
333    /// with the given argument.
334    pub fn fit_content(argument: LengthPercentage) -> Self {
335        fit_content(argument)
336    }
337}
338impl<T: TaffyFitContent> TaffyFitContent for Size<T> {
339    fn fit_content(argument: LengthPercentage) -> Self {
340        Size { width: T::fit_content(argument), height: T::fit_content(argument) }
341    }
342}
343impl<T: TaffyFitContent> Size<T> {
344    /// Returns a Size where with width and height set to the same `fit-content(…)` value
345    /// with the given argument.
346    pub fn fit_content(argument: LengthPercentage) -> Self {
347        fit_content(argument)
348    }
349}
350impl<T: TaffyFitContent> TaffyFitContent for Rect<T> {
351    fn fit_content(argument: LengthPercentage) -> Self {
352        Rect {
353            left: T::fit_content(argument),
354            right: T::fit_content(argument),
355            top: T::fit_content(argument),
356            bottom: T::fit_content(argument),
357        }
358    }
359}
360impl<T: TaffyFitContent> Rect<T> {
361    /// Returns a Rect where the left, right, top and bottom values are all constant fit_content value of the contained type
362    /// (e.g. 2.1, Some(2.1), or Dimension::Length(2.1))
363    pub fn fit_content(argument: LengthPercentage) -> Self {
364        fit_content(argument)
365    }
366}
367
368/// Returns a value of the inferred type which represent an absolute length
369pub fn length<Input: Into<f32> + Copy, T: FromLength>(value: Input) -> T {
370    T::from_length(value)
371}
372
373/// Trait to create absolute length values from plain numbers
374pub trait FromLength {
375    /// Converts into an `Into<f32>` into Self
376    fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self;
377}
378impl FromLength for f32 {
379    fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
380        value.into()
381    }
382}
383impl FromLength for Option<f32> {
384    fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
385        Some(value.into())
386    }
387}
388impl<T: FromLength> FromLength for Point<T> {
389    fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
390        Point { x: T::from_length(value.into()), y: T::from_length(value.into()) }
391    }
392}
393impl<T: FromLength> Point<T> {
394    /// Returns a Point where x and y values are the same given absolute length
395    pub fn length<Input: Into<f32> + Copy>(value: Input) -> Self {
396        length::<Input, Self>(value)
397    }
398}
399impl<T: FromLength> FromLength for Line<T> {
400    fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
401        Line { start: T::from_length(value.into()), end: T::from_length(value.into()) }
402    }
403}
404impl<T: FromLength> Line<T> {
405    /// Returns a Line where both the start and end values are the same given absolute length
406    pub fn length<Input: Into<f32> + Copy>(value: Input) -> Self {
407        length::<Input, Self>(value)
408    }
409}
410impl<T: FromLength> FromLength for Size<T> {
411    fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
412        Size { width: T::from_length(value.into()), height: T::from_length(value.into()) }
413    }
414}
415impl<T: FromLength> Size<T> {
416    /// Returns a Size where both the width and height values the same given absolute length
417    pub fn length<Input: Into<f32> + Copy>(value: Input) -> Self {
418        length::<Input, Self>(value)
419    }
420}
421impl<T: FromLength> FromLength for Rect<T> {
422    fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
423        Rect {
424            left: T::from_length(value.into()),
425            right: T::from_length(value.into()),
426            top: T::from_length(value.into()),
427            bottom: T::from_length(value.into()),
428        }
429    }
430}
431impl<T: FromLength> Rect<T> {
432    /// Returns a Rect where the left, right, top and bottom values are all the same given absolute length
433    pub fn length<Input: Into<f32> + Copy>(value: Input) -> Self {
434        length::<Input, Self>(value)
435    }
436}
437
438/// Returns a value of the inferred type which represent a percentage
439pub fn percent<Input: Into<f32> + Copy, T: FromPercent>(percent: Input) -> T {
440    T::from_percent(percent)
441}
442
443/// Trait to create constant percent values from plain numbers
444pub trait FromPercent {
445    /// Converts into an `Into<f32>` into Self
446    fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self;
447}
448impl FromPercent for f32 {
449    fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
450        percent.into()
451    }
452}
453impl FromPercent for Option<f32> {
454    fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
455        Some(percent.into())
456    }
457}
458impl<T: FromPercent> FromPercent for Point<T> {
459    fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
460        Point { x: T::from_percent(percent.into()), y: T::from_percent(percent.into()) }
461    }
462}
463impl<T: FromPercent> Point<T> {
464    /// Returns a Point where both the x and y values are the constant percent value of the contained type
465    /// (e.g. 2.1, Some(2.1), or Dimension::Length(2.1))
466    pub fn percent<Input: Into<f32> + Copy>(percent_value: Input) -> Self {
467        percent::<Input, Self>(percent_value)
468    }
469}
470impl<T: FromPercent> FromPercent for Line<T> {
471    fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
472        Line { start: T::from_percent(percent.into()), end: T::from_percent(percent.into()) }
473    }
474}
475impl<T: FromPercent> Line<T> {
476    /// Returns a Line where both the start and end values are the constant percent value of the contained type
477    /// (e.g. 2.1, Some(2.1), or Dimension::Length(2.1))
478    pub fn percent<Input: Into<f32> + Copy>(percent_value: Input) -> Self {
479        percent::<Input, Self>(percent_value)
480    }
481}
482impl<T: FromPercent> FromPercent for Size<T> {
483    fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
484        Size { width: T::from_percent(percent.into()), height: T::from_percent(percent.into()) }
485    }
486}
487impl<T: FromPercent> Size<T> {
488    /// Returns a Size where both the width and height values are the constant percent value of the contained type
489    /// (e.g. 2.1, Some(2.1), or Dimension::Length(2.1))
490    pub fn percent<Input: Into<f32> + Copy>(percent_value: Input) -> Self {
491        percent::<Input, Self>(percent_value)
492    }
493}
494impl<T: FromPercent> FromPercent for Rect<T> {
495    fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
496        Rect {
497            left: T::from_percent(percent.into()),
498            right: T::from_percent(percent.into()),
499            top: T::from_percent(percent.into()),
500            bottom: T::from_percent(percent.into()),
501        }
502    }
503}
504impl<T: FromPercent> Rect<T> {
505    /// Returns a Rect where the left, right, top and bottom values are all constant percent value of the contained type
506    /// (e.g. 2.1, Some(2.1), or Dimension::Length(2.1))
507    pub fn percent<Input: Into<f32> + Copy>(percent_value: Input) -> Self {
508        percent::<Input, Self>(percent_value)
509    }
510}
511
512/// Create a `Fraction` track sizing function (`fr` in CSS)
513#[cfg(feature = "grid")]
514pub fn fr<Input: Into<f32> + Copy, T: FromFlex>(flex: Input) -> T {
515    T::from_flex(flex)
516}
517
518/// Trait to create constant percent values from plain numbers
519pub trait FromFlex {
520    /// Converts into an `Into<f32>` into Self
521    fn from_flex<Input: Into<f32> + Copy>(flex: Input) -> Self;
522}
523
524#[cfg(feature = "grid")]
525#[cfg(test)]
526mod repeat_fn_tests {
527    use super::repeat;
528    use crate::style::{GridTrackRepetition, NonRepeatedTrackSizingFunction, TrackSizingFunction};
529
530    const TEST_VEC: Vec<NonRepeatedTrackSizingFunction> = Vec::new();
531
532    #[test]
533    fn test_repeat_u16() {
534        assert_eq!(repeat(123, TEST_VEC), TrackSizingFunction::Repeat(GridTrackRepetition::Count(123), TEST_VEC));
535    }
536
537    #[test]
538    fn test_repeat_auto_fit_str() {
539        assert_eq!(repeat("auto-fit", TEST_VEC), TrackSizingFunction::Repeat(GridTrackRepetition::AutoFit, TEST_VEC));
540    }
541
542    #[test]
543    fn test_repeat_auto_fill_str() {
544        assert_eq!(repeat("auto-fill", TEST_VEC), TrackSizingFunction::Repeat(GridTrackRepetition::AutoFill, TEST_VEC));
545    }
546}