fret_ui_kit/declarative/
pixelate.rs1use fret_core::geometry::{Corners, Edges};
2use fret_core::scene::{EffectMode, EffectQuality};
3use fret_ui::element::{
4 AnyElement, ContainerProps, EffectLayerProps, LayoutStyle, Length, Overflow,
5};
6use fret_ui::{ElementContext, Theme, UiHost};
7
8use crate::recipes::pixelate::{
9 PixelateEffectRefinement, PixelateEffectTokenKeys, PixelateTokenKeys, pixelate_effect_chain,
10 resolve_pixelate_chrome, resolve_pixelate_effect,
11};
12use crate::recipes::resolve::ResolvedWithFallback;
13use crate::{ChromeRefinement, IntoUiElement, collect_children};
14
15#[derive(Debug, Clone)]
16pub struct PixelatePanelProps {
17 pub layout: LayoutStyle,
18 pub mode: EffectMode,
19 pub quality: EffectQuality,
20 pub chrome: ChromeRefinement,
21 pub chrome_keys: PixelateTokenKeys,
22 pub effect: PixelateEffectRefinement,
23 pub effect_keys: PixelateEffectTokenKeys,
24}
25
26impl Default for PixelatePanelProps {
27 fn default() -> Self {
28 let mut layout = LayoutStyle::default();
29 layout.size.width = Length::Fill;
30 layout.size.height = Length::Fill;
31 Self {
32 layout,
33 mode: EffectMode::FilterContent,
34 quality: EffectQuality::Auto,
35 chrome: ChromeRefinement::default(),
36 chrome_keys: PixelateTokenKeys::none(),
37 effect: PixelateEffectRefinement::default(),
38 effect_keys: PixelateEffectTokenKeys::none(),
39 }
40 }
41}
42
43pub fn pixelate_panel<H: UiHost, I, T>(
44 cx: &mut ElementContext<'_, H>,
45 props: PixelatePanelProps,
46 children: impl FnOnce(&mut ElementContext<'_, H>) -> I,
47) -> AnyElement
48where
49 I: IntoIterator<Item = T>,
50 T: IntoUiElement<H>,
51{
52 let theme = Theme::global(&*cx.app);
53 let chrome = resolve_pixelate_chrome(theme, &props.chrome, props.chrome_keys);
54 let effect = resolve_pixelate_effect(theme, &props.effect, props.effect_keys);
55 let chain = ResolvedWithFallback::ok(pixelate_effect_chain(effect));
56
57 let outer = ContainerProps {
58 layout: LayoutStyle {
59 overflow: Overflow::Clip,
60 ..props.layout
61 },
62 corner_radii: Corners::all(chrome.radius),
63 ..Default::default()
64 };
65
66 cx.container(outer, move |cx| {
67 let mut effect_layout = LayoutStyle::default();
68 effect_layout.size.width = Length::Fill;
69 effect_layout.size.height = Length::Fill;
70
71 let layer = cx.effect_layer_props(
72 EffectLayerProps {
73 layout: effect_layout,
74 mode: props.mode,
75 chain: chain.value,
76 quality: props.quality,
77 },
78 move |cx| {
79 let mut inner_layout = LayoutStyle::default();
80 inner_layout.size.width = Length::Fill;
81 inner_layout.size.height = Length::Fill;
82 let inner = ContainerProps {
83 layout: inner_layout,
84 padding: Edges::symmetric(chrome.padding_x, chrome.padding_y).into(),
85 background: Some(chrome.background),
86 border: Edges::all(chrome.border_width),
87 border_color: Some(chrome.border_color),
88 corner_radii: Corners::all(chrome.radius),
89 ..Default::default()
90 };
91
92 let items = children(cx);
93 let inner_children = collect_children(cx, items);
94
95 vec![cx.container(inner, move |_cx| inner_children)]
96 },
97 );
98
99 vec![layer]
100 })
101}