Skip to main content

guise/feedback/
progress.rs

1//! `Progress` — a horizontal completion bar.
2
3use gpui::prelude::*;
4use gpui::{div, px, relative, App, IntoElement, Window};
5
6use crate::devtools::Probed;
7use crate::style::ColorValue;
8use crate::theme::{theme, ColorName, Size};
9
10/// A determinate progress bar. `value` is a percentage
11/// in `0.0..=100.0`.
12#[derive(IntoElement)]
13pub struct Progress {
14    value: f32,
15    color: ColorValue,
16    size: Size,
17    radius: Option<Size>,
18}
19
20impl Progress {
21    pub fn new(value: f32) -> Self {
22        Progress {
23            value: value.clamp(0.0, 100.0),
24            color: ColorValue::Named(ColorName::Blue),
25            size: Size::Md,
26            radius: None,
27        }
28    }
29
30    pub fn color(mut self, color: impl Into<ColorValue>) -> Self {
31        self.color = color.into();
32        self
33    }
34
35    pub fn size(mut self, size: Size) -> Self {
36        self.size = size;
37        self
38    }
39
40    pub fn radius(mut self, radius: Size) -> Self {
41        self.radius = Some(radius);
42        self
43    }
44
45    fn height(&self) -> f32 {
46        match self.size {
47            Size::Xs => 4.0,
48            Size::Sm => 6.0,
49            Size::Md => 8.0,
50            Size::Lg => 12.0,
51            Size::Xl => 16.0,
52        }
53    }
54}
55
56impl RenderOnce for Progress {
57    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
58        let t = theme(cx);
59        let height = self.height();
60        let radius = self.radius.map(|r| t.radius(r)).unwrap_or(height / 2.0);
61        let track = t
62            .color(ColorName::Gray, if t.scheme.is_dark() { 7 } else { 2 })
63            .hsla();
64        let fill = crate::style::solid(t, self.color);
65        let fraction = (self.value / 100.0).clamp(0.0, 1.0);
66
67        div()
68            .w_full()
69            .h(px(height))
70            .rounded(px(radius))
71            .bg(track)
72            .child(
73                div()
74                    .h_full()
75                    .w(relative(fraction))
76                    .rounded(px(radius))
77                    .bg(fill),
78            )
79            .probe("Progress")
80            .attr_with("value", || format!("{:.0}%", self.value * 100.0))
81            .attr("size", self.size.label())
82    }
83}