use std::cell::RefCell;
use std::rc::Rc;
use web_time::{Duration, Instant};
use repose_core::input::{PointerId, PointerKind};
const FIRST_DELAY_MS: u64 = 300;
const REPEAT_MS: u64 = 100;
const MOUSE_POINTER: u64 = u64::MAX;
pub fn pointer_key(kind: PointerKind, id: PointerId) -> u64 {
match kind {
PointerKind::Touch => id.0,
_ => MOUSE_POINTER,
}
}
pub fn key_for_touch(touch: Option<u64>) -> u64 {
touch.unwrap_or(MOUSE_POINTER)
}
struct ActiveRepeat {
pointer: u64,
next_fire: Instant,
page: Rc<dyn Fn()>,
}
thread_local! {
static ACTIVE: RefCell<Option<ActiveRepeat>> = const { RefCell::new(None) };
}
pub fn begin_track_repeat(pointer: u64, page: Rc<dyn Fn()>) {
ACTIVE.with(|active| {
*active.borrow_mut() = Some(ActiveRepeat {
pointer,
next_fire: Instant::now() + Duration::from_millis(FIRST_DELAY_MS),
page,
});
});
}
pub fn cancel_track_repeat(pointer: u64) {
ACTIVE.with(|active| {
let mut slot = active.borrow_mut();
if slot
.as_ref()
.is_some_and(|repeat| repeat.pointer == pointer)
{
*slot = None;
}
});
}
pub fn cancel_all_track_repeats() {
ACTIVE.with(|active| {
*active.borrow_mut() = None;
});
}
pub fn cancel_track_repeat_for_touch(touch: Option<u64>) {
cancel_track_repeat(key_for_touch(touch));
}
pub fn poll_track_repeat() -> bool {
let now = Instant::now();
let page = ACTIVE.with(|active| {
let mut slot = active.borrow_mut();
match slot.as_mut() {
Some(repeat) if now >= repeat.next_fire => {
repeat.next_fire = now + Duration::from_millis(REPEAT_MS);
Some(repeat.page.clone())
}
_ => None,
}
});
match page {
Some(page) => {
page();
repose_core::request_frame();
true
}
None => false,
}
}
pub fn track_repeat_deadline() -> Option<Instant> {
ACTIVE.with(|active| active.borrow().as_ref().map(|repeat| repeat.next_fire))
}