guise/feedback/
progress.rs1use 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#[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}