use std::cell::Cell;
use std::time::Duration;
use web_time::Instant;
std::thread_local! {
static NEEDS_DRAW: Cell<bool> = Cell::new(false);
static NEXT_DRAW_AT: Cell<Option<Instant>> = Cell::new(None);
static INVALIDATION_EPOCH: Cell<u64> = Cell::new(0);
}
pub fn request_draw() {
NEEDS_DRAW.with(|c| c.set(true));
INVALIDATION_EPOCH.with(|c| c.set(c.get().wrapping_add(1)));
}
pub fn request_draw_without_invalidation() {
NEEDS_DRAW.with(|c| c.set(true));
}
pub fn wants_draw() -> bool {
NEEDS_DRAW.with(|c| c.get())
}
pub fn invalidation_epoch() -> u64 {
INVALIDATION_EPOCH.with(|c| c.get())
}
pub fn clear_draw_request() {
NEEDS_DRAW.with(|c| c.set(false));
NEXT_DRAW_AT.with(|c| c.set(None));
}
pub fn request_draw_after(delay: Duration) {
let when = Instant::now() + delay;
NEXT_DRAW_AT.with(|c| match c.get() {
Some(existing) if existing <= when => {}
_ => c.set(Some(when)),
});
}
pub fn take_next_draw_deadline() -> Option<Instant> {
NEXT_DRAW_AT.with(|c| c.replace(None))
}
#[derive(Clone, Copy)]
pub struct Tween {
current: f64,
start_value: f64,
target: f64,
start_time: Option<Instant>,
duration: f64,
}
impl Tween {
pub const fn new(initial: f64, duration_secs: f64) -> Self {
Self {
current: initial,
start_value: initial,
target: initial,
start_time: None,
duration: duration_secs,
}
}
pub fn set_target(&mut self, new_target: f64) {
if (self.target - new_target).abs() > 1e-9 {
self.start_value = self.current;
self.target = new_target;
self.start_time = Some(Instant::now());
}
}
pub fn tick(&mut self) -> f64 {
if let Some(start) = self.start_time {
let elapsed = start.elapsed().as_secs_f64();
let p = (elapsed / self.duration).min(1.0);
let eased = 1.0 - (1.0 - p).powi(3);
self.current = self.start_value + (self.target - self.start_value) * eased;
if p >= 1.0 {
self.current = self.target;
self.start_time = None;
} else {
request_draw();
}
}
self.current
}
pub fn value(&self) -> f64 {
self.current
}
pub fn is_animating(&self) -> bool {
self.start_time.is_some()
}
}
impl Default for Tween {
fn default() -> Self {
Self::new(0.0, 0.12)
}
}