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    fg_color: Hsla,
 17}
 18
 19impl ProgressBar {
 20    pub fn new(id: impl Into<ElementId>, value: f32, max_value: f32, cx: &App) -> Self {
 21        Self {
 22            id: id.into(),
 23            value,
 24            max_value,
 25            bg_color: cx.theme().colors().background,
 26            fg_color: cx.theme().status().info,
 27        }
 28    }
 29
 30    /// Sets the current value of the progress bar.
 31    pub fn value(mut self, value: f32) -> Self {
 32        self.value = value;
 33        self
 34    }
 35
 36    /// Sets the maximum value of the progress bar.
 37    pub fn max_value(mut self, max_value: f32) -> Self {
 38        self.max_value = max_value;
 39        self
 40    }
 41
 42    /// Sets the background color of the progress bar.
 43    pub fn bg_color(mut self, color: Hsla) -> Self {
 44        self.bg_color = color;
 45        self
 46    }
 47
 48    /// Sets the foreground color of the progress bar.
 49    pub fn fg_color(mut self, color: Hsla) -> Self {
 50        self.fg_color = color;
 51        self
 52    }
 53}
 54
 55impl RenderOnce for ProgressBar {
 56    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
 57        let fill_width = (self.value / self.max_value).clamp(0.02, 1.0);
 58
 59        div()
 60            .id(self.id.clone())
 61            .w_full()
 62            .h(px(8.0))
 63            .rounded_full()
 64            .py(px(2.0))
 65            .px(px(4.0))
 66            .bg(self.bg_color)
 67            .shadow(smallvec::smallvec![gpui::BoxShadow {
 68                color: gpui::black().opacity(0.08),
 69                offset: point(px(0.), px(1.)),
 70                blur_radius: px(0.),
 71                spread_radius: px(0.),
 72            }])
 73            .child(
 74                div()
 75                    .h_full()
 76                    .rounded_full()
 77                    .bg(self.fg_color)
 78                    .w(relative(fill_width)),
 79            )
 80    }
 81}
 82
 83impl Component for ProgressBar {
 84    fn scope() -> ComponentScope {
 85        ComponentScope::Status
 86    }
 87
 88    fn description() -> Option<&'static str> {
 89        Some(Self::DOCS)
 90    }
 91
 92    fn preview(_window: &mut Window, cx: &mut App) -> Option<AnyElement> {
 93        let max_value = 180.0;
 94
 95        Some(
 96            div()
 97                .flex()
 98                .flex_col()
 99                .gap_4()
100                .p_4()
101                .w(px(240.0))
102                .child(div().child("Progress Bar"))
103                .child(
104                    div()
105                        .flex()
106                        .flex_col()
107                        .gap_2()
108                        .child(
109                            div()
110                                .flex()
111                                .justify_between()
112                                .child(Label::new("0%"))
113                                .child(Label::new("Empty")),
114                        )
115                        .child(ProgressBar::new("empty", 0.0, max_value, cx)),
116                )
117                .child(
118                    div()
119                        .flex()
120                        .flex_col()
121                        .gap_2()
122                        .child(
123                            div()
124                                .flex()
125                                .justify_between()
126                                .child(Label::new("38%"))
127                                .child(Label::new("Partial")),
128                        )
129                        .child(ProgressBar::new("partial", max_value * 0.35, max_value, cx)),
130                )
131                .child(
132                    div()
133                        .flex()
134                        .flex_col()
135                        .gap_2()
136                        .child(
137                            div()
138                                .flex()
139                                .justify_between()
140                                .child(Label::new("100%"))
141                                .child(Label::new("Complete")),
142                        )
143                        .child(ProgressBar::new("filled", max_value, max_value, cx)),
144                )
145                .into_any_element(),
146        )
147    }
148}