use crate::animation::{PlayState, TimeSpan};
use crate::reactive::{IDisposable, IObservable, IObserver, LightweightSubject};
use std::cell::Cell;
use std::rc::Rc;
pub struct ClockBase {
observable: LightweightSubject<TimeSpan>,
previous_time: Cell<Option<TimeSpan>>,
internal_time: Cell<TimeSpan>,
play_state: Cell<PlayState>,
}
impl Default for ClockBase {
fn default() -> Self {
Self::new()
}
}
impl ClockBase {
pub fn new() -> Self {
Self {
observable: LightweightSubject::new(),
previous_time: Cell::new(None),
internal_time: Cell::new(TimeSpan::ZERO),
play_state: Cell::new(PlayState::Run),
}
}
pub fn has_subscriptions(&self) -> bool {
self.observable.has_observers()
}
#[inline]
pub fn play_state(&self) -> PlayState {
self.play_state.get()
}
#[inline]
pub fn set_play_state(&self, value: PlayState) {
self.play_state.set(value)
}
pub fn pulse(&self, system_time: TimeSpan, stop: impl FnOnce()) {
match self.previous_time.get() {
None => {
self.previous_time.set(Some(system_time));
self.internal_time.set(TimeSpan::ZERO);
}
Some(previous_time) => {
if self.play_state.get() == PlayState::Pause {
self.previous_time.set(Some(system_time));
return;
}
let delta = system_time - previous_time;
self.internal_time.set(self.internal_time.get() + delta);
self.previous_time.set(Some(system_time));
}
}
self.observable.on_next(self.internal_time.get());
if self.play_state.get() == PlayState::Stop {
stop();
}
}
pub fn subscribe(&self, observer: Rc<dyn IObserver<TimeSpan>>) -> Rc<dyn IDisposable> {
self.observable.subscribe(observer)
}
}