Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ui/src/geometry.rs
9354 views
1
use bevy_math::{MismatchedUnitsError, StableInterpolate as _, TryStableInterpolate, Vec2};
2
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
3
use bevy_utils::default;
4
use core::ops::{Div, DivAssign, Mul, MulAssign, Neg};
5
use thiserror::Error;
6
7
#[cfg(feature = "serialize")]
8
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
9
10
/// Represents the possible value types for layout properties.
11
///
12
/// This enum allows specifying values for various [`Node`](crate::Node) properties in different units,
13
/// such as logical pixels, percentages, or automatically determined values.
14
///
15
/// `Val` also implements [`core::str::FromStr`] to allow parsing values from strings in the format `#.#px`. Whitespaces between the value and unit is allowed. The following units are supported:
16
/// * `px`: logical pixels
17
/// * `%`: percentage
18
/// * `vw`: percentage of the viewport width
19
/// * `vh`: percentage of the viewport height
20
/// * `vmin`: percentage of the viewport's smaller dimension
21
/// * `vmax`: percentage of the viewport's larger dimension
22
///
23
/// Additionally, `auto` will be parsed as [`Val::Auto`].
24
#[derive(Copy, Clone, Debug, Reflect)]
25
#[reflect(Default, PartialEq, Debug, Clone)]
26
#[cfg_attr(
27
feature = "serialize",
28
derive(serde::Serialize, serde::Deserialize),
29
reflect(Serialize, Deserialize)
30
)]
31
pub enum Val {
32
/// Automatically determine the value based on the context and other [`Node`](crate::Node) properties.
33
Auto,
34
/// Set this value in logical pixels.
35
Px(f32),
36
/// Set the value as a percentage of its parent node's length along a specific axis.
37
///
38
/// If the UI node has no parent, the percentage is calculated based on the window's length
39
/// along the corresponding axis.
40
///
41
/// The chosen axis depends on the [`Node`](crate::Node) field set:
42
/// * For `flex_basis`, the percentage is relative to the main-axis length determined by the `flex_direction`.
43
/// * For `gap`, `min_size`, `size`, and `max_size`:
44
/// - `width` is relative to the parent's width.
45
/// - `height` is relative to the parent's height.
46
/// * For `margin`, `padding`, and `border` values: the percentage is relative to the parent node's width.
47
/// * For positions, `left` and `right` are relative to the parent's width, while `bottom` and `top` are relative to the parent's height.
48
Percent(f32),
49
/// Set this value in percent of the viewport width
50
Vw(f32),
51
/// Set this value in percent of the viewport height
52
Vh(f32),
53
/// Set this value in percent of the viewport's smaller dimension.
54
VMin(f32),
55
/// Set this value in percent of the viewport's larger dimension.
56
VMax(f32),
57
}
58
59
#[derive(Debug, Error, PartialEq, Eq)]
60
pub enum ValParseError {
61
UnitMissing,
62
ValueMissing,
63
InvalidValue,
64
InvalidUnit,
65
}
66
67
impl core::fmt::Display for ValParseError {
68
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
69
match self {
70
ValParseError::UnitMissing => write!(f, "unit missing"),
71
ValParseError::ValueMissing => write!(f, "value missing"),
72
ValParseError::InvalidValue => write!(f, "invalid value"),
73
ValParseError::InvalidUnit => write!(f, "invalid unit"),
74
}
75
}
76
}
77
78
impl core::str::FromStr for Val {
79
type Err = ValParseError;
80
81
fn from_str(s: &str) -> Result<Self, Self::Err> {
82
let s = s.trim();
83
84
if s.eq_ignore_ascii_case("auto") {
85
return Ok(Val::Auto);
86
}
87
88
let Some(end_of_number) = s
89
.bytes()
90
.position(|c| !(c.is_ascii_digit() || c == b'.' || c == b'-' || c == b'+'))
91
else {
92
return Err(ValParseError::UnitMissing);
93
};
94
95
if end_of_number == 0 {
96
return Err(ValParseError::ValueMissing);
97
}
98
99
let (value, unit) = s.split_at(end_of_number);
100
101
let value: f32 = value.parse().map_err(|_| ValParseError::InvalidValue)?;
102
103
let unit = unit.trim();
104
105
if unit.eq_ignore_ascii_case("px") {
106
Ok(Val::Px(value))
107
} else if unit.eq_ignore_ascii_case("%") {
108
Ok(Val::Percent(value))
109
} else if unit.eq_ignore_ascii_case("vw") {
110
Ok(Val::Vw(value))
111
} else if unit.eq_ignore_ascii_case("vh") {
112
Ok(Val::Vh(value))
113
} else if unit.eq_ignore_ascii_case("vmin") {
114
Ok(Val::VMin(value))
115
} else if unit.eq_ignore_ascii_case("vmax") {
116
Ok(Val::VMax(value))
117
} else {
118
Err(ValParseError::InvalidUnit)
119
}
120
}
121
}
122
123
impl PartialEq for Val {
124
fn eq(&self, other: &Self) -> bool {
125
let same_unit = matches!(
126
(self, other),
127
(Self::Auto, Self::Auto)
128
| (Self::Px(_), Self::Px(_))
129
| (Self::Percent(_), Self::Percent(_))
130
| (Self::Vw(_), Self::Vw(_))
131
| (Self::Vh(_), Self::Vh(_))
132
| (Self::VMin(_), Self::VMin(_))
133
| (Self::VMax(_), Self::VMax(_))
134
);
135
136
let left = match self {
137
Self::Auto => None,
138
Self::Px(v)
139
| Self::Percent(v)
140
| Self::Vw(v)
141
| Self::Vh(v)
142
| Self::VMin(v)
143
| Self::VMax(v) => Some(v),
144
};
145
146
let right = match other {
147
Self::Auto => None,
148
Self::Px(v)
149
| Self::Percent(v)
150
| Self::Vw(v)
151
| Self::Vh(v)
152
| Self::VMin(v)
153
| Self::VMax(v) => Some(v),
154
};
155
156
match (same_unit, left, right) {
157
(true, a, b) => a == b,
158
// All zero-value variants are considered equal.
159
(false, Some(&a), Some(&b)) => a == 0. && b == 0.,
160
_ => false,
161
}
162
}
163
}
164
165
impl Val {
166
pub const DEFAULT: Self = Self::Auto;
167
pub const ZERO: Self = Self::Px(0.0);
168
169
/// Returns a [`UiRect`] with its `left` equal to this value,
170
/// and all other fields set to `Val::ZERO`.
171
///
172
///
173
/// # Example
174
///
175
/// ```
176
/// # use bevy_ui::{UiRect, Val};
177
/// #
178
/// let ui_rect = Val::Px(1.).left();
179
///
180
/// assert_eq!(ui_rect.left, Val::Px(1.));
181
/// assert_eq!(ui_rect.right, Val::ZERO);
182
/// assert_eq!(ui_rect.top, Val::ZERO);
183
/// assert_eq!(ui_rect.bottom, Val::ZERO);
184
/// ```
185
pub const fn left(self) -> UiRect {
186
UiRect::left(self)
187
}
188
189
/// Returns a [`UiRect`] with its `right` equal to this value,
190
/// and all other fields set to `Val::ZERO`.
191
///
192
///
193
/// # Example
194
///
195
/// ```
196
/// # use bevy_ui::{UiRect, Val};
197
/// #
198
/// let ui_rect = Val::Px(1.).right();
199
///
200
/// assert_eq!(ui_rect.left, Val::ZERO);
201
/// assert_eq!(ui_rect.right, Val::Px(1.));
202
/// assert_eq!(ui_rect.top, Val::ZERO);
203
/// assert_eq!(ui_rect.bottom, Val::ZERO);
204
/// ```
205
pub const fn right(self) -> UiRect {
206
UiRect::right(self)
207
}
208
209
/// Returns a [`UiRect`] with its `top` equal to this value,
210
/// and all other fields set to `Val::ZERO`.
211
///
212
///
213
/// # Example
214
///
215
/// ```
216
/// # use bevy_ui::{UiRect, Val};
217
/// #
218
/// let ui_rect = Val::Px(1.).top();
219
///
220
/// assert_eq!(ui_rect.left, Val::ZERO);
221
/// assert_eq!(ui_rect.right, Val::ZERO);
222
/// assert_eq!(ui_rect.top, Val::Px(1.));
223
/// assert_eq!(ui_rect.bottom, Val::ZERO);
224
/// ```
225
pub const fn top(self) -> UiRect {
226
UiRect::top(self)
227
}
228
229
/// Returns a [`UiRect`] with its `bottom` equal to this value,
230
/// and all other fields set to `Val::ZERO`.
231
///
232
///
233
/// # Example
234
///
235
/// ```
236
/// # use bevy_ui::{UiRect, Val};
237
/// #
238
/// let ui_rect = Val::Px(1.).bottom();
239
///
240
/// assert_eq!(ui_rect.left, Val::ZERO);
241
/// assert_eq!(ui_rect.right, Val::ZERO);
242
/// assert_eq!(ui_rect.top, Val::ZERO);
243
/// assert_eq!(ui_rect.bottom, Val::Px(1.));
244
/// ```
245
pub const fn bottom(self) -> UiRect {
246
UiRect::bottom(self)
247
}
248
249
/// Returns a [`UiRect`] with all its fields equal to this value.
250
///
251
/// # Example
252
///
253
/// ```
254
/// # use bevy_ui::{UiRect, Val};
255
/// #
256
/// let ui_rect = Val::Px(1.).all();
257
///
258
/// assert_eq!(ui_rect.left, Val::Px(1.));
259
/// assert_eq!(ui_rect.right, Val::Px(1.));
260
/// assert_eq!(ui_rect.top, Val::Px(1.));
261
/// assert_eq!(ui_rect.bottom, Val::Px(1.));
262
/// ```
263
pub const fn all(self) -> UiRect {
264
UiRect::all(self)
265
}
266
267
/// Returns a [`UiRect`] with all its `left` and `right` equal to this value,
268
/// and its `top` and `bottom` set to `Val::ZERO`.
269
///
270
/// # Example
271
///
272
/// ```
273
/// # use bevy_ui::{UiRect, Val};
274
/// #
275
/// let ui_rect = Val::Px(1.).horizontal();
276
///
277
/// assert_eq!(ui_rect.left, Val::Px(1.));
278
/// assert_eq!(ui_rect.right, Val::Px(1.));
279
/// assert_eq!(ui_rect.top, Val::ZERO);
280
/// assert_eq!(ui_rect.bottom, Val::ZERO);
281
/// ```
282
pub const fn horizontal(self) -> UiRect {
283
UiRect::horizontal(self)
284
}
285
286
/// Returns a [`UiRect`] with all its `top` and `bottom` equal to this value,
287
/// and its `left` and `right` set to `Val::ZERO`.
288
///
289
/// # Example
290
///
291
/// ```
292
/// # use bevy_ui::{UiRect, Val};
293
/// #
294
/// let ui_rect = Val::Px(1.).vertical();
295
///
296
/// assert_eq!(ui_rect.left, Val::ZERO);
297
/// assert_eq!(ui_rect.right, Val::ZERO);
298
/// assert_eq!(ui_rect.top, Val::Px(1.));
299
/// assert_eq!(ui_rect.bottom, Val::Px(1.));
300
/// ```
301
pub const fn vertical(self) -> UiRect {
302
UiRect::vertical(self)
303
}
304
}
305
306
impl Default for Val {
307
fn default() -> Self {
308
Self::DEFAULT
309
}
310
}
311
312
impl Mul<f32> for Val {
313
type Output = Val;
314
315
fn mul(self, rhs: f32) -> Self::Output {
316
match self {
317
Val::Auto => Val::Auto,
318
Val::Px(value) => Val::Px(value * rhs),
319
Val::Percent(value) => Val::Percent(value * rhs),
320
Val::Vw(value) => Val::Vw(value * rhs),
321
Val::Vh(value) => Val::Vh(value * rhs),
322
Val::VMin(value) => Val::VMin(value * rhs),
323
Val::VMax(value) => Val::VMax(value * rhs),
324
}
325
}
326
}
327
328
impl MulAssign<f32> for Val {
329
fn mul_assign(&mut self, rhs: f32) {
330
match self {
331
Val::Auto => {}
332
Val::Px(value)
333
| Val::Percent(value)
334
| Val::Vw(value)
335
| Val::Vh(value)
336
| Val::VMin(value)
337
| Val::VMax(value) => *value *= rhs,
338
}
339
}
340
}
341
342
impl Div<f32> for Val {
343
type Output = Val;
344
345
fn div(self, rhs: f32) -> Self::Output {
346
match self {
347
Val::Auto => Val::Auto,
348
Val::Px(value) => Val::Px(value / rhs),
349
Val::Percent(value) => Val::Percent(value / rhs),
350
Val::Vw(value) => Val::Vw(value / rhs),
351
Val::Vh(value) => Val::Vh(value / rhs),
352
Val::VMin(value) => Val::VMin(value / rhs),
353
Val::VMax(value) => Val::VMax(value / rhs),
354
}
355
}
356
}
357
358
impl DivAssign<f32> for Val {
359
fn div_assign(&mut self, rhs: f32) {
360
match self {
361
Val::Auto => {}
362
Val::Px(value)
363
| Val::Percent(value)
364
| Val::Vw(value)
365
| Val::Vh(value)
366
| Val::VMin(value)
367
| Val::VMax(value) => *value /= rhs,
368
}
369
}
370
}
371
372
impl Neg for Val {
373
type Output = Val;
374
375
fn neg(self) -> Self::Output {
376
match self {
377
Val::Px(value) => Val::Px(-value),
378
Val::Percent(value) => Val::Percent(-value),
379
Val::Vw(value) => Val::Vw(-value),
380
Val::Vh(value) => Val::Vh(-value),
381
Val::VMin(value) => Val::VMin(-value),
382
Val::VMax(value) => Val::VMax(-value),
383
_ => self,
384
}
385
}
386
}
387
388
#[derive(Debug, Eq, PartialEq, Clone, Copy, Error)]
389
pub enum ValArithmeticError {
390
#[error("the given variant of Val is not evaluable (non-numeric)")]
391
NonEvaluable,
392
}
393
394
impl Val {
395
/// Resolves this [`Val`] to a value in physical pixels from the given `scale_factor`, `physical_base_value`,
396
/// and `physical_target_size` context values.
397
///
398
/// Returns a [`ValArithmeticError::NonEvaluable`] if the [`Val`] is impossible to resolve into a concrete value.
399
pub const fn resolve(
400
self,
401
scale_factor: f32,
402
physical_base_value: f32,
403
physical_target_size: Vec2,
404
) -> Result<f32, ValArithmeticError> {
405
match self {
406
Val::Percent(value) => Ok(physical_base_value * value / 100.0),
407
Val::Px(value) => Ok(value * scale_factor),
408
Val::Vw(value) => Ok(physical_target_size.x * value / 100.0),
409
Val::Vh(value) => Ok(physical_target_size.y * value / 100.0),
410
Val::VMin(value) => {
411
Ok(physical_target_size.x.min(physical_target_size.y) * value / 100.0)
412
}
413
Val::VMax(value) => {
414
Ok(physical_target_size.x.max(physical_target_size.y) * value / 100.0)
415
}
416
Val::Auto => Err(ValArithmeticError::NonEvaluable),
417
}
418
}
419
}
420
421
impl TryStableInterpolate for Val {
422
type Error = MismatchedUnitsError;
423
424
/// # Example
425
///
426
/// ```
427
/// # use bevy_ui::Val;
428
/// # use bevy_math::TryStableInterpolate;
429
/// assert!(matches!(Val::Px(0.0).try_interpolate_stable(&Val::Px(10.0), 0.5), Ok(Val::Px(5.0))));
430
/// ```
431
fn try_interpolate_stable(&self, other: &Self, t: f32) -> Result<Self, Self::Error> {
432
match (self, other) {
433
(Val::Px(a), Val::Px(b)) => Ok(Val::Px(a.interpolate_stable(b, t))),
434
(Val::Percent(a), Val::Percent(b)) => Ok(Val::Percent(a.interpolate_stable(b, t))),
435
(Val::Vw(a), Val::Vw(b)) => Ok(Val::Vw(a.interpolate_stable(b, t))),
436
(Val::Vh(a), Val::Vh(b)) => Ok(Val::Vh(a.interpolate_stable(b, t))),
437
(Val::VMin(a), Val::VMin(b)) => Ok(Val::VMin(a.interpolate_stable(b, t))),
438
(Val::VMax(a), Val::VMax(b)) => Ok(Val::VMax(a.interpolate_stable(b, t))),
439
(Val::Auto, Val::Auto) => Ok(Val::Auto),
440
_ => Err(MismatchedUnitsError),
441
}
442
}
443
}
444
445
/// All the types that should be able to be used in the [`Val`] enum should implement this trait.
446
///
447
/// Instead of just implementing `Into<Val>` a custom trait is added.
448
/// This is done in order to prevent having to define a default unit, which could lead to confusion especially for newcomers.
449
pub trait ValNum {
450
/// Called by the [`Val`] helper functions to convert the implementing type to an `f32` that can
451
/// be used by [`Val`].
452
fn val_num_f32(self) -> f32;
453
}
454
455
macro_rules! impl_to_val_num {
456
($($impl_type:ty),*$(,)?) => {
457
$(
458
impl ValNum for $impl_type {
459
fn val_num_f32(self) -> f32 {
460
self as f32
461
}
462
}
463
)*
464
};
465
}
466
467
impl_to_val_num!(f32, f64, i8, i16, i32, i64, u8, u16, u32, u64, usize, isize);
468
469
/// Returns a [`Val::Auto`] where the value is automatically determined
470
/// based on the context and other [`Node`](crate::Node) properties.
471
pub const fn auto() -> Val {
472
Val::Auto
473
}
474
475
/// Returns a [`Val::Px`] representing a value in logical pixels.
476
pub fn px<T: ValNum>(value: T) -> Val {
477
Val::Px(value.val_num_f32())
478
}
479
480
/// Returns a [`Val::Percent`] representing a percentage of the parent node's length
481
/// along a specific axis.
482
///
483
/// If the UI node has no parent, the percentage is based on the window's length
484
/// along that axis.
485
///
486
/// Axis rules:
487
/// * For `flex_basis`, the percentage is relative to the main-axis length determined by the `flex_direction`.
488
/// * For `gap`, `min_size`, `size`, and `max_size`:
489
/// - `width` is relative to the parent's width.
490
/// - `height` is relative to the parent's height.
491
/// * For `margin`, `padding`, and `border` values: the percentage is relative to the parent's width.
492
/// * For positions, `left` and `right` are relative to the parent's width, while `bottom` and `top` are relative to the parent's height.
493
pub fn percent<T: ValNum>(value: T) -> Val {
494
Val::Percent(value.val_num_f32())
495
}
496
497
/// Returns a [`Val::Vw`] representing a percentage of the viewport width.
498
pub fn vw<T: ValNum>(value: T) -> Val {
499
Val::Vw(value.val_num_f32())
500
}
501
502
/// Returns a [`Val::Vh`] representing a percentage of the viewport height.
503
pub fn vh<T: ValNum>(value: T) -> Val {
504
Val::Vh(value.val_num_f32())
505
}
506
507
/// Returns a [`Val::VMin`] representing a percentage of the viewport's smaller dimension.
508
pub fn vmin<T: ValNum>(value: T) -> Val {
509
Val::VMin(value.val_num_f32())
510
}
511
512
/// Returns a [`Val::VMax`] representing a percentage of the viewport's larger dimension.
513
pub fn vmax<T: ValNum>(value: T) -> Val {
514
Val::VMax(value.val_num_f32())
515
}
516
517
/// A type which is commonly used to define margins, paddings and borders.
518
///
519
/// # Examples
520
///
521
/// ## Margin
522
///
523
/// A margin is used to create space around UI elements, outside of any defined borders.
524
///
525
/// ```
526
/// # use bevy_ui::{UiRect, Val};
527
/// #
528
/// let margin = UiRect::all(Val::Auto); // Centers the UI element
529
/// ```
530
///
531
/// ## Padding
532
///
533
/// A padding is used to create space around UI elements, inside of any defined borders.
534
///
535
/// ```
536
/// # use bevy_ui::{UiRect, Val};
537
/// #
538
/// let padding = UiRect {
539
/// left: Val::Px(10.0),
540
/// right: Val::Px(20.0),
541
/// top: Val::Px(30.0),
542
/// bottom: Val::Px(40.0),
543
/// };
544
/// ```
545
///
546
/// ## Borders
547
///
548
/// A border is used to define the width of the border of a UI element.
549
///
550
/// ```
551
/// # use bevy_ui::{UiRect, Val};
552
/// #
553
/// let border = UiRect {
554
/// left: Val::Px(10.0),
555
/// right: Val::Px(20.0),
556
/// top: Val::Px(30.0),
557
/// bottom: Val::Px(40.0),
558
/// };
559
/// ```
560
#[derive(Copy, Clone, PartialEq, Debug, Reflect)]
561
#[reflect(Default, PartialEq, Debug, Clone)]
562
#[cfg_attr(
563
feature = "serialize",
564
derive(serde::Serialize, serde::Deserialize),
565
reflect(Serialize, Deserialize)
566
)]
567
pub struct UiRect {
568
/// The value corresponding to the left side of the UI rect.
569
pub left: Val,
570
/// The value corresponding to the right side of the UI rect.
571
pub right: Val,
572
/// The value corresponding to the top side of the UI rect.
573
pub top: Val,
574
/// The value corresponding to the bottom side of the UI rect.
575
pub bottom: Val,
576
}
577
578
impl UiRect {
579
pub const DEFAULT: Self = Self::all(Val::ZERO);
580
pub const ZERO: Self = Self::all(Val::ZERO);
581
pub const AUTO: Self = Self::all(Val::Auto);
582
583
/// Creates a new [`UiRect`] from the values specified.
584
///
585
/// # Example
586
///
587
/// ```
588
/// # use bevy_ui::{UiRect, Val};
589
/// #
590
/// let ui_rect = UiRect::new(
591
/// Val::Px(10.0),
592
/// Val::Px(20.0),
593
/// Val::Px(30.0),
594
/// Val::Px(40.0),
595
/// );
596
///
597
/// assert_eq!(ui_rect.left, Val::Px(10.0));
598
/// assert_eq!(ui_rect.right, Val::Px(20.0));
599
/// assert_eq!(ui_rect.top, Val::Px(30.0));
600
/// assert_eq!(ui_rect.bottom, Val::Px(40.0));
601
/// ```
602
pub const fn new(left: Val, right: Val, top: Val, bottom: Val) -> Self {
603
UiRect {
604
left,
605
right,
606
top,
607
bottom,
608
}
609
}
610
611
/// Creates a new [`UiRect`] where all sides have the same value.
612
///
613
/// # Example
614
///
615
/// ```
616
/// # use bevy_ui::{UiRect, Val};
617
/// #
618
/// let ui_rect = UiRect::all(Val::Px(10.0));
619
///
620
/// assert_eq!(ui_rect.left, Val::Px(10.0));
621
/// assert_eq!(ui_rect.right, Val::Px(10.0));
622
/// assert_eq!(ui_rect.top, Val::Px(10.0));
623
/// assert_eq!(ui_rect.bottom, Val::Px(10.0));
624
/// ```
625
pub const fn all(value: Val) -> Self {
626
UiRect {
627
left: value,
628
right: value,
629
top: value,
630
bottom: value,
631
}
632
}
633
634
/// Creates a new [`UiRect`] from the values specified in logical pixels.
635
///
636
/// This is a shortcut for [`UiRect::new()`], applying [`Val::Px`] to all arguments.
637
///
638
/// # Example
639
///
640
/// ```
641
/// # use bevy_ui::{UiRect, Val};
642
/// #
643
/// let ui_rect = UiRect::px(10., 20., 30., 40.);
644
/// assert_eq!(ui_rect.left, Val::Px(10.));
645
/// assert_eq!(ui_rect.right, Val::Px(20.));
646
/// assert_eq!(ui_rect.top, Val::Px(30.));
647
/// assert_eq!(ui_rect.bottom, Val::Px(40.));
648
/// ```
649
pub const fn px(left: f32, right: f32, top: f32, bottom: f32) -> Self {
650
UiRect {
651
left: Val::Px(left),
652
right: Val::Px(right),
653
top: Val::Px(top),
654
bottom: Val::Px(bottom),
655
}
656
}
657
658
/// Creates a new [`UiRect`] from the values specified in percentages.
659
///
660
/// This is a shortcut for [`UiRect::new()`], applying [`Val::Percent`] to all arguments.
661
///
662
/// # Example
663
///
664
/// ```
665
/// # use bevy_ui::{UiRect, Val};
666
/// #
667
/// let ui_rect = UiRect::percent(5., 10., 2., 1.);
668
/// assert_eq!(ui_rect.left, Val::Percent(5.));
669
/// assert_eq!(ui_rect.right, Val::Percent(10.));
670
/// assert_eq!(ui_rect.top, Val::Percent(2.));
671
/// assert_eq!(ui_rect.bottom, Val::Percent(1.));
672
/// ```
673
pub const fn percent(left: f32, right: f32, top: f32, bottom: f32) -> Self {
674
UiRect {
675
left: Val::Percent(left),
676
right: Val::Percent(right),
677
top: Val::Percent(top),
678
bottom: Val::Percent(bottom),
679
}
680
}
681
682
/// Creates a new [`UiRect`] where `left` and `right` take the given value,
683
/// and `top` and `bottom` set to zero `Val::ZERO`.
684
///
685
/// # Example
686
///
687
/// ```
688
/// # use bevy_ui::{UiRect, Val};
689
/// #
690
/// let ui_rect = UiRect::horizontal(Val::Px(10.0));
691
///
692
/// assert_eq!(ui_rect.left, Val::Px(10.0));
693
/// assert_eq!(ui_rect.right, Val::Px(10.0));
694
/// assert_eq!(ui_rect.top, Val::ZERO);
695
/// assert_eq!(ui_rect.bottom, Val::ZERO);
696
/// ```
697
pub const fn horizontal(value: Val) -> Self {
698
Self {
699
left: value,
700
right: value,
701
..Self::DEFAULT
702
}
703
}
704
705
/// Creates a new [`UiRect`] where `top` and `bottom` take the given value,
706
/// and `left` and `right` are set to `Val::ZERO`.
707
///
708
/// # Example
709
///
710
/// ```
711
/// # use bevy_ui::{UiRect, Val};
712
/// #
713
/// let ui_rect = UiRect::vertical(Val::Px(10.0));
714
///
715
/// assert_eq!(ui_rect.left, Val::ZERO);
716
/// assert_eq!(ui_rect.right, Val::ZERO);
717
/// assert_eq!(ui_rect.top, Val::Px(10.0));
718
/// assert_eq!(ui_rect.bottom, Val::Px(10.0));
719
/// ```
720
pub const fn vertical(value: Val) -> Self {
721
Self {
722
top: value,
723
bottom: value,
724
..Self::DEFAULT
725
}
726
}
727
728
/// Creates a new [`UiRect`] where both `left` and `right` take the value of `horizontal`, and both `top` and `bottom` take the value of `vertical`.
729
///
730
/// # Example
731
///
732
/// ```
733
/// # use bevy_ui::{UiRect, Val};
734
/// #
735
/// let ui_rect = UiRect::axes(Val::Px(10.0), Val::Percent(15.0));
736
///
737
/// assert_eq!(ui_rect.left, Val::Px(10.0));
738
/// assert_eq!(ui_rect.right, Val::Px(10.0));
739
/// assert_eq!(ui_rect.top, Val::Percent(15.0));
740
/// assert_eq!(ui_rect.bottom, Val::Percent(15.0));
741
/// ```
742
pub const fn axes(horizontal: Val, vertical: Val) -> Self {
743
Self {
744
left: horizontal,
745
right: horizontal,
746
top: vertical,
747
bottom: vertical,
748
}
749
}
750
751
/// Creates a new [`UiRect`] where `left` takes the given value, and
752
/// the other fields are set to `Val::ZERO`.
753
///
754
/// # Example
755
///
756
/// ```
757
/// # use bevy_ui::{UiRect, Val};
758
/// #
759
/// let ui_rect = UiRect::left(Val::Px(10.0));
760
///
761
/// assert_eq!(ui_rect.left, Val::Px(10.0));
762
/// assert_eq!(ui_rect.right, Val::ZERO);
763
/// assert_eq!(ui_rect.top, Val::ZERO);
764
/// assert_eq!(ui_rect.bottom, Val::ZERO);
765
/// ```
766
pub const fn left(left: Val) -> Self {
767
Self {
768
left,
769
..Self::DEFAULT
770
}
771
}
772
773
/// Creates a new [`UiRect`] where `right` takes the given value,
774
/// and the other fields are set to `Val::ZERO`.
775
///
776
/// # Example
777
///
778
/// ```
779
/// # use bevy_ui::{UiRect, Val};
780
/// #
781
/// let ui_rect = UiRect::right(Val::Px(10.0));
782
///
783
/// assert_eq!(ui_rect.left, Val::ZERO);
784
/// assert_eq!(ui_rect.right, Val::Px(10.0));
785
/// assert_eq!(ui_rect.top, Val::ZERO);
786
/// assert_eq!(ui_rect.bottom, Val::ZERO);
787
/// ```
788
pub const fn right(right: Val) -> Self {
789
Self {
790
right,
791
..Self::DEFAULT
792
}
793
}
794
795
/// Creates a new [`UiRect`] where `top` takes the given value,
796
/// and the other fields are set to `Val::ZERO`.
797
///
798
/// # Example
799
///
800
/// ```
801
/// # use bevy_ui::{UiRect, Val};
802
/// #
803
/// let ui_rect = UiRect::top(Val::Px(10.0));
804
///
805
/// assert_eq!(ui_rect.left, Val::ZERO);
806
/// assert_eq!(ui_rect.right, Val::ZERO);
807
/// assert_eq!(ui_rect.top, Val::Px(10.0));
808
/// assert_eq!(ui_rect.bottom, Val::ZERO);
809
/// ```
810
pub const fn top(top: Val) -> Self {
811
Self {
812
top,
813
..Self::DEFAULT
814
}
815
}
816
817
/// Creates a new [`UiRect`] where `bottom` takes the given value,
818
/// and the other fields are set to `Val::ZERO`.
819
///
820
/// # Example
821
///
822
/// ```
823
/// # use bevy_ui::{UiRect, Val};
824
/// #
825
/// let ui_rect = UiRect::bottom(Val::Px(10.0));
826
///
827
/// assert_eq!(ui_rect.left, Val::ZERO);
828
/// assert_eq!(ui_rect.right, Val::ZERO);
829
/// assert_eq!(ui_rect.top, Val::ZERO);
830
/// assert_eq!(ui_rect.bottom, Val::Px(10.0));
831
/// ```
832
pub const fn bottom(bottom: Val) -> Self {
833
Self {
834
bottom,
835
..Self::DEFAULT
836
}
837
}
838
839
/// Returns the [`UiRect`] with its `left` field set to the given value.
840
///
841
/// # Example
842
///
843
/// ```
844
/// # use bevy_ui::{UiRect, Val};
845
/// #
846
/// let ui_rect = UiRect::all(Val::Px(20.0)).with_left(Val::Px(10.0));
847
/// assert_eq!(ui_rect.left, Val::Px(10.0));
848
/// assert_eq!(ui_rect.right, Val::Px(20.0));
849
/// assert_eq!(ui_rect.top, Val::Px(20.0));
850
/// assert_eq!(ui_rect.bottom, Val::Px(20.0));
851
/// ```
852
#[inline]
853
pub const fn with_left(mut self, left: Val) -> Self {
854
self.left = left;
855
self
856
}
857
858
/// Returns the [`UiRect`] with its `right` field set to the given value.
859
///
860
/// # Example
861
///
862
/// ```
863
/// # use bevy_ui::{UiRect, Val};
864
/// #
865
/// let ui_rect = UiRect::all(Val::Px(20.0)).with_right(Val::Px(10.0));
866
/// assert_eq!(ui_rect.left, Val::Px(20.0));
867
/// assert_eq!(ui_rect.right, Val::Px(10.0));
868
/// assert_eq!(ui_rect.top, Val::Px(20.0));
869
/// assert_eq!(ui_rect.bottom, Val::Px(20.0));
870
/// ```
871
#[inline]
872
pub const fn with_right(mut self, right: Val) -> Self {
873
self.right = right;
874
self
875
}
876
877
/// Returns the [`UiRect`] with its `top` field set to the given value.
878
///
879
/// # Example
880
///
881
/// ```
882
/// # use bevy_ui::{UiRect, Val};
883
/// #
884
/// let ui_rect = UiRect::all(Val::Px(20.0)).with_top(Val::Px(10.0));
885
/// assert_eq!(ui_rect.left, Val::Px(20.0));
886
/// assert_eq!(ui_rect.right, Val::Px(20.0));
887
/// assert_eq!(ui_rect.top, Val::Px(10.0));
888
/// assert_eq!(ui_rect.bottom, Val::Px(20.0));
889
/// ```
890
#[inline]
891
pub const fn with_top(mut self, top: Val) -> Self {
892
self.top = top;
893
self
894
}
895
896
/// Returns the [`UiRect`] with its `bottom` field set to the given value.
897
///
898
/// # Example
899
///
900
/// ```
901
/// # use bevy_ui::{UiRect, Val};
902
/// #
903
/// let ui_rect = UiRect::all(Val::Px(20.0)).with_bottom(Val::Px(10.0));
904
/// assert_eq!(ui_rect.left, Val::Px(20.0));
905
/// assert_eq!(ui_rect.right, Val::Px(20.0));
906
/// assert_eq!(ui_rect.top, Val::Px(20.0));
907
/// assert_eq!(ui_rect.bottom, Val::Px(10.0));
908
/// ```
909
#[inline]
910
pub const fn with_bottom(mut self, bottom: Val) -> Self {
911
self.bottom = bottom;
912
self
913
}
914
}
915
916
impl Default for UiRect {
917
fn default() -> Self {
918
Self::DEFAULT
919
}
920
}
921
922
impl From<Val> for UiRect {
923
fn from(value: Val) -> Self {
924
UiRect::all(value)
925
}
926
}
927
928
#[derive(Debug, Clone, Copy, PartialEq, Reflect)]
929
#[reflect(Default, Debug, PartialEq)]
930
#[cfg_attr(
931
feature = "serialize",
932
derive(serde::Serialize, serde::Deserialize),
933
reflect(Serialize, Deserialize)
934
)]
935
/// Responsive position relative to a UI node.
936
pub struct UiPosition {
937
/// Normalized anchor point
938
pub anchor: Vec2,
939
/// Responsive horizontal position relative to the anchor point
940
pub x: Val,
941
/// Responsive vertical position relative to the anchor point
942
pub y: Val,
943
}
944
945
impl Default for UiPosition {
946
fn default() -> Self {
947
Self::CENTER
948
}
949
}
950
951
impl UiPosition {
952
/// Position at the given normalized anchor point
953
pub const fn anchor(anchor: Vec2) -> Self {
954
Self {
955
anchor,
956
x: Val::ZERO,
957
y: Val::ZERO,
958
}
959
}
960
961
/// Position at the top-left corner
962
pub const TOP_LEFT: Self = Self::anchor(Vec2::new(-0.5, -0.5));
963
964
/// Position at the center of the left edge
965
pub const LEFT: Self = Self::anchor(Vec2::new(-0.5, 0.0));
966
967
/// Position at the bottom-left corner
968
pub const BOTTOM_LEFT: Self = Self::anchor(Vec2::new(-0.5, 0.5));
969
970
/// Position at the center of the top edge
971
pub const TOP: Self = Self::anchor(Vec2::new(0.0, -0.5));
972
973
/// Position at the center of the element
974
pub const CENTER: Self = Self::anchor(Vec2::new(0.0, 0.0));
975
976
/// Position at the center of the bottom edge
977
pub const BOTTOM: Self = Self::anchor(Vec2::new(0.0, 0.5));
978
979
/// Position at the top-right corner
980
pub const TOP_RIGHT: Self = Self::anchor(Vec2::new(0.5, -0.5));
981
982
/// Position at the center of the right edge
983
pub const RIGHT: Self = Self::anchor(Vec2::new(0.5, 0.0));
984
985
/// Position at the bottom-right corner
986
pub const BOTTOM_RIGHT: Self = Self::anchor(Vec2::new(0.5, 0.5));
987
988
/// Create a new position
989
pub const fn new(anchor: Vec2, x: Val, y: Val) -> Self {
990
Self { anchor, x, y }
991
}
992
993
/// Creates a position from self with the given `x` and `y` coordinates
994
pub const fn at(self, x: Val, y: Val) -> Self {
995
Self { x, y, ..self }
996
}
997
998
/// Creates a position from self with the given `x` coordinate
999
pub const fn at_x(self, x: Val) -> Self {
1000
Self { x, ..self }
1001
}
1002
1003
/// Creates a position from self with the given `y` coordinate
1004
pub const fn at_y(self, y: Val) -> Self {
1005
Self { y, ..self }
1006
}
1007
1008
/// Creates a position in logical pixels from self with the given `x` and `y` coordinates
1009
pub const fn at_px(self, x: f32, y: f32) -> Self {
1010
self.at(Val::Px(x), Val::Px(y))
1011
}
1012
1013
/// Creates a percentage position from self with the given `x` and `y` coordinates
1014
pub const fn at_percent(self, x: f32, y: f32) -> Self {
1015
self.at(Val::Percent(x), Val::Percent(y))
1016
}
1017
1018
/// Creates a position from self with the given `anchor` point
1019
pub const fn with_anchor(self, anchor: Vec2) -> Self {
1020
Self { anchor, ..self }
1021
}
1022
1023
/// Position relative to the top-left corner
1024
pub const fn top_left(x: Val, y: Val) -> Self {
1025
Self::TOP_LEFT.at(x, y)
1026
}
1027
1028
/// Position relative to the left edge
1029
pub const fn left(x: Val, y: Val) -> Self {
1030
Self::LEFT.at(x, y)
1031
}
1032
1033
/// Position relative to the bottom-left corner
1034
pub const fn bottom_left(x: Val, y: Val) -> Self {
1035
Self::BOTTOM_LEFT.at(x, y)
1036
}
1037
1038
/// Position relative to the top edge
1039
pub const fn top(x: Val, y: Val) -> Self {
1040
Self::TOP.at(x, y)
1041
}
1042
1043
/// Position relative to the center
1044
pub const fn center(x: Val, y: Val) -> Self {
1045
Self::CENTER.at(x, y)
1046
}
1047
1048
/// Position relative to the bottom edge
1049
pub const fn bottom(x: Val, y: Val) -> Self {
1050
Self::BOTTOM.at(x, y)
1051
}
1052
1053
/// Position relative to the top-right corner
1054
pub const fn top_right(x: Val, y: Val) -> Self {
1055
Self::TOP_RIGHT.at(x, y)
1056
}
1057
1058
/// Position relative to the right edge
1059
pub const fn right(x: Val, y: Val) -> Self {
1060
Self::RIGHT.at(x, y)
1061
}
1062
1063
/// Position relative to the bottom-right corner
1064
pub const fn bottom_right(x: Val, y: Val) -> Self {
1065
Self::BOTTOM_RIGHT.at(x, y)
1066
}
1067
1068
/// Resolves the `Position` into physical coordinates.
1069
pub fn resolve(
1070
self,
1071
scale_factor: f32,
1072
physical_size: Vec2,
1073
physical_target_size: Vec2,
1074
) -> Vec2 {
1075
let d = self.anchor.map(|p| if 0. < p { -1. } else { 1. });
1076
1077
physical_size * self.anchor
1078
+ d * Vec2::new(
1079
self.x
1080
.resolve(scale_factor, physical_size.x, physical_target_size)
1081
.unwrap_or(0.),
1082
self.y
1083
.resolve(scale_factor, physical_size.y, physical_target_size)
1084
.unwrap_or(0.),
1085
)
1086
}
1087
}
1088
1089
impl From<Val> for UiPosition {
1090
fn from(x: Val) -> Self {
1091
Self { x, ..default() }
1092
}
1093
}
1094
1095
impl From<(Val, Val)> for UiPosition {
1096
fn from((x, y): (Val, Val)) -> Self {
1097
Self { x, y, ..default() }
1098
}
1099
}
1100
1101
#[cfg(test)]
1102
mod tests {
1103
use crate::geometry::*;
1104
use bevy_math::vec2;
1105
1106
#[test]
1107
fn val_evaluate() {
1108
let size = 250.;
1109
let viewport_size = vec2(1000., 500.);
1110
let result = Val::Percent(80.).resolve(1., size, viewport_size).unwrap();
1111
1112
assert_eq!(result, size * 0.8);
1113
}
1114
1115
#[test]
1116
fn val_resolve_px() {
1117
let size = 250.;
1118
let viewport_size = vec2(1000., 500.);
1119
let result = Val::Px(10.).resolve(1., size, viewport_size).unwrap();
1120
1121
assert_eq!(result, 10.);
1122
1123
let result = Val::Px(10.).resolve(3., size, viewport_size).unwrap();
1124
assert_eq!(result, 30.);
1125
let result = Val::Px(10.).resolve(0.25, size, viewport_size).unwrap();
1126
assert_eq!(result, 2.5);
1127
}
1128
1129
#[test]
1130
fn val_resolve_viewport_coords() {
1131
let size = 250.;
1132
let viewport_size = vec2(500., 500.);
1133
1134
for value in (-10..10).map(|value| value as f32) {
1135
// for a square viewport there should be no difference between `Vw` and `Vh` and between `Vmin` and `Vmax`.
1136
assert_eq!(
1137
Val::Vw(value).resolve(1., size, viewport_size),
1138
Val::Vh(value).resolve(1., size, viewport_size)
1139
);
1140
assert_eq!(
1141
Val::VMin(value).resolve(1., size, viewport_size),
1142
Val::VMax(value).resolve(1., size, viewport_size)
1143
);
1144
assert_eq!(
1145
Val::VMin(value).resolve(1., size, viewport_size),
1146
Val::Vw(value).resolve(1., size, viewport_size)
1147
);
1148
}
1149
1150
let viewport_size = vec2(1000., 500.);
1151
assert_eq!(
1152
Val::Vw(100.).resolve(1., size, viewport_size).unwrap(),
1153
1000.
1154
);
1155
assert_eq!(
1156
Val::Vh(100.).resolve(1., size, viewport_size).unwrap(),
1157
500.
1158
);
1159
assert_eq!(Val::Vw(60.).resolve(1., size, viewport_size).unwrap(), 600.);
1160
assert_eq!(Val::Vh(40.).resolve(1., size, viewport_size).unwrap(), 200.);
1161
assert_eq!(
1162
Val::VMin(50.).resolve(1., size, viewport_size).unwrap(),
1163
250.
1164
);
1165
assert_eq!(
1166
Val::VMax(75.).resolve(1., size, viewport_size).unwrap(),
1167
750.
1168
);
1169
}
1170
1171
#[test]
1172
fn val_auto_is_non_evaluable() {
1173
let size = 250.;
1174
let viewport_size = vec2(1000., 500.);
1175
let resolve_auto = Val::Auto.resolve(1., size, viewport_size);
1176
1177
assert_eq!(resolve_auto, Err(ValArithmeticError::NonEvaluable));
1178
}
1179
1180
#[test]
1181
fn val_arithmetic_error_messages() {
1182
assert_eq!(
1183
format!("{}", ValArithmeticError::NonEvaluable),
1184
"the given variant of Val is not evaluable (non-numeric)"
1185
);
1186
}
1187
1188
#[test]
1189
fn val_str_parse() {
1190
assert_eq!("auto".parse::<Val>(), Ok(Val::Auto));
1191
assert_eq!("Auto".parse::<Val>(), Ok(Val::Auto));
1192
assert_eq!("AUTO".parse::<Val>(), Ok(Val::Auto));
1193
1194
assert_eq!("3px".parse::<Val>(), Ok(Val::Px(3.)));
1195
assert_eq!("3 px".parse::<Val>(), Ok(Val::Px(3.)));
1196
assert_eq!("3.5px".parse::<Val>(), Ok(Val::Px(3.5)));
1197
assert_eq!("-3px".parse::<Val>(), Ok(Val::Px(-3.)));
1198
assert_eq!("3.5 PX".parse::<Val>(), Ok(Val::Px(3.5)));
1199
1200
assert_eq!("3%".parse::<Val>(), Ok(Val::Percent(3.)));
1201
assert_eq!("3 %".parse::<Val>(), Ok(Val::Percent(3.)));
1202
assert_eq!("3.5%".parse::<Val>(), Ok(Val::Percent(3.5)));
1203
assert_eq!("-3%".parse::<Val>(), Ok(Val::Percent(-3.)));
1204
1205
assert_eq!("3vw".parse::<Val>(), Ok(Val::Vw(3.)));
1206
assert_eq!("3 vw".parse::<Val>(), Ok(Val::Vw(3.)));
1207
assert_eq!("3.5vw".parse::<Val>(), Ok(Val::Vw(3.5)));
1208
assert_eq!("-3vw".parse::<Val>(), Ok(Val::Vw(-3.)));
1209
assert_eq!("3.5 VW".parse::<Val>(), Ok(Val::Vw(3.5)));
1210
1211
assert_eq!("3vh".parse::<Val>(), Ok(Val::Vh(3.)));
1212
assert_eq!("3 vh".parse::<Val>(), Ok(Val::Vh(3.)));
1213
assert_eq!("3.5vh".parse::<Val>(), Ok(Val::Vh(3.5)));
1214
assert_eq!("-3vh".parse::<Val>(), Ok(Val::Vh(-3.)));
1215
assert_eq!("3.5 VH".parse::<Val>(), Ok(Val::Vh(3.5)));
1216
1217
assert_eq!("3vmin".parse::<Val>(), Ok(Val::VMin(3.)));
1218
assert_eq!("3 vmin".parse::<Val>(), Ok(Val::VMin(3.)));
1219
assert_eq!("3.5vmin".parse::<Val>(), Ok(Val::VMin(3.5)));
1220
assert_eq!("-3vmin".parse::<Val>(), Ok(Val::VMin(-3.)));
1221
assert_eq!("3.5 VMIN".parse::<Val>(), Ok(Val::VMin(3.5)));
1222
1223
assert_eq!("3vmax".parse::<Val>(), Ok(Val::VMax(3.)));
1224
assert_eq!("3 vmax".parse::<Val>(), Ok(Val::VMax(3.)));
1225
assert_eq!("3.5vmax".parse::<Val>(), Ok(Val::VMax(3.5)));
1226
assert_eq!("-3vmax".parse::<Val>(), Ok(Val::VMax(-3.)));
1227
assert_eq!("3.5 VMAX".parse::<Val>(), Ok(Val::VMax(3.5)));
1228
1229
assert_eq!("".parse::<Val>(), Err(ValParseError::UnitMissing));
1230
assert_eq!(
1231
"hello world".parse::<Val>(),
1232
Err(ValParseError::ValueMissing)
1233
);
1234
assert_eq!("3".parse::<Val>(), Err(ValParseError::UnitMissing));
1235
assert_eq!("3.5".parse::<Val>(), Err(ValParseError::UnitMissing));
1236
assert_eq!("3pxx".parse::<Val>(), Err(ValParseError::InvalidUnit));
1237
assert_eq!("3.5pxx".parse::<Val>(), Err(ValParseError::InvalidUnit));
1238
assert_eq!("3-3px".parse::<Val>(), Err(ValParseError::InvalidValue));
1239
assert_eq!("3.5-3px".parse::<Val>(), Err(ValParseError::InvalidValue));
1240
}
1241
1242
#[test]
1243
fn default_val_equals_const_default_val() {
1244
assert_eq!(Val::default(), Val::DEFAULT);
1245
}
1246
1247
#[test]
1248
fn uirect_default_equals_const_default() {
1249
assert_eq!(UiRect::default(), UiRect::all(Val::ZERO));
1250
assert_eq!(UiRect::default(), UiRect::DEFAULT);
1251
}
1252
1253
#[test]
1254
fn test_uirect_axes() {
1255
let x = Val::Px(1.);
1256
let y = Val::Vw(4.);
1257
let r = UiRect::axes(x, y);
1258
let h = UiRect::horizontal(x);
1259
let v = UiRect::vertical(y);
1260
1261
assert_eq!(r.top, v.top);
1262
assert_eq!(r.bottom, v.bottom);
1263
assert_eq!(r.left, h.left);
1264
assert_eq!(r.right, h.right);
1265
}
1266
1267
#[test]
1268
fn uirect_px() {
1269
let r = UiRect::px(3., 5., 20., 999.);
1270
assert_eq!(r.left, Val::Px(3.));
1271
assert_eq!(r.right, Val::Px(5.));
1272
assert_eq!(r.top, Val::Px(20.));
1273
assert_eq!(r.bottom, Val::Px(999.));
1274
}
1275
1276
#[test]
1277
fn uirect_percent() {
1278
let r = UiRect::percent(3., 5., 20., 99.);
1279
assert_eq!(r.left, Val::Percent(3.));
1280
assert_eq!(r.right, Val::Percent(5.));
1281
assert_eq!(r.top, Val::Percent(20.));
1282
assert_eq!(r.bottom, Val::Percent(99.));
1283
}
1284
1285
#[test]
1286
fn val_constructor_fns_return_correct_val_variant() {
1287
assert_eq!(auto(), Val::Auto);
1288
assert_eq!(px(0.0), Val::Px(0.0));
1289
assert_eq!(percent(0.0), Val::Percent(0.0));
1290
assert_eq!(vw(0.0), Val::Vw(0.0));
1291
assert_eq!(vh(0.0), Val::Vh(0.0));
1292
assert_eq!(vmin(0.0), Val::VMin(0.0));
1293
assert_eq!(vmax(0.0), Val::VMax(0.0));
1294
}
1295
}
1296
1297