Skip to main content

freya_core/
animation_clock.rs

1use std::{
2    sync::{
3        Arc,
4        atomic::{
5            AtomicU32,
6            Ordering,
7        },
8    },
9    time::Duration,
10};
11
12use tracing::info;
13
14use crate::prelude::consume_root_context;
15
16/// Controls the animation speed of this window.
17#[derive(Clone)]
18pub struct AnimationClock(Arc<AtomicU32>);
19
20#[doc(hidden)]
21pub trait New: sealed::Sealed {
22    fn new() -> Self;
23}
24
25impl New for AnimationClock {
26    fn new() -> Self {
27        Self(Arc::new(AtomicU32::new(Self::DEFAULT_SPEED.to_bits())))
28    }
29}
30
31mod sealed {
32    pub trait Sealed {}
33    impl Sealed for crate::animation_clock::AnimationClock {}
34}
35
36impl AnimationClock {
37    /// Normal speed.
38    pub const DEFAULT_SPEED: f32 = 1.0;
39    /// Lowest allowed speed.
40    pub const MIN_SPEED: f32 = 0.05;
41    /// Highest allowed speed.
42    pub const MAX_SPEED: f32 = 5.0;
43    /// Speed that makes animations finish instantly.
44    pub const DISABLED_SPEED: f32 = 999_999_999.0;
45
46    /// Retrieve the current [`AnimationClock`] from the root context.
47    #[track_caller]
48    pub fn get() -> Self {
49        consume_root_context()
50    }
51
52    /// Get the current speed.
53    pub fn speed(&self) -> f32 {
54        let bits = self.0.load(Ordering::Relaxed);
55        (f32::from_bits(bits) * 100.0).round() / 100.0
56    }
57
58    /// Enable animations.
59    pub fn enable(&self) {
60        self.0
61            .store(Self::DEFAULT_SPEED.to_bits(), Ordering::Relaxed);
62        info!("Animation clock speed enabled");
63    }
64
65    /// Disable animations.
66    pub fn disable(&self) {
67        self.0
68            .store(Self::DISABLED_SPEED.to_bits(), Ordering::Relaxed);
69        info!("Animation clock speed disabled");
70    }
71
72    /// Update the speed.
73    pub fn set_speed(&self, speed: f32) {
74        let speed = speed.clamp(Self::MIN_SPEED, Self::MAX_SPEED);
75        self.0.store(speed.to_bits(), Ordering::Relaxed);
76        info!("Animation clock speed changed to {:.2}x", speed);
77    }
78
79    /// Scale a duration by the current speed.
80    pub fn correct_elapsed_duration(&self, elapsed: Duration) -> Duration {
81        let scaled_secs = elapsed.as_secs_f32() * self.speed();
82        Duration::from_secs_f32(scaled_secs)
83    }
84}