tessera_ui_basic_components/
progress.rs

1use derive_builder::Builder;
2use tessera_ui::{Color, ComputedData, Constraint, DimensionValue, Dp, Px, PxPosition, place_node};
3use tessera_ui_macros::tessera;
4
5use crate::{
6    shape_def::Shape,
7    surface::{SurfaceArgsBuilder, surface},
8};
9
10/// Arguments for the `progress` component.
11#[derive(Builder, Clone, Debug)]
12#[builder(pattern = "owned")]
13pub struct ProgressArgs {
14    /// The current value of the progress bar, ranging from 0.0 to 1.0.
15    #[builder(default = "0.0")]
16    pub value: f32,
17
18    /// The width of the progress bar.
19    #[builder(default = "Dp(200.0)")]
20    pub width: Dp,
21
22    /// The height of the progress bar.
23    #[builder(default = "Dp(8.0)")]
24    pub height: Dp,
25
26    /// The color of the active part of the track.
27    #[builder(default = "Color::new(0.2, 0.5, 0.8, 1.0)")]
28    pub progress_color: Color,
29
30    /// The color of the inactive part of the track.
31    #[builder(default = "Color::new(0.8, 0.8, 0.8, 1.0)")]
32    pub track_color: Color,
33
34    /// The shape of the progress bar.
35    #[builder(default = "Shape::RoundedRectangle{ corner_radius: 4.0, g2_k_value: 3.0 }")]
36    pub shape: Shape,
37}
38
39#[tessera]
40pub fn progress(args: impl Into<ProgressArgs>) {
41    let args: ProgressArgs = args.into();
42
43    // Child 1: The background track. It's drawn first.
44    surface(
45        SurfaceArgsBuilder::default()
46            .color(args.track_color)
47            .shape(args.shape)
48            .width(DimensionValue::Fill {
49                min: None,
50                max: None,
51            })
52            .height(DimensionValue::Fill {
53                min: None,
54                max: None,
55            })
56            .build()
57            .unwrap(),
58        None,
59        || {},
60    );
61
62    // Child 2: The progress fill. It's drawn on top of the track.
63    surface(
64        SurfaceArgsBuilder::default()
65            .color(args.progress_color)
66            .shape(args.shape)
67            .width(DimensionValue::Fill {
68                min: None,
69                max: None,
70            })
71            .height(DimensionValue::Fill {
72                min: None,
73                max: None,
74            })
75            .build()
76            .unwrap(),
77        None,
78        || {},
79    );
80
81    measure(Box::new(move |input| {
82        let self_width = args.width.to_px();
83        let self_height = args.height.to_px();
84
85        let track_id = input.children_ids[0];
86        let progress_id = input.children_ids[1];
87
88        // Measure and place the background track to take the full size of the component.
89        let track_constraint = Constraint::new(
90            DimensionValue::Fixed(self_width),
91            DimensionValue::Fixed(self_height),
92        );
93        tessera_ui::measure_node(
94            track_id,
95            &track_constraint,
96            input.tree,
97            input.metadatas,
98            input.compute_resource_manager.clone(),
99            input.gpu,
100        )?;
101        place_node(track_id, PxPosition::new(Px(0), Px(0)), input.metadatas);
102
103        // Measure and place the progress fill based on the `value`.
104        let progress_width = Px((self_width.to_f32() * args.value.clamp(0.0, 1.0)) as i32);
105        let progress_constraint = Constraint::new(
106            DimensionValue::Fixed(progress_width),
107            DimensionValue::Fixed(self_height),
108        );
109        tessera_ui::measure_node(
110            progress_id,
111            &progress_constraint,
112            input.tree,
113            input.metadatas,
114            input.compute_resource_manager.clone(),
115            input.gpu,
116        )?;
117        place_node(progress_id, PxPosition::new(Px(0), Px(0)), input.metadatas);
118
119        // The progress component itself is a container, its size is defined by the args.
120        Ok(ComputedData {
121            width: self_width,
122            height: self_height,
123        })
124    }));
125}