tuigui/widgets/
animation_container.rs

1use crate::preludes::widget_creation::*;
2
3#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
4pub enum AnimationContainerSequence<A: crate::Animation> {
5    Single(A),
6    Many(Vec<A>),
7}
8
9#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
10/// Play widget animations
11pub struct AnimationContainer<W: Widget, A: crate::Animation> {
12    pub widget: W,
13    pub sequence: AnimationContainerSequence<A>,
14    index: usize,
15    prev_transform: Option<Transform>,
16    new_start_transform: Option<Transform>,
17    is_playing: bool,
18    paused_time: Option<std::time::Instant>,
19    paused_duration: std::time::Duration,
20    is_done: bool,
21    widget_data: WidgetData,
22}
23
24impl<W: Widget, A: crate::Animation> AnimationContainer<W, A> {
25    /// Create new animation container
26    pub fn new(sequence: AnimationContainerSequence<A>, autoplay: bool, widget: W) -> Self {
27        Self {
28            widget,
29            sequence,
30            index: 0,
31            prev_transform: None,
32            new_start_transform: None,
33            is_playing: autoplay,
34            paused_time: None,
35            paused_duration: std::time::Duration::ZERO,
36            is_done: false,
37            widget_data: WidgetData::new(),
38        }
39    }
40
41    /// Play/resume animation(s)
42    pub fn play(&mut self) {
43        if self.is_playing == false {
44            self.is_playing = true;
45
46            if let Some(paused_time) = self.paused_time {
47                let duration = std::time::Instant::now() - paused_time;
48
49                self.paused_duration += duration;
50            }
51
52            else {
53                self.soft_reset();
54            }
55        }
56    }
57
58    /// Pause animation(s)
59    pub fn pause(&mut self) {
60        if self.is_playing {
61            self.is_playing = false;
62            self.paused_time = Some(std::time::Instant::now());
63        }
64    }
65
66    /// Returns 'true' if the animations are playing (not paused)
67    pub fn is_playing(&self) -> bool {
68        return self.is_playing;
69    }
70
71    /// Returns 'true' if all the animations have finished
72    pub fn has_finished(&self) -> bool {
73        return self.is_done;
74    }
75
76    /// Reset the animations
77    pub fn reset(&mut self, autoplay: bool) {
78        self.index = 0;
79        self.is_done = false;
80        self.is_playing = autoplay;
81        self.soft_reset();
82    }
83
84    fn soft_reset(&mut self) {
85        self.paused_time = None;
86        self.paused_duration = std::time::Duration::ZERO;
87        self.widget.widget_data().animation_data.reset();
88    }
89}
90
91impl<W: Widget, A: crate::Animation> Widget for AnimationContainer<W, A> {
92    fn draw(&mut self, canvas: &mut Canvas, state_frame: Option<&EventStateFrame>) {
93        let is_playing = self.is_playing();
94        let is_done = self.has_finished();
95
96        let child_data = self.widget.widget_data();
97
98        // The transform to use if the animation is unable to animate.
99        // (Either paused or done.)
100        let static_rest = self.prev_transform.unwrap_or(canvas.original_transform());
101
102        if is_playing && is_done == false {
103            let offset: f64 = -self.paused_duration.as_secs_f64();
104
105            let (animation, is_single) = match self.sequence {
106                AnimationContainerSequence::Single(ref mut single) => (Some(single), true),
107                AnimationContainerSequence::Many(ref mut many) => (many.get_mut(self.index), false),
108            };
109
110            if let Some(animation) = animation {
111                canvas.animate_with_offset(
112                    animation,
113                    &child_data.animation_data,
114                    self.new_start_transform,
115                    offset
116                );
117
118                self.prev_transform = Some(canvas.transform);
119
120                if animation.is_done(
121                    child_data.animation_data.duration()
122                        .as_secs_f64() + offset,
123                ) {
124                    if is_single {
125                        self.is_done = true;
126                    } else {
127                        self.index += 1;
128                        self.new_start_transform = Some(canvas.transform);
129                        self.soft_reset();
130                    }
131                }
132            }
133
134            else {
135                self.is_done = true;
136                canvas.transform = static_rest;
137            }
138        }
139
140        else {
141            canvas.transform = static_rest;
142        }
143
144        self.widget.draw(canvas, state_frame);
145    }
146
147    fn widget_info(&self) -> WidgetInfo {
148        return self.widget.widget_info();
149    }
150
151    fn widget_data(&mut self) -> &mut WidgetData {
152        return &mut self.widget_data;
153    }
154}