Skip to main content

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}