rosace_widgets/tree/
circular_progress.rs1use rosace_core::types::{Point, Size};
2use rosace_render::Color;
3use super::{Widget, LayoutCtx, PaintCtx};
4
5pub struct CircularProgress {
8 value: Option<f32>, diameter: f32,
10 thickness: f32,
11 color: Option<Color>,
12 track: Option<Color>,
13}
14
15impl CircularProgress {
16 pub fn new(value: f32) -> Self {
18 Self { value: Some(value.clamp(0.0, 1.0)), diameter: 36.0, thickness: 4.0, color: None, track: None }
19 }
20 pub fn spinner() -> Self {
22 Self { value: None, diameter: 36.0, thickness: 4.0, color: None, track: None }
23 }
24 pub fn diameter(mut self, d: f32) -> Self { self.diameter = d; self }
25 pub fn thickness(mut self, t: f32) -> Self { self.thickness = t; self }
26 pub fn color(mut self, c: Color) -> Self { self.color = Some(c); self }
27 pub fn track(mut self, c: Color) -> Self { self.track = Some(c); self }
28}
29
30impl Widget for CircularProgress {
31 fn layout(&self, ctx: &LayoutCtx) -> Size {
32 ctx.constraints.constrain(Size { width: self.diameter, height: self.diameter })
33 }
34
35 fn paint(&self, ctx: &mut PaintCtx) {
36 let r = ctx.rect;
37 let color = self.color.unwrap_or_else(|| ctx.tc(ctx.theme.colors.primary));
38 let center = Point { x: r.origin.x + r.size.width / 2.0, y: r.origin.y + r.size.height / 2.0 };
39 let radius = (self.diameter - self.thickness) / 2.0;
40
41 match self.value {
42 Some(v) => {
43 let track = self.track.unwrap_or(Color::rgba(255, 255, 255, 28));
45 ctx.fill_arc(center, radius, self.thickness, 0.0, 360.0, track);
46 if v > 0.0 {
47 ctx.fill_arc(center, radius, self.thickness, -90.0, 360.0 * v, color);
48 }
49 }
50 None => {
51 let t = super::anim_clock();
53 let start = (t * 360.0) % 360.0;
54 ctx.fill_arc(center, radius, self.thickness, start, 270.0, color);
55 ctx.request_animation();
56 }
57 }
58 }
59}