pub enum Motion {
Every(u64),
None,
}Expand description
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.
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.
Variants§
Every(u64)
Sample every animation in flight this often, in milliseconds.
Clamped to at least 1 ms: zero would ask the event loop never to sleep, which is not a frame rate but a busy loop.
None
Do not animate. Transitions land at their end state immediately, and nothing in the tree asks to be woken for movement.
This is the prefers-reduced-motion answer, and the right setting on
hardware where any animation is a bad trade. It stops motion, not
schedules: a tooltip still appears after its dwell, a toast still
goes after its hold, a carousel still advances — those are deadlines,
and a deadline is not a frame rate.
Implementations§
Source§impl Motion
impl Motion
Sourcepub const DEFAULT_INTERVAL_MS: u64 = 16
pub const DEFAULT_INTERVAL_MS: u64 = 16
Sixty frames a second, the default.
Sixty rather than twenty because a rotating arc is the animation least forgiving of a low rate: a caret can blink twice a second and a knob can cross in eight frames, but a ring turning in visible steps reads as a stutter rather than as a style.
The spinner said twenty for a while, on the argument that twenty is above
the rate at which a rotation stops reading as separate positions and
costs a third of the wakes. The first half of that turned out to be wrong
by eye: asked for twenty and given twenty, the arc is visibly steppy. It
had never actually been tried, because until the desktop backend started
honouring next_wake_ms the loop free-ran at 60 Hz and quietly delivered
sixty.
The second half was right, and is why sixty is affordable: the drawing is
not the expense — the #17 bench puts a spinner-sized arc at about three
microseconds — the wake is, and each wake ends in a present. That was
costing 16 MB of copying on macOS until denise-winit started handing the
compositor an IOSurface; a present there is now free, a DRM page flip
always was, and win32 blits the damage rectangle.
Which is also why it is a default and not a constant. Sixty wakes a second for a widget that can keep a device awake indefinitely is a small cost on a desktop and a real one on a battery.
Sourcepub const fn interval_ms(self) -> Option<u64>
pub const fn interval_ms(self) -> Option<u64>
The sampling interval in milliseconds, or None under Motion::None.