fret_ui_kit/declarative/
hover_intent.rs1use fret_ui::{ElementContext, UiHost};
2
3use crate::declarative::scheduling;
4use crate::declarative::transition;
5use crate::headless::hover_intent::{HoverIntentConfig, HoverIntentState, HoverIntentUpdate};
6
7#[derive(Debug, Default, Clone, Copy)]
8struct HoverIntentDriverState {
9 last_frame_tick: Option<u64>,
10 tick: u64,
11 intent: HoverIntentState,
12}
13
14#[track_caller]
17pub fn hover_intent<H: UiHost>(
18 cx: &mut ElementContext<'_, H>,
19 hovered: bool,
20 cfg: HoverIntentConfig,
21) -> HoverIntentUpdate {
22 let (open_delay_ticks, close_delay_ticks) = transition::effective_transition_durations_for_cx(
23 &*cx,
24 cfg.open_delay_ticks,
25 cfg.close_delay_ticks,
26 );
27 let cfg = HoverIntentConfig::new(open_delay_ticks, close_delay_ticks);
28
29 let frame_tick = cx.app.frame_id().0;
30 let update = cx.slot_state(HoverIntentDriverState::default, |st| {
31 match st.last_frame_tick {
32 None => {
33 st.last_frame_tick = Some(frame_tick);
34 st.tick = frame_tick;
35 }
36 Some(prev) if prev != frame_tick => {
37 st.last_frame_tick = Some(frame_tick);
38 st.tick = frame_tick;
39 }
40 Some(_) => {
41 st.tick = st.tick.saturating_add(1);
44 }
45 }
46 st.intent.update(hovered, st.tick, cfg)
47 });
48
49 scheduling::set_continuous_frames(cx, update.wants_continuous_ticks);
50 update
51}