progress_bar.rs

  1use documented::Documented;
  2use gpui::{Hsla, point};
  3
  4use crate::components::Label;
  5use crate::prelude::*;
  6
  7/// A progress bar is a horizontal bar that communicates the status of a process.
  8///
  9/// A progress bar should not be used to represent indeterminate progress.
 10#[derive(IntoElement, RegisterComponent, Documented)]
 11pub struct ProgressBar {
 12    id: ElementId,
 13    value: f32,
 14    max_value: f32,
 15    bg_color: Hsla,
 16    over_color: Hsla,
 17    fg_color: Hsla,
 18}
 19
 20impl ProgressBar {
 21    pub fn new(id: impl Into<ElementId>, value: f32, max_value: f32, cx: &App) -> Self {
 22        Self {
 23            id: id.into(),
 24            value,
 25            max_value,
 26            bg_color: cx.theme().colors().background,
 27            over_color: cx.theme().status().error,
 28            fg_color: cx.theme().status().info,
 29        }
 30    }
 31
 32    /// Sets the current value of the progress bar.
 33    pub fn value(mut self, value: f32) -> Self {
 34        self.value = value;
 35        self
 36    }
 37
 38    /// Sets the maximum value of the progress bar.
 39    pub fn max_value(mut self, max_value: f32) -> Self {
 40        self.max_value = max_value;
 41        self
 42    }
 43
 44    /// Sets the background color of the progress bar.
 45    pub fn bg_color(mut self, color: Hsla) -> Self {
 46        self.bg_color = color;
 47        self
 48    }
 49
 50    /// Sets the foreground color of the progress bar.
 51    pub fn fg_color(mut self, color: Hsla) -> Self {
 52        self.fg_color = color;
 53        self
 54    }
 55
 56    /// Sets the over limit color of the progress bar.
 57    pub fn over_color(mut self, color: Hsla) -> Self {
 58        self.over_color = color;
 59        self
 60    }
 61}
 62
 63impl RenderOnce for ProgressBar {
 64    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
 65        let fill_width = (self.value / self.max_value).clamp(0.02, 1.0);
 66
 67        div()
 68            .id(self.id.clone())
 69            .w_full()
 70            .h_2()
 71            .p_0p5()
 72            .rounded_full()
 73            .bg(self.bg_color)
 74            .shadow(vec![gpui::BoxShadow {
 75                color: gpui::black().opacity(0.08),
 76                offset: point(px(0.), px(1.)),
 77                blur_radius: px(0.),
 78                spread_radius: px(0.),
 79            }])
 80            .child(
 81                div()
 82                    .h_full()
 83                    .rounded_full()
 84                    .when(self.value > self.max_value, |div| div.bg(self.over_color))
 85                    .when(self.value <= self.max_value, |div| div.bg(self.fg_color))
 86                    .w(relative(fill_width)),
 87            )
 88    }
 89}
 90
 91impl Component for ProgressBar {
 92    fn scope() -> ComponentScope {
 93        ComponentScope::Status
 94    }
 95
 96    fn description() -> Option<&'static str> {
 97        Some(Self::DOCS)
 98    }
 99
100    fn preview(_window: &mut Window, cx: &mut App) -> Option<AnyElement> {
101        let max_value = 180.0;
102        let container = || v_flex().w_full().gap_1();
103
104        Some(
105            example_group(vec![single_example(
106                "Examples",
107                v_flex()
108                    .w_full()
109                    .gap_2()
110                    .child(
111                        container()
112                            .child(
113                                h_flex()
114                                    .justify_between()
115                                    .child(Label::new("0%"))
116                                    .child(Label::new("Empty")),
117                            )
118                            .child(ProgressBar::new("empty", 0.0, max_value, cx)),
119                    )
120                    .child(
121                        container()
122                            .child(
123                                h_flex()
124                                    .justify_between()
125                                    .child(Label::new("38%"))
126                                    .child(Label::new("Partial")),
127                            )
128                            .child(ProgressBar::new("partial", max_value * 0.35, max_value, cx)),
129                    )
130                    .child(
131                        container()
132                            .child(
133                                h_flex()
134                                    .justify_between()
135                                    .child(Label::new("100%"))
136                                    .child(Label::new("Complete")),
137                            )
138                            .child(ProgressBar::new("filled", max_value, max_value, cx)),
139                    )
140                    .into_any_element(),
141            )])
142            .into_any_element(),
143        )
144    }
145}