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}