⎇ 9eacffcf1eefe9cf68895579d90c5f1cfe30f489
src/style_helpers.rs
Ñawpa willay
Pi imata llamkarqan
ch'uya
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 u16 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: FromFr>(flex: Input) -> T {
515 T::from_fr(flex)
516}
517
518/// Trait to create constant percent values from plain numbers
519pub trait FromFr {
520 /// Converts into an `Into<f32>` into Self
521 fn from_fr<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}