tessera_ui_basic_components/
glass_button.rs1use std::sync::Arc;
11
12use derive_builder::Builder;
13use tessera_ui::{Color, DimensionValue, Dp, tessera};
14
15use crate::{
16 fluid_glass::{FluidGlassArgsBuilder, GlassBorder, fluid_glass},
17 ripple_state::RippleState,
18 shape_def::Shape,
19};
20
21#[derive(Builder, Clone, Default)]
23#[builder(pattern = "owned", setter(into, strip_option), default)]
24pub struct GlassButtonArgs {
25 #[builder(setter(strip_option, into = false))]
27 pub on_click: Option<Arc<dyn Fn() + Send + Sync>>,
28
29 #[builder(default = "Color::from_rgb(1.0, 1.0, 1.0)")]
32 pub ripple_color: Color,
33
34 #[builder(default = "Dp(12.0)")]
37 pub padding: Dp,
38 #[builder(default = "DimensionValue::WRAP", setter(into))]
40 pub width: DimensionValue,
41 #[builder(default = "DimensionValue::WRAP", setter(into))]
43 pub height: DimensionValue,
44
45 #[builder(default = "Color::new(0.5, 0.5, 0.5, 0.1)")]
47 pub tint_color: Color,
48 #[builder(
49 default = "Shape::RoundedRectangle { top_left: Dp(25.0), top_right: Dp(25.0), bottom_right: Dp(25.0), bottom_left: Dp(25.0), g2_k_value: 3.0 }"
50 )]
51 pub shape: Shape,
52 #[builder(default = "0.0")]
53 pub blur_radius: f32,
54 #[builder(default = "25.0")]
55 pub dispersion_height: f32,
56 #[builder(default = "1.2")]
57 pub chroma_multiplier: f32,
58 #[builder(default = "24.0")]
59 pub refraction_height: f32,
60 #[builder(default = "32.0")]
61 pub refraction_amount: f32,
62 #[builder(default = "0.02")]
63 pub noise_amount: f32,
64 #[builder(default = "1.0")]
65 pub noise_scale: f32,
66 #[builder(default = "0.0")]
67 pub time: f32,
68 #[builder(default, setter(strip_option))]
69 pub contrast: Option<f32>,
70 #[builder(default, setter(strip_option))]
71 pub border: Option<GlassBorder>,
72}
73
74impl GlassButtonArgs {
76 pub fn primary(on_click: Arc<dyn Fn() + Send + Sync>) -> Self {
78 GlassButtonArgsBuilder::default()
79 .on_click(on_click)
80 .tint_color(Color::new(0.2, 0.5, 0.8, 0.2)) .border(GlassBorder::new(Dp(1.0).into()))
82 .build()
83 .unwrap()
84 }
85
86 pub fn secondary(on_click: Arc<dyn Fn() + Send + Sync>) -> Self {
88 GlassButtonArgsBuilder::default()
89 .on_click(on_click)
90 .tint_color(Color::new(0.6, 0.6, 0.6, 0.2)) .border(GlassBorder::new(Dp(1.0).into()))
92 .build()
93 .unwrap()
94 }
95
96 pub fn success(on_click: Arc<dyn Fn() + Send + Sync>) -> Self {
98 GlassButtonArgsBuilder::default()
99 .on_click(on_click)
100 .tint_color(Color::new(0.1, 0.7, 0.3, 0.2)) .border(GlassBorder::new(Dp(1.0).into()))
102 .build()
103 .unwrap()
104 }
105
106 pub fn danger(on_click: Arc<dyn Fn() + Send + Sync>) -> Self {
108 GlassButtonArgsBuilder::default()
109 .on_click(on_click)
110 .tint_color(Color::new(0.8, 0.2, 0.2, 0.2)) .border(GlassBorder::new(Dp(1.0).into()))
112 .build()
113 .unwrap()
114 }
115}
116
117#[tessera]
159pub fn glass_button(
160 args: impl Into<GlassButtonArgs>,
161 ripple_state: Arc<RippleState>,
162 child: impl FnOnce() + Send + Sync + 'static,
163) {
164 let args: GlassButtonArgs = args.into();
165
166 let mut glass_args_builder = FluidGlassArgsBuilder::default();
167 if let Some((progress, center)) = ripple_state.get_animation_progress() {
168 let ripple_alpha = (1.0 - progress) * 0.3; glass_args_builder = glass_args_builder
170 .ripple_center(center)
171 .ripple_radius(progress)
172 .ripple_alpha(ripple_alpha)
173 .ripple_strength(progress);
174 }
175
176 if let Some(contrast) = args.contrast {
177 glass_args_builder = glass_args_builder.contrast(contrast);
178 }
179
180 let mut glass_args = glass_args_builder
181 .tint_color(args.tint_color)
182 .shape(args.shape)
183 .blur_radius(args.blur_radius)
184 .dispersion_height(args.dispersion_height)
185 .chroma_multiplier(args.chroma_multiplier)
186 .refraction_height(args.refraction_height)
187 .refraction_amount(args.refraction_amount)
188 .noise_amount(args.noise_amount)
189 .noise_scale(args.noise_scale)
190 .width(args.width)
191 .height(args.height)
192 .time(args.time)
193 .padding(args.padding);
194
195 if let Some(on_click) = args.on_click {
196 glass_args = glass_args.on_click(on_click);
197 }
198
199 if let Some(border) = args.border {
200 glass_args = glass_args.border(border);
201 }
202
203 let glass_args = glass_args.build().unwrap();
204
205 fluid_glass(glass_args, Some(ripple_state), child);
206}