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