1use egui::Rangef;
2
3#[derive(Clone, Debug, Copy)]
5pub enum Size {
6 Absolute { initial: f32, range: Rangef },
8
9 Relative { fraction: f32, range: Rangef },
11
12 Remainder { range: Rangef },
14}
15
16impl Size {
17 pub fn exact(points: f32) -> Self {
19 Self::Absolute {
20 initial: points,
21 range: Rangef::new(points, points),
22 }
23 }
24
25 pub fn initial(points: f32) -> Self {
27 Self::Absolute {
28 initial: points,
29 range: Rangef::new(0.0, f32::INFINITY),
30 }
31 }
32
33 pub fn relative(fraction: f32) -> Self {
35 debug_assert!(0.0 <= fraction && fraction <= 1.0);
36 Self::Relative {
37 fraction,
38 range: Rangef::new(0.0, f32::INFINITY),
39 }
40 }
41
42 pub fn remainder() -> Self {
44 Self::Remainder {
45 range: Rangef::new(0.0, f32::INFINITY),
46 }
47 }
48
49 #[inline]
51 pub fn at_least(mut self, minimum: f32) -> Self {
52 self.range_mut().min = minimum;
53 self
54 }
55
56 #[inline]
58 pub fn at_most(mut self, maximum: f32) -> Self {
59 self.range_mut().max = maximum;
60 self
61 }
62
63 #[inline]
64 pub fn with_range(mut self, range: Rangef) -> Self {
65 *self.range_mut() = range;
66 self
67 }
68
69 pub fn range(self) -> Rangef {
71 match self {
72 Self::Absolute { range, .. }
73 | Self::Relative { range, .. }
74 | Self::Remainder { range, .. } => range,
75 }
76 }
77
78 pub fn range_mut(&mut self) -> &mut Rangef {
79 match self {
80 Self::Absolute { range, .. }
81 | Self::Relative { range, .. }
82 | Self::Remainder { range, .. } => range,
83 }
84 }
85
86 #[inline]
87 pub fn is_absolute(&self) -> bool {
88 matches!(self, Self::Absolute { .. })
89 }
90
91 #[inline]
92 pub fn is_relative(&self) -> bool {
93 matches!(self, Self::Relative { .. })
94 }
95
96 #[inline]
97 pub fn is_remainder(&self) -> bool {
98 matches!(self, Self::Remainder { .. })
99 }
100}
101
102#[derive(Clone, Default)]
103pub struct Sizing {
104 pub(crate) sizes: Vec<Size>,
105}
106
107impl Sizing {
108 pub fn add(&mut self, size: Size) {
109 self.sizes.push(size);
110 }
111
112 pub fn to_lengths(&self, length: f32, spacing: f32) -> Vec<f32> {
113 if self.sizes.is_empty() {
114 return vec![];
115 }
116
117 let mut num_remainders = 0;
118 let sum_non_remainder = self
119 .sizes
120 .iter()
121 .map(|&size| match size {
122 Size::Absolute { initial, .. } => initial,
123 Size::Relative { fraction, range } => {
124 assert!(0.0 <= fraction && fraction <= 1.0);
125 range.clamp(length * fraction)
126 }
127 Size::Remainder { .. } => {
128 num_remainders += 1;
129 0.0
130 }
131 })
132 .sum::<f32>()
133 + spacing * (self.sizes.len() - 1) as f32;
134
135 let avg_remainder_length = if num_remainders == 0 {
136 0.0
137 } else {
138 let mut remainder_length = length - sum_non_remainder;
139 let avg_remainder_length = 0.0f32.max(remainder_length / num_remainders as f32).floor();
140 for &size in &self.sizes {
141 if let Size::Remainder { range } = size {
142 if avg_remainder_length < range.min {
143 remainder_length -= range.min;
144 num_remainders -= 1;
145 }
146 }
147 }
148 if num_remainders > 0 {
149 0.0f32.max(remainder_length / num_remainders as f32)
150 } else {
151 0.0
152 }
153 };
154
155 self.sizes
156 .iter()
157 .map(|&size| match size {
158 Size::Absolute { initial, .. } => initial,
159 Size::Relative { fraction, range } => range.clamp(length * fraction),
160 Size::Remainder { range } => range.clamp(avg_remainder_length),
161 })
162 .collect()
163 }
164}
165
166impl From<Vec<Size>> for Sizing {
167 fn from(sizes: Vec<Size>) -> Self {
168 Self { sizes }
169 }
170}
171
172#[test]
173fn test_sizing() {
174 let sizing: Sizing = vec![].into();
175 assert_eq!(sizing.to_lengths(50.0, 0.0), Vec::<f32>::new());
176
177 let sizing: Sizing = vec![Size::remainder().at_least(20.0), Size::remainder()].into();
178 assert_eq!(sizing.to_lengths(50.0, 0.0), vec![25.0, 25.0]);
179 assert_eq!(sizing.to_lengths(30.0, 0.0), vec![20.0, 10.0]);
180 assert_eq!(sizing.to_lengths(20.0, 0.0), vec![20.0, 0.0]);
181 assert_eq!(sizing.to_lengths(10.0, 0.0), vec![20.0, 0.0]);
182 assert_eq!(sizing.to_lengths(20.0, 10.0), vec![20.0, 0.0]);
183 assert_eq!(sizing.to_lengths(30.0, 10.0), vec![20.0, 0.0]);
184 assert_eq!(sizing.to_lengths(40.0, 10.0), vec![20.0, 10.0]);
185 assert_eq!(sizing.to_lengths(110.0, 10.0), vec![50.0, 50.0]);
186
187 let sizing: Sizing = vec![Size::relative(0.5).at_least(10.0), Size::exact(10.0)].into();
188 assert_eq!(sizing.to_lengths(50.0, 0.0), vec![25.0, 10.0]);
189 assert_eq!(sizing.to_lengths(30.0, 0.0), vec![15.0, 10.0]);
190 assert_eq!(sizing.to_lengths(20.0, 0.0), vec![10.0, 10.0]);
191 assert_eq!(sizing.to_lengths(10.0, 0.0), vec![10.0, 10.0]);
192}