1use std::fmt;
2
3use bitflags::bitflags;
4use zng_var::{animation::Transitionable, impl_from_and_into_var};
5
6use super::{FactorUnits, Px, PxSize, euclid};
7
8pub use euclid::BoolVector2D;
9
10bitflags! {
11 #[derive(Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, Debug)]
12 struct PxConstraintsFlags: u8 {
13 const FILL = 0b0000_0001;
14 const INNER = 0b0000_0010;
15 }
16}
17impl Transitionable for PxConstraintsFlags {
18 fn lerp(self, to: &Self, step: zng_var::animation::easing::EasingStep) -> Self {
19 if step >= 1.fct() { *to } else { self }
20 }
21}
22
23#[derive(Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, Transitionable)]
29pub struct PxConstraints {
30 #[serde(with = "serde_constraints_max")]
31 #[serde(default = "serde_constraints_max_default")]
32 max: Px,
33 min: Px,
34
35 flags: PxConstraintsFlags,
36}
37impl fmt::Debug for PxConstraints {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 if f.alternate() {
40 f.debug_struct("PxConstraints")
41 .field("max", &self.max)
42 .field("min", &self.min)
43 .field("flags", &self.flags)
44 .finish()
45 } else {
46 write!(f, "{{ ")?;
47 let mut sep = "";
48 if self.min > Px(0) {
49 write!(f, "min: {}", self.min)?;
50 sep = ", ";
51 }
52 if self.max < Px::MAX {
53 write!(f, "{sep}max: {}", self.max)?;
54 sep = ", ";
55 }
56 if self.is_fill() {
57 write!(f, "{sep}is_fill")?;
58 sep = ", ";
59 }
60 if self.is_inner() {
61 write!(f, "{sep}is_inner")?;
62 }
63 write!(f, " }}")
64 }
65 }
66}
67impl PxConstraints {
68 pub fn new_unbounded() -> Self {
70 PxConstraints {
71 max: Px::MAX,
72 min: Px(0),
73 flags: PxConstraintsFlags::empty(),
74 }
75 }
76
77 pub fn new_bounded(max: Px) -> Self {
79 PxConstraints {
80 max,
81 min: Px(0),
82 flags: PxConstraintsFlags::empty(),
83 }
84 }
85
86 pub fn new_exact(length: Px) -> Self {
88 PxConstraints {
89 max: length,
90 min: length,
91 flags: PxConstraintsFlags::FILL,
92 }
93 }
94
95 pub fn new_fill(length: Px) -> Self {
97 PxConstraints {
98 max: length,
99 min: Px(0),
100 flags: PxConstraintsFlags::FILL,
101 }
102 }
103
104 pub fn new_range(min: Px, max: Px) -> Self {
110 assert!(min <= max);
111
112 PxConstraints {
113 max,
114 min,
115 flags: PxConstraintsFlags::empty(),
116 }
117 }
118
119 pub fn with_new_min(mut self, min: Px) -> Self {
121 self.min = min;
122 self.max = self.max.max(self.min);
123 self
124 }
125
126 pub fn with_min(self, min: Px) -> Self {
130 if min > self.min { self.with_new_min(min) } else { self }
131 }
132
133 pub fn with_new_max(mut self, max: Px) -> Self {
135 self.max = max;
136 self.min = self.min.min(self.max);
137 self
138 }
139
140 pub fn with_max(self, max: Px) -> Self {
144 if max < self.max { self.with_new_max(max) } else { self }
145 }
146
147 pub fn with_new_exact(mut self, len: Px) -> Self {
149 self.max = len;
150 self.min = len;
151 self.flags = PxConstraintsFlags::FILL;
152 self
153 }
154
155 pub fn with_exact(self, len: Px) -> Self {
159 self.with_new_exact(self.clamp(len))
160 }
161
162 pub fn with_fill(mut self, fill: bool) -> Self {
166 self.flags.set(PxConstraintsFlags::FILL, fill);
167 self
168 }
169
170 pub fn with_inner(mut self, inner: bool) -> Self {
174 self.flags.set(PxConstraintsFlags::INNER, inner);
175 self
176 }
177
178 pub fn with_fill_and(mut self, fill: bool) -> Self {
180 let fill = self.is_fill() && fill;
181 self.flags.set(PxConstraintsFlags::FILL, fill);
182 self
183 }
184
185 pub fn with_unbounded(mut self) -> Self {
187 self.max = Px::MAX;
188 self
189 }
190
191 pub fn with_less(mut self, sub: Px) -> Self {
195 if self.max < Px::MAX {
196 self.max -= sub;
197 self.max = self.max.max(Px(0));
198 }
199 self.min -= sub;
200 self.min = self.min.max(Px(0));
201 self
202 }
203
204 pub fn with_more(mut self, add: Px) -> Self {
208 self.max.0 = self.max.0.saturating_add(add.0);
209 self
210 }
211
212 pub fn is_bounded(self) -> bool {
214 self.max != Px::MAX
215 }
216
217 pub fn is_unbounded(self) -> bool {
219 self.max == Px::MAX
220 }
221
222 pub fn is_exact(self) -> bool {
224 self.max == self.min
225 }
226
227 pub fn is_fill(self) -> bool {
231 self.flags.contains(PxConstraintsFlags::FILL)
232 }
233
234 pub fn is_fill_max(self) -> bool {
236 self.is_fill() && !self.is_unbounded()
237 }
238
239 pub fn is_inner(self) -> bool {
247 self.flags.contains(PxConstraintsFlags::INNER)
248 }
249
250 pub fn exact(self) -> Option<Px> {
252 if self.is_exact() { Some(self.max) } else { None }
253 }
254
255 pub fn max(self) -> Option<Px> {
259 if self.max < Px::MAX { Some(self.max) } else { None }
260 }
261
262 pub fn min(self) -> Px {
266 self.min
267 }
268
269 pub fn max_bounded(self) -> Px {
271 if self.max < Px::MAX { self.max } else { self.min }
272 }
273
274 pub fn clamp(self, px: Px) -> Px {
276 self.min.max(px).min(self.max)
277 }
278
279 pub fn fill(self) -> Px {
283 if self.is_fill_max() { self.max } else { self.min }
284 }
285
286 pub fn fill_or(self, length: Px) -> Px {
288 if self.is_fill_max() { self.max } else { self.clamp(length) }
289 }
290
291 pub fn fill_or_exact(self) -> Option<Px> {
293 if self.is_fill_max() || self.is_exact() {
294 Some(self.max)
295 } else {
296 None
297 }
298 }
299
300 pub fn max_or(self, length: Px) -> Px {
302 if self.is_unbounded() { self.clamp(length) } else { self.max }
303 }
304
305 pub fn inner(self) -> Self {
313 if self.is_inner() { PxConstraints::new_unbounded() } else { self }
314 }
315}
316impl_from_and_into_var! {
317 fn from(length: Px) -> PxConstraints {
319 PxConstraints::new_exact(length)
320 }
321}
322impl Default for PxConstraints {
323 fn default() -> Self {
324 Self::new_unbounded()
325 }
326}
327mod serde_constraints_max {
328 use super::Px;
329 use serde::*;
330 pub fn serialize<S: Serializer>(max: &Px, serializer: S) -> Result<S::Ok, S::Error> {
331 if serializer.is_human_readable() {
332 let px = if *max == Px::MAX { None } else { Some(*max) };
333 px.serialize(serializer)
334 } else {
335 max.serialize(serializer)
336 }
337 }
338
339 pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Px, D::Error> {
340 if deserializer.is_human_readable() {
341 Ok(Option::<Px>::deserialize(deserializer)?.unwrap_or(Px::MAX))
342 } else {
343 Px::deserialize(deserializer)
344 }
345 }
346}
347fn serde_constraints_max_default() -> Px {
348 Px::MAX
349}
350
351#[derive(Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, Transitionable)]
356pub struct PxConstraints2d {
357 pub x: PxConstraints,
359 pub y: PxConstraints,
361}
362
363impl fmt::Debug for PxConstraints2d {
364 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365 if f.alternate() {
366 f.debug_struct("PxConstraints2d").field("x", &self.x).field("y", &self.y).finish()
367 } else if self.x == self.y {
368 fmt::Debug::fmt(&self.x, f)
369 } else {
370 write!(f, "{{ ")?;
371 let mut sep = "";
372 if self.x.min > Px(0) || self.y.min > Px(0) {
373 write!(f, "min: ({}, {})", self.x.min, self.y.min)?;
374 sep = ", ";
375 }
376 if self.x.max < Px::MAX || self.y.max < Px::MAX {
377 struct M(Px);
378 impl fmt::Display for M {
379 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380 if self.0 == Px::MAX {
381 write!(f, "_")
382 } else {
383 fmt::Display::fmt(&self.0, f)
384 }
385 }
386 }
387 write!(f, "{sep}max: ({}, {})", M(self.x.max), M(self.y.max))?;
388 sep = ", ";
389 }
390 if self.is_fill().any() {
391 write!(f, "{sep}is_fill: ({}, {})", self.x.is_fill(), self.y.is_fill())?;
392 sep = ", ";
393 }
394 if self.is_inner().any() {
395 write!(f, "{sep}is_inner: ({}, {})", self.x.is_inner(), self.y.is_inner())?
396 }
397 write!(f, " }}")
398 }
399 }
400}
401impl PxConstraints2d {
402 pub fn new_unbounded() -> Self {
404 Self {
405 x: PxConstraints::new_unbounded(),
406 y: PxConstraints::new_unbounded(),
407 }
408 }
409
410 pub fn new_bounded(max_x: Px, max_y: Px) -> Self {
412 Self {
413 x: PxConstraints::new_bounded(max_x),
414 y: PxConstraints::new_bounded(max_y),
415 }
416 }
417
418 pub fn new_bounded_size(max: PxSize) -> Self {
420 Self::new_bounded(max.width, max.height)
421 }
422
423 pub fn new_exact(x: Px, y: Px) -> Self {
427 Self {
428 x: PxConstraints::new_exact(x),
429 y: PxConstraints::new_exact(y),
430 }
431 }
432
433 pub fn new_exact_size(size: PxSize) -> Self {
435 Self::new_exact(size.width, size.height)
436 }
437
438 pub fn new_fill(x: Px, y: Px) -> Self {
440 Self {
441 x: PxConstraints::new_fill(x),
442 y: PxConstraints::new_fill(y),
443 }
444 }
445
446 pub fn new_fill_size(size: PxSize) -> Self {
448 Self::new_fill(size.width, size.height)
449 }
450
451 pub fn new_range(min_x: Px, max_x: Px, min_y: Px, max_y: Px) -> Self {
459 Self {
460 x: PxConstraints::new_range(min_x, max_x),
461 y: PxConstraints::new_range(min_y, max_y),
462 }
463 }
464
465 pub fn with_new_min(mut self, min_x: Px, min_y: Px) -> Self {
468 self.x = self.x.with_new_min(min_x);
469 self.y = self.y.with_new_min(min_y);
470 self
471 }
472
473 pub fn with_min(mut self, min_x: Px, min_y: Px) -> Self {
476 self.x = self.x.with_min(min_x);
477 self.y = self.y.with_min(min_y);
478 self
479 }
480
481 pub fn with_new_min_size(self, min: PxSize) -> Self {
484 self.with_new_min(min.width, min.height)
485 }
486
487 pub fn with_min_size(self, min: PxSize) -> Self {
490 self.with_min(min.width, min.height)
491 }
492
493 pub fn with_new_min_x(mut self, min_x: Px) -> Self {
496 self.x = self.x.with_new_min(min_x);
497 self
498 }
499
500 pub fn with_new_min_y(mut self, min_y: Px) -> Self {
503 self.y = self.y.with_new_min(min_y);
504 self
505 }
506
507 pub fn with_min_x(mut self, min_x: Px) -> Self {
510 self.x = self.x.with_min(min_x);
511 self
512 }
513
514 pub fn with_min_y(mut self, min_y: Px) -> Self {
517 self.y = self.y.with_min(min_y);
518 self
519 }
520
521 pub fn with_new_max(mut self, max_x: Px, max_y: Px) -> Self {
524 self.x = self.x.with_new_max(max_x);
525 self.y = self.y.with_new_max(max_y);
526 self
527 }
528
529 pub fn with_max(mut self, max_x: Px, max_y: Px) -> Self {
532 self.x = self.x.with_max(max_x);
533 self.y = self.y.with_max(max_y);
534 self
535 }
536
537 pub fn with_new_max_size(self, max: PxSize) -> Self {
540 self.with_new_max(max.width, max.height)
541 }
542
543 pub fn with_max_size(self, max: PxSize) -> Self {
546 self.with_max(max.width, max.height)
547 }
548
549 pub fn with_new_max_x(mut self, max_x: Px) -> Self {
552 self.x = self.x.with_new_max(max_x);
553 self
554 }
555
556 pub fn with_new_max_y(mut self, max_y: Px) -> Self {
559 self.y = self.y.with_new_max(max_y);
560 self
561 }
562
563 pub fn with_max_x(mut self, max_x: Px) -> Self {
566 self.x = self.x.with_max(max_x);
567 self
568 }
569
570 pub fn with_max_y(mut self, max_y: Px) -> Self {
573 self.y = self.y.with_max(max_y);
574 self
575 }
576
577 pub fn with_new_exact(mut self, x: Px, y: Px) -> Self {
579 self.x = self.x.with_new_exact(x);
580 self.y = self.y.with_new_exact(y);
581 self
582 }
583
584 pub fn with_exact(mut self, x: Px, y: Px) -> Self {
586 self.x = self.x.with_exact(x);
587 self.y = self.y.with_exact(y);
588 self
589 }
590
591 pub fn with_new_exact_size(self, size: PxSize) -> Self {
593 self.with_new_exact(size.width, size.height)
594 }
595
596 pub fn with_exact_size(self, size: PxSize) -> Self {
598 self.with_exact(size.width, size.height)
599 }
600
601 pub fn with_new_exact_x(mut self, x: Px) -> Self {
603 self.x = self.x.with_new_exact(x);
604 self
605 }
606
607 pub fn with_new_exact_y(mut self, y: Px) -> Self {
609 self.y = self.y.with_new_exact(y);
610 self
611 }
612
613 pub fn with_exact_x(mut self, x: Px) -> Self {
616 self.x = self.x.with_exact(x);
617 self
618 }
619
620 pub fn with_exact_y(mut self, y: Px) -> Self {
623 self.y = self.y.with_exact(y);
624 self
625 }
626
627 pub fn with_fill(mut self, fill_x: bool, fill_y: bool) -> Self {
629 self.x = self.x.with_fill(fill_x);
630 self.y = self.y.with_fill(fill_y);
631 self
632 }
633
634 pub fn with_inner(mut self, inner_x: bool, inner_y: bool) -> Self {
638 self.x = self.x.with_inner(inner_x);
639 self.y = self.y.with_inner(inner_y);
640 self
641 }
642
643 pub fn with_fill_and(mut self, fill_x: bool, fill_y: bool) -> Self {
645 self.x = self.x.with_fill_and(fill_x);
646 self.y = self.y.with_fill_and(fill_y);
647 self
648 }
649
650 pub fn with_fill_vector(self, fill: BoolVector2D) -> Self {
652 self.with_fill(fill.x, fill.y)
653 }
654
655 pub fn with_fill_x(mut self, fill_x: bool) -> Self {
657 self.x = self.x.with_fill(fill_x);
658 self
659 }
660
661 pub fn with_fill_y(mut self, fill_y: bool) -> Self {
663 self.y = self.y.with_fill(fill_y);
664 self
665 }
666
667 pub fn with_unbounded(mut self) -> Self {
669 self.x = self.x.with_unbounded();
670 self.y = self.y.with_unbounded();
671 self
672 }
673
674 pub fn with_unbounded_x(mut self) -> Self {
676 self.x = self.x.with_unbounded();
677 self
678 }
679
680 pub fn with_unbounded_y(mut self) -> Self {
682 self.y = self.y.with_unbounded();
683 self
684 }
685
686 pub fn with_less(mut self, sub_x: Px, sub_y: Px) -> Self {
690 self.x = self.x.with_less(sub_x);
691 self.y = self.y.with_less(sub_y);
692 self
693 }
694
695 pub fn with_less_size(self, sub: PxSize) -> Self {
699 self.with_less(sub.width, sub.height)
700 }
701
702 pub fn with_less_x(mut self, sub_x: Px) -> Self {
706 self.x = self.x.with_less(sub_x);
707 self
708 }
709
710 pub fn with_less_y(mut self, sub_y: Px) -> Self {
714 self.y = self.y.with_less(sub_y);
715 self
716 }
717
718 pub fn with_more(mut self, add_x: Px, add_y: Px) -> Self {
722 self.x = self.x.with_more(add_x);
723 self.y = self.y.with_more(add_y);
724 self
725 }
726
727 pub fn with_more_size(self, add: PxSize) -> Self {
731 self.with_more(add.width, add.height)
732 }
733
734 pub fn with_x(mut self, x: impl FnOnce(PxConstraints) -> PxConstraints) -> Self {
738 self.x = x(self.x);
739 self
740 }
741
742 pub fn with_y(mut self, y: impl FnOnce(PxConstraints) -> PxConstraints) -> Self {
746 self.y = y(self.y);
747 self
748 }
749
750 pub fn is_bounded(self) -> BoolVector2D {
752 BoolVector2D {
753 x: self.x.is_bounded(),
754 y: self.y.is_bounded(),
755 }
756 }
757
758 pub fn is_unbounded(self) -> BoolVector2D {
760 BoolVector2D {
761 x: self.x.is_unbounded(),
762 y: self.y.is_unbounded(),
763 }
764 }
765
766 pub fn is_exact(self) -> BoolVector2D {
768 BoolVector2D {
769 x: self.x.is_exact(),
770 y: self.y.is_exact(),
771 }
772 }
773
774 pub fn is_fill(self) -> BoolVector2D {
778 BoolVector2D {
779 x: self.x.is_fill(),
780 y: self.y.is_fill(),
781 }
782 }
783
784 pub fn is_fill_max(self) -> BoolVector2D {
786 BoolVector2D {
787 x: self.x.is_fill_max(),
788 y: self.y.is_fill_max(),
789 }
790 }
791
792 pub fn is_inner(self) -> BoolVector2D {
800 BoolVector2D {
801 x: self.x.is_inner(),
802 y: self.y.is_inner(),
803 }
804 }
805
806 pub fn fixed_size(self) -> Option<PxSize> {
808 Some(PxSize::new(self.x.exact()?, self.y.exact()?))
809 }
810
811 pub fn max_size(self) -> Option<PxSize> {
815 Some(PxSize::new(self.x.max()?, self.y.max()?))
816 }
817
818 pub fn min_size(self) -> PxSize {
822 PxSize::new(self.x.min(), self.y.min())
823 }
824
825 pub fn clamp_size(self, size: PxSize) -> PxSize {
827 PxSize::new(self.x.clamp(size.width), self.y.clamp(size.height))
828 }
829
830 pub fn fill_size(self) -> PxSize {
834 PxSize::new(self.x.fill(), self.y.fill())
835 }
836
837 pub fn fill_size_or(self, size: PxSize) -> PxSize {
839 PxSize::new(self.x.fill_or(size.width), self.y.fill_or(size.height))
840 }
841
842 pub fn fill_or_exact(self) -> Option<PxSize> {
844 Some(PxSize::new(self.x.fill_or_exact()?, self.y.fill_or_exact()?))
845 }
846
847 pub fn max_size_or(self, size: PxSize) -> PxSize {
849 PxSize::new(self.x.max_or(size.width), self.y.max_or(size.height))
850 }
851
852 pub fn max_bounded_size(self) -> PxSize {
854 PxSize::new(self.x.max_bounded(), self.y.max_bounded())
855 }
856
857 pub fn fill_ratio(self, size: PxSize) -> PxSize {
859 if size.width == Px(0) || size.height == Px(0) {
860 return self.fill_size_or(size);
861 }
862
863 if self.x.is_unbounded() {
864 if self.y.is_unbounded() {
865 let container = size.max(self.min_size()).to_f32();
867 let content = size.to_f32();
868 let scale = (container.width / content.width).max(container.height / content.height).fct();
869 size * scale
870 } else {
871 let height = self.y.fill_or(size.height.max(self.y.min));
873 let scale = (height.0 as f32 / size.height.0 as f32).fct();
874 PxSize::new(size.width * scale, height)
875 }
876 } else if self.y.is_unbounded() {
877 let width = self.x.fill_or(size.width.max(self.x.min));
879 let scale = (width.0 as f32 / size.width.0 as f32).fct();
880 PxSize::new(width, size.height * scale)
881 } else if self.x.is_fill() || self.y.is_fill() {
882 let container = self.fill_size_or(size).to_f32();
884 let content = size.to_f32();
885 let scale = (container.width / content.width).min(container.height / content.height).fct();
886
887 (size * scale).max(self.min_size())
888 } else {
889 let container = self.min_size().to_f32();
891 let content = size.to_f32();
892 let scale = (container.width / content.width).max(container.height / content.height).fct();
893
894 (size * scale).min(PxSize::new(self.x.max, self.y.max))
895 }
896 }
897
898 pub fn inner(self) -> Self {
906 Self {
907 x: self.x.inner(),
908 y: self.y.inner(),
909 }
910 }
911}
912impl_from_and_into_var! {
913 fn from(size: PxSize) -> PxConstraints2d {
915 PxConstraints2d::new_exact(size.width, size.height)
916 }
917
918 fn from((a, b): (PxSize, PxSize)) -> PxConstraints2d {
920 PxConstraints2d {
921 x: if a.width > b.width {
922 PxConstraints::new_range(b.width, a.width)
923 } else {
924 PxConstraints::new_range(a.width, b.width)
925 },
926 y: if a.height > b.height {
927 PxConstraints::new_range(b.height, a.height)
928 } else {
929 PxConstraints::new_range(a.height, b.height)
930 },
931 }
932 }
933}
934impl Default for PxConstraints2d {
935 fn default() -> Self {
936 Self::new_unbounded()
937 }
938}
939
940#[cfg(test)]
941mod tests {
942 use super::*;
943
944 #[test]
945 fn fill_ratio_unbounded_no_min() {
946 let constraints = PxConstraints2d::new_unbounded();
947
948 let size = PxSize::new(Px(400), Px(200));
949 let filled = constraints.fill_ratio(size);
950
951 assert_eq!(size, filled)
952 }
953
954 #[test]
955 fn fill_ratio_unbounded_with_min_x() {
956 let constraints = PxConstraints2d::new_unbounded().with_min_x(Px(800));
957
958 let size = PxSize::new(Px(400), Px(200));
959 let filled = constraints.fill_ratio(size);
960
961 assert_eq!(filled, PxSize::new(Px(800), Px(400)))
962 }
963
964 #[test]
965 fn fill_ratio_unbounded_with_min_y() {
966 let constraints = PxConstraints2d::new_unbounded().with_min_y(Px(400));
967
968 let size = PxSize::new(Px(400), Px(200));
969 let filled = constraints.fill_ratio(size);
970
971 assert_eq!(filled, PxSize::new(Px(800), Px(400)))
972 }
973
974 #[test]
975 fn fill_ratio_bounded_x() {
976 let constraints = PxConstraints2d::new_fill(Px(800), Px::MAX);
977
978 let size = PxSize::new(Px(400), Px(200));
979 let filled = constraints.fill_ratio(size);
980
981 assert_eq!(filled, PxSize::new(Px(800), Px(400)))
982 }
983
984 #[test]
985 fn fill_ratio_bounded_y() {
986 let constraints = PxConstraints2d::new_fill(Px::MAX, Px(400));
987
988 let size = PxSize::new(Px(400), Px(200));
989 let filled = constraints.fill_ratio(size);
990
991 assert_eq!(filled, PxSize::new(Px(800), Px(400)))
992 }
993
994 #[test]
995 fn fill_ratio_bounded1() {
996 let constraints = PxConstraints2d::new_fill(Px(800), Px(400));
997
998 let size = PxSize::new(Px(400), Px(200));
999 let filled = constraints.fill_ratio(size);
1000
1001 assert_eq!(filled, PxSize::new(Px(800), Px(400)))
1002 }
1003
1004 #[test]
1005 fn fill_ratio_bounded2() {
1006 let constraints = PxConstraints2d::new_fill(Px(400), Px(400));
1007
1008 let size = PxSize::new(Px(400), Px(200));
1009 let filled = constraints.fill_ratio(size);
1010
1011 assert_eq!(filled, PxSize::new(Px(400), Px(200)))
1012 }
1013
1014 #[test]
1015 fn fill_ratio_exact() {
1016 let constraints = PxConstraints2d::new_exact(Px(123), Px(321));
1017
1018 let size = PxSize::new(Px(400), Px(200));
1019 let filled = constraints.fill_ratio(size);
1020
1021 assert_eq!(filled, PxSize::new(Px(123), Px(321)))
1022 }
1023
1024 #[test]
1025 fn fill_ratio_no_fill_bounded_with_min_x() {
1026 let constraints = PxConstraints2d::new_bounded(Px(1000), Px(1000)).with_min_x(Px(800));
1027
1028 let size = PxSize::new(Px(400), Px(200));
1029 let filled = constraints.fill_ratio(size);
1030
1031 assert_eq!(filled, PxSize::new(Px(800), Px(400)))
1032 }
1033
1034 #[test]
1035 fn fill_ratio_no_fill_bounded_with_min_y() {
1036 let constraints = PxConstraints2d::new_bounded(Px(1000), Px(1000)).with_min_y(Px(400));
1037
1038 let size = PxSize::new(Px(400), Px(200));
1039 let filled = constraints.fill_ratio(size);
1040
1041 assert_eq!(filled, PxSize::new(Px(800), Px(400)))
1042 }
1043}