1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
use std::{cmp::Ordering, rc::Rc};
use web_time::{Duration, Instant};
use crate::{context::EventContext, entity::Entity};
/// Enum which can be used to determine the reason a timer callback was called.
///
/// When a timer is ticked (called after some interval), the frame rate may not be in sync with the timer rate.
/// This will affect the accuracy of the timer. To account for this, the `Tick` variant provides a `delta` duration,
/// which is the time difference between the current frame time and the timer time. Typically this will be 0-2 ms.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TimerAction {
// The timer was started.
Start,
// The timer was ticked, i.e. called after an interval. The `delta` represents the time difference between the current frame time and the timer time.
Tick(Duration),
// The timer was stopped.
Stop,
}
#[derive(Clone)]
pub struct TimerState {
pub(crate) entity: Entity,
pub(crate) id: Timer,
pub(crate) time: Instant,
pub(crate) interval: Duration,
pub(crate) duration: Option<Duration>,
pub(crate) start_time: Instant,
pub(crate) callback: Rc<dyn Fn(&mut EventContext, TimerAction)>,
pub(crate) ticking: bool,
pub(crate) stopping: bool,
}
impl TimerState {
pub fn start_time(&self) -> Instant {
self.start_time
}
pub fn end_time(&self) -> Option<Instant> {
self.duration.map(|duration| self.start_time + duration)
}
/// Sets the tick interval of the timer.
pub fn set_interval(&mut self, interval: Duration) -> &mut Self {
self.interval = interval;
self
}
/// Sets the duration of the timer. Pass `None` for a timer which ticks forever.
pub fn set_duration(&mut self, duration: Option<Duration>) -> &mut Self {
self.duration = duration;
self
}
/// Returns the duration of the timer.
pub fn duration(&self) -> Option<Duration> {
self.duration
}
/// Returns the tick interval of the timer.
pub fn interval(&self) -> Duration {
self.interval
}
/// Converts the timer to an `f32` value indicating the progress of the timer between zero and one. Returns `None` for a timer with no fixed duration.
pub fn progress(&self) -> Option<f32> {
self.duration.map(|duration| {
((self.time - self.start_time).as_secs_f32() / duration.as_secs_f32()).clamp(0.0, 1.0)
})
}
}
impl PartialEq<Self> for TimerState {
fn eq(&self, other: &Self) -> bool {
self.time.eq(&other.time)
}
}
impl Eq for TimerState {}
impl PartialOrd for TimerState {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for TimerState {
fn cmp(&self, other: &Self) -> Ordering {
self.time.cmp(&other.time).reverse()
}
}
/// A handle used to start, stop, and check the running status of a timer added with `cx.add_timer()`.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct Timer(pub usize);