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
131
132
133
134
135
//! How fast the tree animates, and how a widget says what it is waiting for.
//!
//! Two different things used to be spelled the same way. A spinner asking for
//! "another frame in 16 ms" and a carousel asking for "the next page in eight
//! seconds" both came back as a millisecond deadline, so nothing could tell a
//! **sample rate** from a **duration** — and a setting that halved one would
//! have silently halved the other. [`Wake`] separates them, and [`Motion`] is
//! the one knob that sets the rate for everything.
/// How often the tree looks at whatever is animating.
///
/// One setting for every moving thing in the tree: spinners, knobs crossing,
/// carousel slides, layout tweens, toast fades. It is a **sample rate**, not a
/// duration — halving it makes animation coarser, never slower. A toggle still
/// crosses in 120 ms and a carousel still advances after eight seconds,
/// whatever this says.
///
/// ```
/// # use denise::{Size, theme};
/// # use denise_ui::{Motion, Ui};
/// # enum Msg { Noop }
/// # let mut ui: Ui<Msg> = Ui::new(Size::new(1920, 1080), theme::DARK);
/// ui.set_motion(Motion::Every(33)); // 30 fps: half the wakes, half the cost
/// ui.set_motion(Motion::None); // reduced motion, or a tight power budget
/// ```
///
/// # Why this and not a constant per widget
///
/// It used to be a constant per widget — four of them, all saying 16 or 50, all
/// private. That is one decision copied four times and reachable from nowhere,
/// and it is the wrong number in two directions at once: a desktop wants sixty
/// frames a second because a rotating arc at twenty reads as a stutter, and a
/// battery-powered panel wants the arc to cost a third as much. The gallery on a
/// Pi 3A+ is 4.20% of a core at 16 ms and 1.37% at 50, for as long as one
/// spinner is on screen.
///
/// So the widget says *that* it is moving and the tree says *when* to look —
/// which also means a custom widget gets the setting for free, without knowing
/// it exists.
/// When a widget wants [`Widget::animate`](crate::Widget::animate) called again.
///
/// The distinction this type exists for:
///
/// - [`Wake::Animating`] is a **rate**. The widget is mid-movement and wants to
/// be looked at as often as the tree looks at movement — so [`Motion`] decides
/// how often, and turning it down costs the animation resolution and nothing
/// else.
/// - [`Wake::At`] is a **deadline**. Something happens at that reading of the
/// clock: a carousel advances, a caret flips, a toast expires. [`Motion`] does
/// not touch it, because quantising a schedule to a frame rate would be a bug.
///
/// Both were `Option<u64>` before, and the difference was invisible.