egui_components/
progress.rs1use egui::{vec2, Color32, Response, Sense, Ui, Widget};
9use egui_components_theme::Theme;
10
11use crate::common::Variant;
12
13pub struct Progress {
14 value: f32,
15 indeterminate: bool,
16 width: Option<f32>,
17 height: f32,
18 variant: Variant,
19}
20
21impl Progress {
22 pub fn new(value: f32) -> Self {
23 Self {
24 value: value.clamp(0.0, 1.0),
25 indeterminate: false,
26 width: None,
27 height: 8.0,
28 variant: Variant::Primary,
29 }
30 }
31
32 pub fn indeterminate() -> Self {
33 Self {
34 value: 0.0,
35 indeterminate: true,
36 width: None,
37 height: 8.0,
38 variant: Variant::Primary,
39 }
40 }
41
42 pub fn width(mut self, w: f32) -> Self {
43 self.width = Some(w);
44 self
45 }
46 pub fn height(mut self, h: f32) -> Self {
47 self.height = h;
48 self
49 }
50 pub fn variant(mut self, v: Variant) -> Self {
51 self.variant = v;
52 self
53 }
54}
55
56impl Widget for Progress {
57 fn ui(self, ui: &mut Ui) -> Response {
58 let theme = Theme::get(ui.ctx());
59 let c = theme.colors;
60 let width = self.width.unwrap_or_else(|| ui.available_width().min(280.0));
61 let (rect, response) = ui.allocate_exact_size(vec2(width, self.height), Sense::hover());
62
63 if ui.is_rect_visible(rect) {
64 let radius = egui::CornerRadius::same((self.height * 0.5) as u8);
65 let painter = ui.painter();
66 painter.rect_filled(rect, radius, c.muted_background);
67
68 let fill = fill_color(&c, self.variant);
69 if self.indeterminate {
70 let t = (ui.input(|i| i.time) % 1.4) as f32 / 1.4;
72 let seg_w = width * 0.35;
73 let travel = width + seg_w;
74 let x = rect.left() - seg_w + travel * t;
75 let seg = egui::Rect::from_min_max(
76 egui::pos2(x.max(rect.left()), rect.top()),
77 egui::pos2((x + seg_w).min(rect.right()), rect.bottom()),
78 );
79 if seg.width() > 0.0 {
80 painter.rect_filled(seg, radius, fill);
81 }
82 ui.ctx().request_repaint();
83 } else if self.value > 0.0 {
84 let filled = egui::Rect::from_min_size(
85 rect.min,
86 vec2(width * self.value, self.height),
87 );
88 painter.rect_filled(filled, radius, fill);
89 }
90 }
91
92 response
93 }
94}
95
96fn fill_color(c: &egui_components_theme::ThemeColor, v: Variant) -> Color32 {
97 match v {
98 Variant::Success => c.success_background,
99 Variant::Warning => c.warning_background,
100 Variant::Danger => c.danger_background,
101 Variant::Info => c.info_background,
102 _ => c.primary_background,
103 }
104}