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,
107 Fill,
108 FillMinimum,
109 Percentage(Length),
110 Pixels(Length),
111 RootPercentage(Length),
112 Fn(Box<SizeFn>),
113 Flex(Length),
114}
115
116impl Default for Size {
117 fn default() -> Self {
118 Self::Inner
119 }
120}
121
122impl Size {
123 pub(crate) fn flex_grow(&self) -> Option<Length> {
124 match self {
125 Self::Flex(f) => Some(*f),
126 _ => None,
127 }
128 }
129
130 pub(crate) fn is_flex(&self) -> bool {
131 matches!(self, Self::Flex(_))
132 }
133
134 pub(crate) fn inner_sized(&self) -> bool {
135 matches!(self, Self::Inner | Self::FillMinimum)
136 }
137
138 pub fn pretty(&self) -> String {
139 match self {
140 Self::Inner => "auto".to_string(),
141 Self::Pixels(s) => format!("{}", s.get()),
142 Self::Fn(_) => "Fn".to_string(),
143 Self::Percentage(p) => format!("{}%", p.get()),
144 Self::Fill => "fill".to_string(),
145 Self::FillMinimum => "fill-min".to_string(),
146 Self::RootPercentage(p) => format!("{}% of root", p.get()),
147 Self::Flex(f) => format!("flex({})", f.get()),
148 }
149 }
150
151 pub(crate) fn eval(
152 &self,
153 parent: f32,
154 available_parent: f32,
155 parent_margin: f32,
156 root: f32,
157 phase: Phase,
158 ) -> Option<f32> {
159 match self {
160 Self::Pixels(px) => Some(px.get() + parent_margin),
161 Self::Percentage(per) => Some(parent / 100.0 * per.get()),
162 Self::Fill => Some(available_parent),
163 Self::RootPercentage(per) => Some(root / 100.0 * per.get()),
164 Self::Flex(_) | Self::FillMinimum if phase == Phase::Final => Some(available_parent),
165 Self::Fn(f) => f.call(SizeFnContext {
166 parent,
167 available_parent,
168 parent_margin,
169 root,
170 phase,
171 }),
172 _ => None,
173 }
174 }
175
176 #[allow(clippy::too_many_arguments)]
177 pub(crate) fn min_max(
178 &self,
179 value: f32,
180 parent_value: f32,
181 available_parent_value: f32,
182 single_margin: f32,
183 margin: f32,
184 minimum: &Self,
185 maximum: &Self,
186 root_value: f32,
187 phase: Phase,
188 ) -> f32 {
189 let value = self
190 .eval(
191 parent_value,
192 available_parent_value,
193 margin,
194 root_value,
195 phase,
196 )
197 .unwrap_or(value + margin);
198
199 let minimum_value = minimum
200 .eval(
201 parent_value,
202 available_parent_value,
203 margin,
204 root_value,
205 phase,
206 )
207 .map(|v| v + single_margin);
208 let maximum_value = maximum.eval(
209 parent_value,
210 available_parent_value,
211 margin,
212 root_value,
213 phase,
214 );
215
216 let mut final_value = value;
217
218 if let Some(minimum_value) = minimum_value
219 && minimum_value > final_value
220 {
221 final_value = minimum_value;
222 }
223
224 if let Some(maximum_value) = maximum_value
225 && final_value > maximum_value
226 {
227 final_value = maximum_value;
228 }
229
230 final_value
231 }
232
233 pub(crate) fn most_fitting_size<'a>(&self, size: &'a f32, available_size: &'a f32) -> &'a f32 {
234 match self {
235 Self::Inner => available_size,
236 _ => size,
237 }
238 }
239}
240
241impl Scaled for Size {
242 fn scale(&mut self, scale_factor: f32) {
243 if let Self::Pixels(s) = self {
244 *s *= scale_factor;
245 }
246 }
247}