1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use std::f64::consts::PI;
use druid::kurbo::Line;
use druid::widget::prelude::*;
use druid::{theme, Color, Data, KeyOrValue, Point, Vec2};
pub struct Spinner {
t: f64,
color: KeyOrValue<Color>,
}
impl Spinner {
pub fn new() -> Spinner {
Spinner::default()
}
pub fn with_color(mut self, color: impl Into<KeyOrValue<Color>>) -> Self {
self.color = color.into();
self
}
pub fn set_color(&mut self, color: impl Into<KeyOrValue<Color>>) {
self.color = color.into();
}
}
impl Default for Spinner {
fn default() -> Self {
Spinner {
t: 0.0,
color: theme::LABEL_COLOR.into(),
}
}
}
impl<T: Data> Widget<T> for Spinner {
fn event(&mut self, _ctx: &mut EventCtx, _event: &Event, _data: &mut T, _env: &Env) {}
fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, _data: &T, _env: &Env) {
if let LifeCycle::WidgetAdded = event {
ctx.request_anim_frame();
}
if let LifeCycle::AnimFrame(interval) = event {
self.t += (*interval as f64) * 1e-9;
if self.t >= 1.0 {
self.t = 0.0;
}
ctx.request_anim_frame();
}
}
fn update(&mut self, _ctx: &mut UpdateCtx, _old_data: &T, _data: &T, _env: &Env) {}
fn layout(
&mut self,
_layout_ctx: &mut LayoutCtx,
bc: &BoxConstraints,
_data: &T,
env: &Env,
) -> Size {
bc.debug_check("Spinner");
if bc.is_width_bounded() && bc.is_height_bounded() {
bc.max()
} else {
bc.constrain(Size::new(
env.get(theme::BASIC_WIDGET_HEIGHT),
env.get(theme::BASIC_WIDGET_HEIGHT),
))
}
}
fn paint(&mut self, ctx: &mut PaintCtx, _data: &T, env: &Env) {
let t = self.t;
let (width, height) = (ctx.size().width, ctx.size().height);
let center = Point::new(width / 2.0, height / 2.0);
let (r, g, b, original_alpha) = Color::as_rgba(&self.color.resolve(env));
let scale_factor = width.min(height) / 40.0;
for step in 1..=12 {
let step = f64::from(step);
let fade_t = (t * 12.0 + 1.0).trunc();
let fade = ((fade_t + step).rem_euclid(12.0) / 12.0) + 1.0 / 12.0;
let angle = Vec2::from_angle((step / 12.0) * -2.0 * PI);
let ambit_start = center + (10.0 * scale_factor * angle);
let ambit_end = center + (20.0 * scale_factor * angle);
let color = Color::rgba(r, g, b, fade * original_alpha);
ctx.stroke(
Line::new(ambit_start, ambit_end),
&color,
3.0 * scale_factor,
);
}
}
}