tessera_ui_basic_components/glass_progress.rs
1//! Provides a glassmorphism-style progress bar component for visualizing task completion.
2//!
3//! The `glass_progress` module implements a customizable, frosted glass effect progress bar,
4//! featuring a blurred background, tint colors, and borders. It is designed to display a
5//! progress value from 0.0 to 1.0, making it suitable for loading screens, dashboards, or
6//! any interface requiring a modern and visually appealing progress indicator.
7
8use derive_builder::Builder;
9use tessera_ui::{Color, ComputedData, Constraint, DimensionValue, Dp, Px, PxPosition};
10use tessera_ui_macros::tessera;
11
12use crate::{
13 fluid_glass::{FluidGlassArgsBuilder, GlassBorder, fluid_glass},
14 shape_def::Shape,
15};
16
17/// Arguments for the `glass_progress` component.
18#[derive(Builder, Clone, Debug)]
19#[builder(pattern = "owned")]
20pub struct GlassProgressArgs {
21 /// The current value of the progress bar, ranging from 0.0 to 1.0.
22 #[builder(default = "0.0")]
23 pub value: f32,
24
25 /// The width of the progress bar.
26 #[builder(default = "Dp(200.0)")]
27 pub width: Dp,
28
29 /// The height of the progress bar.
30 #[builder(default = "Dp(12.0)")]
31 pub height: Dp,
32
33 /// Glass tint color for the track background.
34 #[builder(default = "Color::new(0.3, 0.3, 0.3, 0.15)")]
35 pub track_tint_color: Color,
36
37 /// Glass tint color for the progress fill.
38 #[builder(default = "Color::new(0.5, 0.7, 1.0, 0.25)")]
39 pub progress_tint_color: Color,
40
41 /// Glass blur radius for all components.
42 #[builder(default = "8.0")]
43 pub blur_radius: f32,
44
45 /// Border width for the track.
46 #[builder(default = "Dp(1.0)")]
47 pub track_border_width: Dp,
48}
49
50/// Creates a progress bar component with a frosted glass effect.
51///
52/// The `glass_progress` displays a value from a continuous range (0.0 to 1.0)
53/// with a modern, semi-transparent "glassmorphism" aesthetic, including a
54/// blurred background and subtle highlights.
55///
56/// # Arguments
57///
58/// * `args` - An instance of `GlassProgressArgs` or `GlassProgressArgsBuilder`
59/// to configure the progress bar's appearance.
60/// - `value`: The current progress value, must be between 0.0 and 1.0.
61///
62/// # Example
63///
64/// ```rust,no_run
65/// use tessera_ui_basic_components::glass_progress::{glass_progress, GlassProgressArgsBuilder};
66///
67/// // In your component function
68/// glass_progress(
69/// GlassProgressArgsBuilder::default()
70/// .value(0.75)
71/// .build()
72/// .unwrap(),
73/// );
74/// ```
75#[tessera]
76pub fn glass_progress(args: impl Into<GlassProgressArgs>) {
77 let args: GlassProgressArgs = args.into();
78
79 // External track (background) with border - capsule shape
80 fluid_glass(
81 FluidGlassArgsBuilder::default()
82 .width(DimensionValue::Fixed(args.width.to_px()))
83 .height(DimensionValue::Fixed(args.height.to_px()))
84 .tint_color(args.track_tint_color)
85 .blur_radius(args.blur_radius)
86 .shape(Shape::RoundedRectangle {
87 corner_radius: args.height.to_px().to_f32() / 2.0,
88 g2_k_value: 2.0, // Capsule shape
89 })
90 .border(GlassBorder::new(args.track_border_width.into()))
91 .padding(args.track_border_width)
92 .build()
93 .unwrap(),
94 None,
95 move || {
96 // Internal progress fill - capsule shape
97 let progress_width = (args.width.to_px().to_f32() * args.value.clamp(0.0, 1.0))
98 - (args.track_border_width.to_px().to_f32() * 2.0);
99 let effective_height =
100 args.height.to_px().to_f32() - (args.track_border_width.to_px().to_f32() * 2.0);
101
102 if progress_width > 0.0 {
103 fluid_glass(
104 FluidGlassArgsBuilder::default()
105 .width(DimensionValue::Fixed(Px(progress_width as i32)))
106 .height(DimensionValue::Fill {
107 min: None,
108 max: None,
109 })
110 .tint_color(args.progress_tint_color)
111 .shape(Shape::RoundedRectangle {
112 corner_radius: effective_height / 2.0,
113 g2_k_value: 2.0, // Capsule shape
114 })
115 .refraction_amount(0.0)
116 .build()
117 .unwrap(),
118 None,
119 || {},
120 );
121 }
122 },
123 );
124
125 measure(Box::new(move |input| {
126 let self_width = args.width.to_px();
127 let self_height = args.height.to_px();
128
129 let track_id = input.children_ids[0];
130
131 // Measure track
132 let track_constraint = Constraint::new(
133 DimensionValue::Fixed(self_width),
134 DimensionValue::Fixed(self_height),
135 );
136 input.measure_child(track_id, &track_constraint)?;
137 input.place_child(track_id, PxPosition::new(Px(0), Px(0)));
138
139 Ok(ComputedData {
140 width: self_width,
141 height: self_height,
142 })
143 }));
144}