qframe/widget/context/animation.rs
1//! Drawing named one-cell animations while painting.
2
3use std::time::Duration;
4
5use super::PaintCx;
6use super::paint::ANIMATION_FRAME;
7use crate::animation::AnimatedCell;
8use crate::style::CellStyle;
9
10impl PaintCx<'_> {
11 /// The cell the animation `name` shows now, drawn in `style`: frames without a colour, and
12 /// `$fg` in colour expressions, take `style.fg`. Draw it with [`PaintCx::text`] in one cell.
13 ///
14 /// `since` is when the animation started on the [`PaintCx::now`] clock; looping indicators
15 /// pass `Some(Duration::ZERO)` so they turn in step with every other one, and `None` shows the
16 /// rest frame. With reduced motion the rest frame always shows. Schedules the next frame
17 /// exactly when the frame changes, and smooth frames while a colour pulses or blends. An
18 /// unknown name draws `⟦name⟧`, cut to the cell, like a missing icon.
19 ///
20 /// ```
21 /// # use std::time::Duration;
22 /// # use qframe::widget::PaintCx;
23 /// # use qframe::geometry::Rect;
24 /// fn paint_busy_mark(cx: &mut PaintCx<'_>, area: Rect) {
25 /// let style = cx.style("spinner", None, &[]).text();
26 /// let cell = cx.animation("spinner-pulse", style, Some(Duration::ZERO));
27 /// cx.text(area.x, area.y, &cell.glyph, cell.style, 1);
28 /// }
29 /// ```
30 pub fn animation(&mut self, name: &str, style: CellStyle, since: Option<Duration>) -> AnimatedCell {
31 let env = self.env;
32 let Some(animation) = env.icons().animation(name) else {
33 return AnimatedCell { glyph: format!("⟦{name}⟧"), style, finished: true };
34 };
35 let since = since.filter(|_| !env.reduced_motion());
36 let frame = animation.sample(env.theme(), style.fg, self.now, since);
37 if since.is_some() {
38 if frame.smooth {
39 self.request_frame_in(ANIMATION_FRAME);
40 } else if let Some(next) = frame.next {
41 self.request_frame_in(next);
42 }
43 }
44 let glyph = animation.glyph(frame.index, env.icons().mode()).to_owned();
45 AnimatedCell { glyph, style: CellStyle { fg: frame.color.or(style.fg), ..style }, finished: frame.finished }
46 }
47}