use std::collections::{BTreeMap, VecDeque};
use crate::hit_test::FullHitTest;
const MAX_HOVER_HISTORY: usize = 5;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum InputPointId {
Mouse,
Touch(u64),
}
#[derive(Debug, Clone, PartialEq)]
pub struct HoverManager {
hover_histories: BTreeMap<InputPointId, VecDeque<FullHitTest>>,
}
impl HoverManager {
pub fn new() -> Self {
Self {
hover_histories: BTreeMap::new(),
}
}
pub fn push_hit_test(&mut self, input_id: InputPointId, hit_test: FullHitTest) {
let history = self
.hover_histories
.entry(input_id)
.or_insert_with(|| VecDeque::with_capacity(MAX_HOVER_HISTORY));
history.push_front(hit_test);
if history.len() > MAX_HOVER_HISTORY {
history.pop_back();
}
}
pub fn remove_input_point(&mut self, input_id: &InputPointId) {
self.hover_histories.remove(input_id);
}
pub fn get_current(&self, input_id: &InputPointId) -> Option<&FullHitTest> {
self.hover_histories
.get(input_id)
.and_then(|history| history.front())
}
pub fn get_current_mouse(&self) -> Option<&FullHitTest> {
self.get_current(&InputPointId::Mouse)
}
pub fn get_frame(&self, input_id: &InputPointId, frames_ago: usize) -> Option<&FullHitTest> {
self.hover_histories
.get(input_id)
.and_then(|history| history.get(frames_ago))
}
pub fn get_history(&self, input_id: &InputPointId) -> Option<&VecDeque<FullHitTest>> {
self.hover_histories.get(input_id)
}
pub fn get_active_input_points(&self) -> Vec<InputPointId> {
self.hover_histories.keys().copied().collect()
}
pub fn frame_count(&self, input_id: &InputPointId) -> usize {
self.hover_histories
.get(input_id)
.map(|h| h.len())
.unwrap_or(0)
}
pub fn clear(&mut self) {
self.hover_histories.clear();
}
pub fn clear_input_point(&mut self, input_id: &InputPointId) {
if let Some(history) = self.hover_histories.get_mut(input_id) {
history.clear();
}
}
pub fn has_sufficient_history_for_gestures(&self, input_id: &InputPointId) -> bool {
self.frame_count(input_id) >= 2
}
pub fn any_has_sufficient_history_for_gestures(&self) -> bool {
self.hover_histories
.iter()
.any(|(_, history)| history.len() >= 2)
}
pub fn current_hover_node(&self) -> Option<azul_core::id::NodeId> {
let current = self.get_current_mouse()?;
let dom_id = azul_core::dom::DomId { inner: 0 };
let ht = current.hovered_nodes.get(&dom_id)?;
ht.regular_hit_test_nodes.keys().last().copied()
}
pub fn previous_hover_node(&self) -> Option<azul_core::id::NodeId> {
let history = self.hover_histories.get(&InputPointId::Mouse)?;
let previous = history.get(1)?; let dom_id = azul_core::dom::DomId { inner: 0 };
let ht = previous.hovered_nodes.get(&dom_id)?;
ht.regular_hit_test_nodes.keys().last().copied()
}
pub fn remap_node_ids(
&mut self,
dom_id: azul_core::dom::DomId,
node_id_map: &std::collections::BTreeMap<azul_core::id::NodeId, azul_core::id::NodeId>,
) {
for history in self.hover_histories.values_mut() {
for hit_test in history.iter_mut() {
if let Some(ht) = hit_test.hovered_nodes.get_mut(&dom_id) {
let old_regular: Vec<_> = ht.regular_hit_test_nodes.keys().cloned().collect();
let mut new_regular = std::collections::BTreeMap::new();
for old_nid in old_regular {
if let Some(&new_nid) = node_id_map.get(&old_nid) {
if let Some(item) = ht.regular_hit_test_nodes.remove(&old_nid) {
new_regular.insert(new_nid, item);
}
}
}
ht.regular_hit_test_nodes = new_regular;
let old_scroll: Vec<_> = ht.scroll_hit_test_nodes.keys().cloned().collect();
let mut new_scroll = std::collections::BTreeMap::new();
for old_nid in old_scroll {
if let Some(&new_nid) = node_id_map.get(&old_nid) {
if let Some(item) = ht.scroll_hit_test_nodes.remove(&old_nid) {
new_scroll.insert(new_nid, item);
}
}
}
ht.scroll_hit_test_nodes = new_scroll;
let old_cursor: Vec<_> = ht.cursor_hit_test_nodes.keys().cloned().collect();
let mut new_cursor = std::collections::BTreeMap::new();
for old_nid in old_cursor {
if let Some(&new_nid) = node_id_map.get(&old_nid) {
if let Some(item) = ht.cursor_hit_test_nodes.remove(&old_nid) {
new_cursor.insert(new_nid, item);
}
}
}
ht.cursor_hit_test_nodes = new_cursor;
let old_sb: Vec<_> = ht.scrollbar_hit_test_nodes.keys().cloned().collect();
let mut new_sb = std::collections::BTreeMap::new();
for old_key in old_sb {
let new_key = remap_scrollbar_hit_id(&old_key, dom_id, node_id_map);
if let Some(item) = ht.scrollbar_hit_test_nodes.remove(&old_key) {
new_sb.insert(new_key, item);
}
}
ht.scrollbar_hit_test_nodes = new_sb;
}
}
}
}
}
impl Default for HoverManager {
fn default() -> Self {
Self::new()
}
}
fn remap_scrollbar_hit_id(
id: &azul_core::hit_test::ScrollbarHitId,
dom_id: azul_core::dom::DomId,
node_id_map: &std::collections::BTreeMap<azul_core::id::NodeId, azul_core::id::NodeId>,
) -> azul_core::hit_test::ScrollbarHitId {
use azul_core::hit_test::ScrollbarHitId;
match id {
ScrollbarHitId::VerticalTrack(d, n) if *d == dom_id => {
ScrollbarHitId::VerticalTrack(*d, *node_id_map.get(n).unwrap_or(n))
}
ScrollbarHitId::VerticalThumb(d, n) if *d == dom_id => {
ScrollbarHitId::VerticalThumb(*d, *node_id_map.get(n).unwrap_or(n))
}
ScrollbarHitId::HorizontalTrack(d, n) if *d == dom_id => {
ScrollbarHitId::HorizontalTrack(*d, *node_id_map.get(n).unwrap_or(n))
}
ScrollbarHitId::HorizontalThumb(d, n) if *d == dom_id => {
ScrollbarHitId::HorizontalThumb(*d, *node_id_map.get(n).unwrap_or(n))
}
other => other.clone(),
}
}