Skip to main content

fret_ui_headless/
tooltip_delay_group.rs

1//! Tooltip provider delay-group logic (Radix-aligned outcomes).
2//!
3//! Radix tooltips commonly share a delay provider so:
4//! - the first tooltip opens after a delay, but
5//! - moving between tooltips shortly after closing skips the delay.
6
7#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
8pub struct TooltipDelayGroupConfig {
9    pub delay_ticks: u64,
10    pub skip_delay_ticks: u64,
11}
12
13impl TooltipDelayGroupConfig {
14    pub fn new(delay_ticks: u64, skip_delay_ticks: u64) -> Self {
15        Self {
16            delay_ticks,
17            skip_delay_ticks,
18        }
19    }
20}
21
22#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
23pub struct TooltipDelayGroupState {
24    pub last_closed_at: Option<u64>,
25}
26
27impl TooltipDelayGroupState {
28    pub fn open_delay_ticks(&self, now: u64, cfg: TooltipDelayGroupConfig) -> u64 {
29        if cfg.delay_ticks == 0 {
30            return 0;
31        }
32        let Some(last) = self.last_closed_at else {
33            return cfg.delay_ticks;
34        };
35        if cfg.skip_delay_ticks == 0 {
36            return cfg.delay_ticks;
37        }
38        let elapsed = now.saturating_sub(last);
39        if elapsed <= cfg.skip_delay_ticks {
40            0
41        } else {
42            cfg.delay_ticks
43        }
44    }
45
46    pub fn note_closed(&mut self, now: u64) {
47        self.last_closed_at = Some(now);
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn open_delay_is_skipped_within_skip_window() {
57        let mut st = TooltipDelayGroupState::default();
58        let cfg = TooltipDelayGroupConfig::new(10, 30);
59
60        assert_eq!(st.open_delay_ticks(100, cfg), 10);
61
62        st.note_closed(120);
63        assert_eq!(st.open_delay_ticks(121, cfg), 0);
64        assert_eq!(st.open_delay_ticks(150, cfg), 0);
65        assert_eq!(st.open_delay_ticks(151, cfg), 10);
66    }
67
68    #[test]
69    fn zero_delay_always_opens_immediately() {
70        let mut st = TooltipDelayGroupState::default();
71        let cfg = TooltipDelayGroupConfig::new(0, 30);
72
73        assert_eq!(st.open_delay_ticks(10, cfg), 0);
74        st.note_closed(20);
75        assert_eq!(st.open_delay_ticks(21, cfg), 0);
76    }
77}