ferroui_base/animation/
clock_base.rs1use crate::animation::{PlayState, TimeSpan};
2use crate::reactive::{IDisposable, IObservable, IObserver, LightweightSubject};
3use std::cell::Cell;
4use std::rc::Rc;
5
6pub struct ClockBase {
13 observable: LightweightSubject<TimeSpan>,
14 previous_time: Cell<Option<TimeSpan>>,
15 internal_time: Cell<TimeSpan>,
16 play_state: Cell<PlayState>,
17}
18
19impl Default for ClockBase {
20 fn default() -> Self {
21 Self::new()
22 }
23}
24
25impl ClockBase {
26 pub fn new() -> Self {
27 Self {
28 observable: LightweightSubject::new(),
29 previous_time: Cell::new(None),
30 internal_time: Cell::new(TimeSpan::ZERO),
31 play_state: Cell::new(PlayState::Run),
32 }
33 }
34
35 pub fn has_subscriptions(&self) -> bool {
37 self.observable.has_observers()
38 }
39
40 #[inline]
42 pub fn play_state(&self) -> PlayState {
43 self.play_state.get()
44 }
45
46 #[inline]
48 pub fn set_play_state(&self, value: PlayState) {
49 self.play_state.set(value)
50 }
51
52 pub fn pulse(&self, system_time: TimeSpan, stop: impl FnOnce()) {
55 match self.previous_time.get() {
56 None => {
57 self.previous_time.set(Some(system_time));
58 self.internal_time.set(TimeSpan::ZERO);
59 }
60 Some(previous_time) => {
61 if self.play_state.get() == PlayState::Pause {
62 self.previous_time.set(Some(system_time));
63 return;
64 }
65 let delta = system_time - previous_time;
66 self.internal_time.set(self.internal_time.get() + delta);
67 self.previous_time.set(Some(system_time));
68 }
69 }
70
71 self.observable.on_next(self.internal_time.get());
72
73 if self.play_state.get() == PlayState::Stop {
74 stop();
75 }
76 }
77
78 pub fn subscribe(&self, observer: Rc<dyn IObserver<TimeSpan>>) -> Rc<dyn IDisposable> {
80 self.observable.subscribe(observer)
81 }
82}