fret_ui_kit/declarative/
glass.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, Invalidation, Theme, UiHost};
7
8use crate::declarative::reduced_transparency_queries;
9use crate::recipes::glass::{
10 GlassEffectRefinement, GlassEffectTokenKeys, GlassTokenKeys, resolve_glass_chrome,
11 resolve_glass_effect, resolve_glass_effect_chain_for_environment,
12};
13use crate::{ChromeRefinement, IntoUiElement, collect_children};
14
15#[derive(Debug, Clone)]
16pub struct GlassPanelProps {
17 pub layout: LayoutStyle,
18 pub mode: EffectMode,
19 pub quality: EffectQuality,
20 pub chrome: ChromeRefinement,
21 pub chrome_keys: GlassTokenKeys,
22 pub effect: GlassEffectRefinement,
23 pub effect_keys: GlassEffectTokenKeys,
24}
25
26impl Default for GlassPanelProps {
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::Backdrop,
34 quality: EffectQuality::Auto,
35 chrome: ChromeRefinement::default(),
36 chrome_keys: GlassTokenKeys::none(),
37 effect: GlassEffectRefinement::default(),
38 effect_keys: GlassEffectTokenKeys::none(),
39 }
40 }
41}
42
43pub fn glass_panel<H: UiHost, I, T>(
44 cx: &mut ElementContext<'_, H>,
45 props: GlassPanelProps,
46 children: impl FnOnce(&mut ElementContext<'_, H>) -> I,
47) -> AnyElement
48where
49 I: IntoIterator<Item = T>,
50 T: IntoUiElement<H>,
51{
52 let prefers_reduced_transparency =
53 reduced_transparency_queries::prefers_reduced_transparency(cx, Invalidation::Paint, false);
54
55 let theme = Theme::global(&*cx.app);
56 let chrome = resolve_glass_chrome(theme, &props.chrome, props.chrome_keys);
57 let effect = resolve_glass_effect(theme, &props.effect, props.effect_keys);
58 let chain = resolve_glass_effect_chain_for_environment(effect, prefers_reduced_transparency);
59 chain.report_if_degraded(&mut *cx.app);
60
61 let outer = ContainerProps {
68 layout: LayoutStyle {
69 overflow: Overflow::Clip,
70 ..props.layout
71 },
72 corner_radii: Corners::all(chrome.radius),
73 ..Default::default()
74 };
75
76 cx.container(outer, move |cx| {
77 let mut effect_layout = LayoutStyle::default();
78 effect_layout.size.width = Length::Fill;
79 effect_layout.size.height = Length::Fill;
80
81 let layer = cx.effect_layer_props(
82 EffectLayerProps {
83 layout: effect_layout,
84 mode: props.mode,
85 chain: chain.value,
86 quality: props.quality,
87 },
88 move |cx| {
89 let mut inner_layout = LayoutStyle::default();
90 inner_layout.size.width = Length::Fill;
91 inner_layout.size.height = Length::Fill;
92 let inner = ContainerProps {
93 layout: inner_layout,
94 padding: Edges::symmetric(chrome.padding_x, chrome.padding_y).into(),
95 background: Some(chrome.tint),
96 border: Edges::all(chrome.border_width),
97 border_color: Some(chrome.border),
98 corner_radii: Corners::all(chrome.radius),
99 ..Default::default()
100 };
101
102 let items = children(cx);
103 let inner_children = collect_children(cx, items);
104
105 vec![cx.container(inner, move |_cx| inner_children)]
106 },
107 );
108
109 vec![layer]
110 })
111}