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