1use std::{
2 fmt::Debug,
3 hash::Hash,
4 sync::Arc,
5};
6
7pub use euclid::Rect;
8
9use crate::{
10 geometry::Length,
11 measure::Phase,
12 scaled::Scaled,
13};
14
15pub struct SizeFnContext {
16 pub parent: f32,
17 pub available_parent: f32,
18 pub parent_margin: f32,
19 pub root: f32,
20 pub phase: Phase,
21}
22
23#[cfg(feature = "serde")]
24pub use serde::*;
25
26#[derive(Clone)]
27pub struct SizeFn(Arc<dyn Fn(SizeFnContext) -> Option<f32> + Sync + Send>, u64);
28
29#[cfg(feature = "serde")]
30impl Serialize for SizeFn {
31 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
32 where
33 S: Serializer,
34 {
35 serializer.serialize_str("Fn")
36 }
37}
38
39#[cfg(feature = "serde")]
40impl<'de> Deserialize<'de> for SizeFn {
41 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
42 where
43 D: Deserializer<'de>,
44 {
45 struct FnVisitor;
46 use serde::de::Visitor;
47
48 impl Visitor<'_> for FnVisitor {
49 type Value = SizeFn;
50
51 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
52 formatter.write_str("\"Fn\"")
53 }
54
55 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
56 where
57 E: de::Error,
58 {
59 if v == "Fn" {
60 Ok(SizeFn(Arc::new(|_ctx| None), 0))
61 } else {
62 Err(E::custom(format!("expected \"Fn\", got {v}")))
63 }
64 }
65 }
66
67 deserializer.deserialize_str(FnVisitor)
68 }
69}
70
71impl SizeFn {
72 pub fn new(func: impl Fn(SizeFnContext) -> Option<f32> + 'static + Sync + Send) -> Self {
73 Self(Arc::new(func), 0)
74 }
75
76 pub fn new_data<D: Hash>(
77 func: impl Fn(SizeFnContext) -> Option<f32> + 'static + Sync + Send,
78 data: &D,
79 ) -> Self {
80 use std::hash::Hasher;
81 let mut hasher = std::hash::DefaultHasher::default();
82 data.hash(&mut hasher);
83 Self(Arc::new(func), hasher.finish())
84 }
85
86 pub fn call(&self, context: SizeFnContext) -> Option<f32> {
87 (self.0)(context)
88 }
89}
90
91impl Debug for SizeFn {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 f.write_str("SizeFn")
94 }
95}
96
97impl PartialEq for SizeFn {
98 fn eq(&self, other: &Self) -> bool {
99 self.1 == other.1
100 }
101}
102
103#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
104#[derive(PartialEq, Clone, Debug)]
105pub enum Size {
106 Inner,
115
116 Fill,
125
126 FillMinimum,
135
136 Percentage(Length),
145
146 Pixels(Length),
155
156 RootPercentage(Length),
165
166 Fn(Box<SizeFn>),
170
171 Flex(Length),
180}
181
182impl Default for Size {
183 fn default() -> Self {
184 Self::Inner
185 }
186}
187
188impl Size {
189 pub fn auto() -> Size {
191 Size::Inner
192 }
193
194 pub fn fill() -> Size {
196 Size::Fill
197 }
198
199 pub fn fill_minimum() -> Size {
201 Size::FillMinimum
202 }
203
204 pub fn percent(percent: impl Into<f32>) -> Size {
206 Size::Percentage(Length::new(percent.into()))
207 }
208
209 pub fn px(px: impl Into<f32>) -> Size {
211 Size::Pixels(Length::new(px.into()))
212 }
213
214 pub fn window_percent(percent: impl Into<f32>) -> Size {
216 Size::RootPercentage(Length::new(percent.into()))
217 }
218
219 pub fn flex(flex: impl Into<f32>) -> Size {
221 Size::Flex(Length::new(flex.into()))
222 }
223
224 pub fn func(func: impl Fn(SizeFnContext) -> Option<f32> + 'static + Sync + Send) -> Size {
226 Self::Fn(Box::new(SizeFn::new(func)))
227 }
228
229 pub fn func_data<D: Hash>(
231 func: impl Fn(SizeFnContext) -> Option<f32> + 'static + Sync + Send,
232 data: &D,
233 ) -> Size {
234 Self::Fn(Box::new(SizeFn::new_data(func, data)))
235 }
236
237 pub(crate) fn flex_grow(&self) -> Option<Length> {
238 match self {
239 Self::Flex(f) => Some(*f),
240 _ => None,
241 }
242 }
243
244 pub(crate) fn is_flex(&self) -> bool {
245 matches!(self, Self::Flex(_))
246 }
247
248 pub(crate) fn inner_sized(&self) -> bool {
249 matches!(self, Self::Inner | Self::FillMinimum)
250 }
251
252 pub fn pretty(&self) -> String {
253 match self {
254 Self::Inner => "auto".to_string(),
255 Self::Pixels(s) => format!("{}", s.get()),
256 Self::Fn(_) => "Fn".to_string(),
257 Self::Percentage(p) => format!("{}%", p.get()),
258 Self::Fill => "fill".to_string(),
259 Self::FillMinimum => "fill-min".to_string(),
260 Self::RootPercentage(p) => format!("{}% of root", p.get()),
261 Self::Flex(f) => format!("flex({})", f.get()),
262 }
263 }
264
265 pub(crate) fn eval(
266 &self,
267 parent: f32,
268 available_parent: f32,
269 parent_margin: f32,
270 root: f32,
271 phase: Phase,
272 ) -> Option<f32> {
273 match self {
274 Self::Pixels(px) => Some(px.get() + parent_margin),
275 Self::Percentage(per) => Some(parent / 100.0 * per.get()),
276 Self::Fill => Some(available_parent),
277 Self::RootPercentage(per) => Some(root / 100.0 * per.get()),
278 Self::Flex(_) | Self::FillMinimum if phase == Phase::Final => Some(available_parent),
279 Self::Fn(f) => f.call(SizeFnContext {
280 parent,
281 available_parent,
282 parent_margin,
283 root,
284 phase,
285 }),
286 _ => None,
287 }
288 }
289
290 #[allow(clippy::too_many_arguments)]
291 pub(crate) fn min_max(
292 &self,
293 value: f32,
294 parent_value: f32,
295 available_parent_value: f32,
296 single_margin: f32,
297 margin: f32,
298 minimum: &Self,
299 maximum: &Self,
300 root_value: f32,
301 phase: Phase,
302 ) -> f32 {
303 let value = self
304 .eval(
305 parent_value,
306 available_parent_value,
307 margin,
308 root_value,
309 phase,
310 )
311 .unwrap_or(value + margin);
312
313 let minimum_value = minimum
314 .eval(
315 parent_value,
316 available_parent_value,
317 margin,
318 root_value,
319 phase,
320 )
321 .map(|v| v + single_margin);
322 let maximum_value = maximum.eval(
323 parent_value,
324 available_parent_value,
325 margin,
326 root_value,
327 phase,
328 );
329
330 let mut final_value = value;
331
332 if let Some(minimum_value) = minimum_value
333 && minimum_value > final_value
334 {
335 final_value = minimum_value;
336 }
337
338 if let Some(maximum_value) = maximum_value
339 && final_value > maximum_value
340 {
341 final_value = maximum_value;
342 }
343
344 final_value
345 }
346
347 pub(crate) fn most_fitting_size<'a>(&self, size: &'a f32, available_size: &'a f32) -> &'a f32 {
348 match self {
349 Self::Inner => available_size,
350 _ => size,
351 }
352 }
353}
354
355impl Scaled for Size {
356 fn scale(&mut self, scale_factor: f32) {
357 if let Self::Pixels(s) = self {
358 *s *= scale_factor;
359 }
360 }
361}