1use fret_core::Px;
2
3use super::{
4 ColorFallback, ColorRef, LengthRefinement, MetricRef, Radius, SignedMetricRef, Space,
5 ThemeTokenRead,
6};
7use crate::Corners4;
8use fret_core::scene::{DashPatternV1, Paint};
9
10#[derive(Debug, Clone, Default)]
11pub struct PaddingRefinement {
12 pub top: Option<MetricRef>,
13 pub right: Option<MetricRef>,
14 pub bottom: Option<MetricRef>,
15 pub left: Option<MetricRef>,
16}
17
18impl PaddingRefinement {
19 pub fn merge(mut self, other: PaddingRefinement) -> Self {
20 if other.top.is_some() {
21 self.top = other.top;
22 }
23 if other.right.is_some() {
24 self.right = other.right;
25 }
26 if other.bottom.is_some() {
27 self.bottom = other.bottom;
28 }
29 if other.left.is_some() {
30 self.left = other.left;
31 }
32 self
33 }
34}
35
36#[derive(Debug, Clone, Default)]
37pub struct PaddingLengthRefinement {
38 pub top: Option<LengthRefinement>,
39 pub right: Option<LengthRefinement>,
40 pub bottom: Option<LengthRefinement>,
41 pub left: Option<LengthRefinement>,
42}
43
44impl PaddingLengthRefinement {
45 pub fn merge(mut self, other: PaddingLengthRefinement) -> Self {
46 if other.top.is_some() {
47 self.top = other.top;
48 }
49 if other.right.is_some() {
50 self.right = other.right;
51 }
52 if other.bottom.is_some() {
53 self.bottom = other.bottom;
54 }
55 if other.left.is_some() {
56 self.left = other.left;
57 }
58 self
59 }
60}
61
62#[derive(Debug, Clone, Default)]
63pub struct MarginRefinement {
64 pub top: Option<MarginEdgeRefinement>,
65 pub right: Option<MarginEdgeRefinement>,
66 pub bottom: Option<MarginEdgeRefinement>,
67 pub left: Option<MarginEdgeRefinement>,
68}
69
70impl MarginRefinement {
71 pub fn merge(mut self, other: MarginRefinement) -> Self {
72 if other.top.is_some() {
73 self.top = other.top;
74 }
75 if other.right.is_some() {
76 self.right = other.right;
77 }
78 if other.bottom.is_some() {
79 self.bottom = other.bottom;
80 }
81 if other.left.is_some() {
82 self.left = other.left;
83 }
84 self
85 }
86}
87
88#[derive(Debug, Clone, Default)]
89pub struct InsetRefinement {
90 pub top: Option<InsetEdgeRefinement>,
91 pub right: Option<InsetEdgeRefinement>,
92 pub bottom: Option<InsetEdgeRefinement>,
93 pub left: Option<InsetEdgeRefinement>,
94}
95
96impl InsetRefinement {
97 pub fn merge(mut self, other: InsetRefinement) -> Self {
98 if other.top.is_some() {
99 self.top = other.top;
100 }
101 if other.right.is_some() {
102 self.right = other.right;
103 }
104 if other.bottom.is_some() {
105 self.bottom = other.bottom;
106 }
107 if other.left.is_some() {
108 self.left = other.left;
109 }
110 self
111 }
112}
113
114#[derive(Debug, Clone)]
115pub enum MarginEdgeRefinement {
116 Px(SignedMetricRef),
117 Fill,
118 Fraction(f32),
122 Auto,
123}
124
125impl MarginEdgeRefinement {
126 pub fn resolve<T: ThemeTokenRead + ?Sized>(&self, theme: &T) -> fret_ui::element::MarginEdge {
127 match self {
128 Self::Px(m) => fret_ui::element::MarginEdge::Px(m.resolve(theme)),
129 Self::Fill => fret_ui::element::MarginEdge::Fill,
130 Self::Fraction(f) => fret_ui::element::MarginEdge::Fraction(*f),
131 Self::Auto => fret_ui::element::MarginEdge::Auto,
132 }
133 }
134}
135
136#[derive(Debug, Clone)]
137pub enum InsetEdgeRefinement {
138 Px(SignedMetricRef),
139 Fill,
140 Fraction(f32),
144 Auto,
145}
146
147impl InsetEdgeRefinement {
148 pub fn resolve<T: ThemeTokenRead + ?Sized>(&self, theme: &T) -> fret_ui::element::InsetEdge {
149 match self {
150 Self::Px(m) => fret_ui::element::InsetEdge::Px(m.resolve(theme)),
151 Self::Fill => fret_ui::element::InsetEdge::Fill,
152 Self::Fraction(f) => fret_ui::element::InsetEdge::Fraction(*f),
153 Self::Auto => fret_ui::element::InsetEdge::Auto,
154 }
155 }
156}
157
158#[derive(Debug, Clone, Default)]
163pub struct ChromeRefinement {
164 pub padding: Option<PaddingRefinement>,
165 pub padding_length: Option<PaddingLengthRefinement>,
166 pub min_height: Option<MetricRef>,
167 pub radius: Option<MetricRef>,
168 pub corner_radii: Option<CornerRadiiRefinement>,
169 pub shadow: Option<ShadowPreset>,
170 pub border_width: Option<MetricRef>,
171 pub background: Option<ColorRef>,
172 pub background_paint: Option<Paint>,
173 pub border_color: Option<ColorRef>,
174 pub border_dash: Option<DashPatternV1>,
175 pub text_color: Option<ColorRef>,
176}
177
178#[derive(Debug, Clone, Default)]
179pub struct CornerRadiiRefinement {
180 pub top_left: Option<MetricRef>,
181 pub top_right: Option<MetricRef>,
182 pub bottom_right: Option<MetricRef>,
183 pub bottom_left: Option<MetricRef>,
184}
185
186impl CornerRadiiRefinement {
187 pub fn merge(mut self, other: CornerRadiiRefinement) -> Self {
188 if other.top_left.is_some() {
189 self.top_left = other.top_left;
190 }
191 if other.top_right.is_some() {
192 self.top_right = other.top_right;
193 }
194 if other.bottom_right.is_some() {
195 self.bottom_right = other.bottom_right;
196 }
197 if other.bottom_left.is_some() {
198 self.bottom_left = other.bottom_left;
199 }
200 self
201 }
202}
203
204#[derive(Debug, Clone, Copy, PartialEq, Eq)]
205pub enum ShadowPreset {
206 None,
207 Xs,
208 Sm,
209 Md,
210 Lg,
211 Xl,
212}
213
214impl ChromeRefinement {
215 pub fn merge(mut self, other: ChromeRefinement) -> Self {
216 if let Some(p) = other.padding {
217 self.padding = Some(self.padding.unwrap_or_default().merge(p));
218 }
219 if let Some(p) = other.padding_length {
220 self.padding_length = Some(self.padding_length.unwrap_or_default().merge(p));
221 }
222 if other.min_height.is_some() {
223 self.min_height = other.min_height;
224 }
225 if other.radius.is_some() {
226 self.radius = other.radius;
227 }
228 if let Some(r) = other.corner_radii {
229 self.corner_radii = Some(self.corner_radii.unwrap_or_default().merge(r));
230 }
231 if other.shadow.is_some() {
232 self.shadow = other.shadow;
233 }
234 if other.border_width.is_some() {
235 self.border_width = other.border_width;
236 }
237 if other.background.is_some() {
238 self.background = other.background;
239 self.background_paint = None;
240 }
241 if other.background_paint.is_some() {
242 self.background_paint = other.background_paint;
243 self.background = None;
244 }
245 if other.border_color.is_some() {
246 self.border_color = other.border_color;
247 }
248 if other.border_dash.is_some() {
249 self.border_dash = other.border_dash;
250 }
251 if other.text_color.is_some() {
252 self.text_color = other.text_color;
253 }
254 self
255 }
256
257 pub fn px(mut self, space: Space) -> Self {
258 let m = MetricRef::space(space);
259 let mut padding = self.padding.unwrap_or_default();
260 padding.left = Some(m.clone());
261 padding.right = Some(m);
262 self.padding = Some(padding);
263 self
264 }
265
266 pub fn py(mut self, space: Space) -> Self {
267 let m = MetricRef::space(space);
268 let mut padding = self.padding.unwrap_or_default();
269 padding.top = Some(m.clone());
270 padding.bottom = Some(m);
271 self.padding = Some(padding);
272 self
273 }
274
275 pub fn p(mut self, space: Space) -> Self {
276 let m = MetricRef::space(space);
277 self.padding = Some(PaddingRefinement {
278 top: Some(m.clone()),
279 right: Some(m.clone()),
280 bottom: Some(m.clone()),
281 left: Some(m),
282 });
283 self
284 }
285
286 pub fn pt(mut self, space: Space) -> Self {
287 let mut padding = self.padding.unwrap_or_default();
288 padding.top = Some(MetricRef::space(space));
289 self.padding = Some(padding);
290 self
291 }
292
293 pub fn pr(mut self, space: Space) -> Self {
294 let mut padding = self.padding.unwrap_or_default();
295 padding.right = Some(MetricRef::space(space));
296 self.padding = Some(padding);
297 self
298 }
299
300 pub fn pb(mut self, space: Space) -> Self {
301 let mut padding = self.padding.unwrap_or_default();
302 padding.bottom = Some(MetricRef::space(space));
303 self.padding = Some(padding);
304 self
305 }
306
307 pub fn pl(mut self, space: Space) -> Self {
308 let mut padding = self.padding.unwrap_or_default();
309 padding.left = Some(MetricRef::space(space));
310 self.padding = Some(padding);
311 self
312 }
313
314 pub fn border_width(mut self, width: impl Into<MetricRef>) -> Self {
315 self.border_width = Some(width.into());
316 self
317 }
318
319 pub fn border_dash(mut self, dash: DashPatternV1) -> Self {
320 self.border_dash = Some(dash);
321 self
322 }
323
324 pub fn radius(mut self, radius: impl Into<MetricRef>) -> Self {
325 self.radius = Some(radius.into());
326 self
327 }
328
329 pub fn rounded(self, radius: Radius) -> Self {
330 self.radius(MetricRef::radius(radius))
331 }
332
333 pub fn corner_radii(mut self, radii: impl Into<Corners4<MetricRef>>) -> Self {
334 let radii = radii.into();
335 self.corner_radii = Some(CornerRadiiRefinement {
336 top_left: Some(radii.top_left),
337 top_right: Some(radii.top_right),
338 bottom_right: Some(radii.bottom_right),
339 bottom_left: Some(radii.bottom_left),
340 });
341 self
342 }
343
344 pub fn rounded_tl(mut self, radius: Radius) -> Self {
345 let mut radii = self.corner_radii.unwrap_or_default();
346 radii.top_left = Some(MetricRef::radius(radius));
347 self.corner_radii = Some(radii);
348 self
349 }
350
351 pub fn rounded_tr(mut self, radius: Radius) -> Self {
352 let mut radii = self.corner_radii.unwrap_or_default();
353 radii.top_right = Some(MetricRef::radius(radius));
354 self.corner_radii = Some(radii);
355 self
356 }
357
358 pub fn rounded_br(mut self, radius: Radius) -> Self {
359 let mut radii = self.corner_radii.unwrap_or_default();
360 radii.bottom_right = Some(MetricRef::radius(radius));
361 self.corner_radii = Some(radii);
362 self
363 }
364
365 pub fn rounded_bl(mut self, radius: Radius) -> Self {
366 let mut radii = self.corner_radii.unwrap_or_default();
367 radii.bottom_left = Some(MetricRef::radius(radius));
368 self.corner_radii = Some(radii);
369 self
370 }
371
372 pub fn shadow(mut self, shadow: ShadowPreset) -> Self {
373 self.shadow = Some(shadow);
374 self
375 }
376
377 pub fn shadow_none(self) -> Self {
378 self.shadow(ShadowPreset::None)
379 }
380
381 pub fn shadow_xs(self) -> Self {
382 self.shadow(ShadowPreset::Xs)
383 }
384
385 pub fn shadow_sm(self) -> Self {
386 self.shadow(ShadowPreset::Sm)
387 }
388
389 pub fn shadow_md(self) -> Self {
390 self.shadow(ShadowPreset::Md)
391 }
392
393 pub fn shadow_lg(self) -> Self {
394 self.shadow(ShadowPreset::Lg)
395 }
396
397 pub fn shadow_xl(self) -> Self {
398 self.shadow(ShadowPreset::Xl)
399 }
400
401 pub fn px_0(self) -> Self {
403 self.px(Space::N0)
404 }
405
406 pub fn px_1(self) -> Self {
407 self.px(Space::N1)
408 }
409
410 pub fn px_0p5(self) -> Self {
411 self.px(Space::N0p5)
412 }
413
414 pub fn px_1p5(self) -> Self {
415 self.px(Space::N1p5)
416 }
417
418 pub fn px_2(self) -> Self {
419 self.px(Space::N2)
420 }
421
422 pub fn px_2p5(self) -> Self {
423 self.px(Space::N2p5)
424 }
425
426 pub fn px_3(self) -> Self {
427 self.px(Space::N3)
428 }
429
430 pub fn px_4(self) -> Self {
431 self.px(Space::N4)
432 }
433
434 pub fn py_0(self) -> Self {
435 self.py(Space::N0)
436 }
437
438 pub fn py_1(self) -> Self {
439 self.py(Space::N1)
440 }
441
442 pub fn py_0p5(self) -> Self {
443 self.py(Space::N0p5)
444 }
445
446 pub fn py_1p5(self) -> Self {
447 self.py(Space::N1p5)
448 }
449
450 pub fn py_2(self) -> Self {
451 self.py(Space::N2)
452 }
453
454 pub fn py_2p5(self) -> Self {
455 self.py(Space::N2p5)
456 }
457
458 pub fn py_3(self) -> Self {
459 self.py(Space::N3)
460 }
461
462 pub fn py_4(self) -> Self {
463 self.py(Space::N4)
464 }
465
466 pub fn p_0(self) -> Self {
467 self.p(Space::N0)
468 }
469
470 pub fn p_1(self) -> Self {
471 self.p(Space::N1)
472 }
473
474 pub fn p_0p5(self) -> Self {
475 self.p(Space::N0p5)
476 }
477
478 pub fn p_1p5(self) -> Self {
479 self.p(Space::N1p5)
480 }
481
482 pub fn p_2(self) -> Self {
483 self.p(Space::N2)
484 }
485
486 pub fn p_2p5(self) -> Self {
487 self.p(Space::N2p5)
488 }
489
490 pub fn p_3(self) -> Self {
491 self.p(Space::N3)
492 }
493
494 pub fn p_4(self) -> Self {
495 self.p(Space::N4)
496 }
497
498 pub fn rounded_md(self) -> Self {
499 self.rounded(Radius::Md)
500 }
501
502 pub fn border_1(self) -> Self {
503 self.border_width(Px(1.0))
504 }
505
506 pub fn bg(mut self, color: ColorRef) -> Self {
507 self.background = Some(color);
508 self.background_paint = None;
509 self
510 }
511
512 pub fn background_paint(mut self, paint: Paint) -> Self {
513 self.background_paint = Some(paint);
514 self.background = None;
515 self
516 }
517
518 pub fn border_color(mut self, color: ColorRef) -> Self {
519 self.border_color = Some(color);
520 self
521 }
522
523 pub fn text_color(mut self, color: ColorRef) -> Self {
524 self.text_color = Some(color);
525 self
526 }
527
528 pub fn focused_border(self) -> Self {
529 self.border_1().border_color(ColorRef::Token {
530 key: "ring",
531 fallback: ColorFallback::ThemeFocusRing,
532 })
533 }
534
535 pub fn debug_border(self, color: ColorRef) -> Self {
536 if cfg!(debug_assertions) {
537 self.border_1().border_color(color)
538 } else {
539 self
540 }
541 }
542
543 pub fn debug_border_primary(self) -> Self {
544 self.debug_border(ColorRef::Token {
545 key: "primary",
546 fallback: ColorFallback::ThemeAccent,
547 })
548 }
549
550 pub fn debug_border_destructive(self) -> Self {
551 self.debug_border(ColorRef::Token {
552 key: "destructive",
553 fallback: ColorFallback::Color(fret_core::Color::from_srgb_hex_rgb(0xef_44_44)),
554 })
555 }
556
557 pub fn debug_border_ring(self) -> Self {
558 self.debug_border(ColorRef::Token {
559 key: "ring",
560 fallback: ColorFallback::ThemeFocusRing,
561 })
562 }
563}