use std::collections::BTreeMap;
pub use azul_core::hit_test::FullHitTest;
use azul_core::{
dom::{DomId, DomNodeId, NodeId},
hit_test::{HitTest, HitTestItem},
window::MouseCursorType,
};
use azul_css::props::style::StyleCursor;
use crate::window::LayoutWindow;
#[derive(Debug, Clone, Default, PartialEq)]
pub struct CursorTypeHitTest {
pub cursor_node: Option<(DomId, NodeId)>,
pub cursor_icon: MouseCursorType,
}
impl CursorTypeHitTest {
pub fn new(hit_test: &FullHitTest, layout_window: &LayoutWindow) -> Self {
use azul_core::hit_test_tag::CursorType;
let mut cursor_node = None;
let mut cursor_icon = MouseCursorType::Default;
let mut best_depth: u32 = u32::MAX;
for (dom_id, hit_nodes) in hit_test.hovered_nodes.iter() {
let layout_result = match layout_window.get_layout_result(dom_id) {
Some(lr) => lr,
None => continue,
};
let styled_dom = &layout_result.styled_dom;
let node_data_container = styled_dom.node_data.as_container();
let styled_nodes = styled_dom.styled_nodes.as_container();
for (node_id, cursor_hit) in hit_nodes.cursor_hit_test_nodes.iter() {
let node_depth = cursor_hit.hit_depth;
if node_depth >= best_depth {
continue;
}
let mouse_cursor = translate_cursor_type(cursor_hit.cursor_type);
if mouse_cursor != MouseCursorType::Default {
cursor_node = Some((*dom_id, *node_id));
cursor_icon = mouse_cursor;
best_depth = node_depth;
}
}
for (node_id, hit_item) in hit_nodes.regular_hit_test_nodes.iter() {
let node_depth = hit_item.hit_depth;
if node_depth >= best_depth {
continue;
}
let cursor_prop = styled_dom.get_css_property_cache().get_cursor(
&node_data_container[*node_id],
node_id,
&styled_nodes[*node_id].styled_node_state,
);
if let Some(cursor_prop) = cursor_prop {
let css_cursor = cursor_prop.get_property().copied().unwrap_or_default();
cursor_node = Some((*dom_id, *node_id));
cursor_icon = translate_cursor(css_cursor);
best_depth = node_depth;
}
}
}
Self {
cursor_node,
cursor_icon,
}
}
}
fn translate_cursor_type(cursor_type: azul_core::hit_test_tag::CursorType) -> MouseCursorType {
use azul_core::hit_test_tag::CursorType;
match cursor_type {
CursorType::Default => MouseCursorType::Default,
CursorType::Pointer => MouseCursorType::Hand,
CursorType::Text => MouseCursorType::Text,
CursorType::Crosshair => MouseCursorType::Crosshair,
CursorType::Move => MouseCursorType::Move,
CursorType::NotAllowed => MouseCursorType::NotAllowed,
CursorType::Grab => MouseCursorType::Grab,
CursorType::Grabbing => MouseCursorType::Grabbing,
CursorType::EResize => MouseCursorType::EResize,
CursorType::WResize => MouseCursorType::WResize,
CursorType::NResize => MouseCursorType::NResize,
CursorType::SResize => MouseCursorType::SResize,
CursorType::EwResize => MouseCursorType::EwResize,
CursorType::NsResize => MouseCursorType::NsResize,
CursorType::NeswResize => MouseCursorType::NeswResize,
CursorType::NwseResize => MouseCursorType::NwseResize,
CursorType::ColResize => MouseCursorType::ColResize,
CursorType::RowResize => MouseCursorType::RowResize,
CursorType::Wait => MouseCursorType::Wait,
CursorType::Help => MouseCursorType::Help,
CursorType::Progress => MouseCursorType::Progress,
}
}
fn translate_cursor(cursor: StyleCursor) -> MouseCursorType {
use azul_css::props::style::effects::StyleCursor;
match cursor {
StyleCursor::Default => MouseCursorType::Default,
StyleCursor::Crosshair => MouseCursorType::Crosshair,
StyleCursor::Pointer => MouseCursorType::Hand,
StyleCursor::Move => MouseCursorType::Move,
StyleCursor::Text => MouseCursorType::Text,
StyleCursor::Wait => MouseCursorType::Wait,
StyleCursor::Help => MouseCursorType::Help,
StyleCursor::Progress => MouseCursorType::Progress,
StyleCursor::ContextMenu => MouseCursorType::ContextMenu,
StyleCursor::Cell => MouseCursorType::Cell,
StyleCursor::VerticalText => MouseCursorType::VerticalText,
StyleCursor::Alias => MouseCursorType::Alias,
StyleCursor::Copy => MouseCursorType::Copy,
StyleCursor::Grab => MouseCursorType::Grab,
StyleCursor::Grabbing => MouseCursorType::Grabbing,
StyleCursor::AllScroll => MouseCursorType::AllScroll,
StyleCursor::ZoomIn => MouseCursorType::ZoomIn,
StyleCursor::ZoomOut => MouseCursorType::ZoomOut,
StyleCursor::EResize => MouseCursorType::EResize,
StyleCursor::NResize => MouseCursorType::NResize,
StyleCursor::SResize => MouseCursorType::SResize,
StyleCursor::SeResize => MouseCursorType::SeResize,
StyleCursor::WResize => MouseCursorType::WResize,
StyleCursor::EwResize => MouseCursorType::EwResize,
StyleCursor::NsResize => MouseCursorType::NsResize,
StyleCursor::NeswResize => MouseCursorType::NeswResize,
StyleCursor::NwseResize => MouseCursorType::NwseResize,
StyleCursor::ColResize => MouseCursorType::ColResize,
StyleCursor::RowResize => MouseCursorType::RowResize,
StyleCursor::Unset => MouseCursorType::Default,
}
}
#[cfg(test)]
mod tests {
use super::*;
use azul_core::dom::DomNodeId;
use azul_core::dom::OptionDomNodeId;
#[test]
fn test_full_hit_test_empty() {
let hit_test = FullHitTest::empty(None);
assert!(hit_test.is_empty());
assert!(hit_test.focused_node.is_none());
}
#[test]
fn test_full_hit_test_with_focused_node() {
let focused = DomNodeId {
dom: DomId { inner: 0 },
node: azul_core::styled_dom::NodeHierarchyItemId::from_crate_internal(Some(
NodeId::new(5),
)),
};
let hit_test = FullHitTest::empty(Some(focused));
assert!(hit_test.is_empty()); assert_eq!(
hit_test.focused_node,
OptionDomNodeId::Some(DomNodeId {
dom: DomId { inner: 0 },
node: azul_core::styled_dom::NodeHierarchyItemId::from_crate_internal(Some(
NodeId::new(5),
)),
})
);
}
#[test]
fn test_cursor_type_hit_test_default() {
let cursor_test = CursorTypeHitTest::default();
assert_eq!(cursor_test.cursor_icon, MouseCursorType::Default);
assert!(cursor_test.cursor_node.is_none());
}
#[test]
fn test_translate_cursor_mapping() {
use azul_css::props::style::effects::StyleCursor;
assert_eq!(
translate_cursor(StyleCursor::Default),
MouseCursorType::Default
);
assert_eq!(
translate_cursor(StyleCursor::Pointer),
MouseCursorType::Hand
);
assert_eq!(translate_cursor(StyleCursor::Text), MouseCursorType::Text);
assert_eq!(translate_cursor(StyleCursor::Move), MouseCursorType::Move);
assert_eq!(
translate_cursor(StyleCursor::Crosshair),
MouseCursorType::Crosshair
);
}
}