maycoon_widgets/
animator.rs

1use maycoon_core::app::context::AppContext;
2use maycoon_core::app::info::AppInfo;
3use maycoon_core::app::update::Update;
4use maycoon_core::layout::{LayoutNode, StyleNode};
5use maycoon_core::vgi::Scene;
6use maycoon_core::widget::Widget;
7use maycoon_theme::id::WidgetId;
8use maycoon_theme::theme::Theme;
9use std::time::{Duration, Instant};
10
11/// A widget that animates another widget using an animation function.
12///
13/// The [WidgetId] is equal to `maycoon-widgets:Animator`.
14pub struct Animator<W: Widget, A: Fn(&mut W, f32) -> Update> {
15    start: Instant,
16    duration: Duration,
17    widget: W,
18    animation: A,
19}
20
21impl<W: Widget, A: Fn(&mut W, f32) -> Update> Animator<W, A> {
22    /// Creates a new animator widget with the given duration, child widget and animation function.
23    ///
24    /// The animation function is called with a value between `0.0` and `1.0` based on the elapsed time since the start of the animation
25    /// and the total duration of the animation.
26    #[inline(always)]
27    pub fn new(duration: Duration, widget: W, animation: A) -> Self {
28        Self {
29            start: Instant::now(),
30            duration,
31            widget,
32            animation,
33        }
34    }
35}
36
37impl<W: Widget, A: Fn(&mut W, f32) -> Update> Widget for Animator<W, A> {
38    #[inline(always)]
39    fn render(
40        &mut self,
41        scene: &mut dyn Scene,
42        theme: &mut dyn Theme,
43        layout_node: &LayoutNode,
44        info: &AppInfo,
45        context: AppContext,
46    ) {
47        self.widget.render(scene, theme, layout_node, info, context);
48    }
49
50    #[inline(always)]
51    fn layout_style(&self) -> StyleNode {
52        self.widget.layout_style()
53    }
54
55    fn update(&mut self, layout: &LayoutNode, context: AppContext, info: &AppInfo) -> Update {
56        let elapsed = self.start.elapsed();
57
58        let mut update = self.widget.update(layout, context, info);
59
60        if elapsed < self.duration {
61            let f = elapsed.as_secs_f32() / self.duration.as_secs_f32();
62
63            update.insert((self.animation)(&mut self.widget, f));
64        }
65
66        update
67    }
68
69    #[inline(always)]
70    fn widget_id(&self) -> WidgetId {
71        WidgetId::new("maycoon-widgets", "Animator")
72    }
73}