use dioxus_native_core::NodeId;
use rustc_hash::{FxHashMap, FxHashSet};
use crate::{
dom_events::{does_event_move_cursor, DomEvent},
freya_events::FreyaEvent,
EventEmitter,
};
fn any_recent_mouse_movement(events: &[FreyaEvent]) -> Option<FreyaEvent> {
events
.iter()
.find(|event| {
if let FreyaEvent::Mouse { name, .. } = event {
does_event_move_cursor(name)
} else {
false
}
})
.cloned()
}
fn has_node_been_hovered_recently(events_to_emit: &[DomEvent], element: &NodeId) -> bool {
events_to_emit
.iter()
.find_map(|event| {
if event.does_move_cursor() && &event.node_id == element {
Some(false)
} else {
None
}
})
.unwrap_or(true)
}
#[derive(Default)]
pub struct EventsProcessor {
hovered_elements: FxHashSet<NodeId>,
}
impl EventsProcessor {
pub fn process_events(
&mut self,
events_to_emit: Vec<DomEvent>,
events: &[FreyaEvent],
event_emitter: &EventEmitter,
) -> FxHashMap<String, Vec<(NodeId, FreyaEvent)>> {
let mut new_events = FxHashMap::<String, Vec<(NodeId, FreyaEvent)>>::default();
let recent_mouse_movement_event = any_recent_mouse_movement(events);
self.hovered_elements.retain(|node_id| {
let no_recent_mouse_movement_on_me =
has_node_been_hovered_recently(&events_to_emit, node_id);
if no_recent_mouse_movement_on_me {
if let Some(FreyaEvent::Mouse { cursor, button, .. }) = recent_mouse_movement_event
{
let events = new_events.entry("mouseleave".to_string()).or_default();
events.push((
*node_id,
FreyaEvent::Mouse {
name: "mouseleave".to_string(),
cursor,
button,
},
));
return false;
}
}
true
});
for event in &events_to_emit {
let id = &event.node_id;
let should_trigger = match event.name.as_str() {
name @ "mouseover"
| name @ "mouseenter"
| name @ "pointerover"
| name @ "pointerenter" => {
let is_hovered = self.hovered_elements.contains(id);
if !is_hovered {
self.hovered_elements.insert(*id);
}
if name == "mouseenter" || name == "pointerenter" {
!is_hovered
} else {
true
}
}
_ => true,
};
if should_trigger {
event_emitter.send(event.clone()).unwrap();
}
}
for event in events_to_emit {
let id = &event.node_id;
if does_event_move_cursor(event.name.as_str()) && !self.hovered_elements.contains(id) {
self.hovered_elements.insert(*id);
}
}
new_events
}
}