More text improvements, performance enhancements, input handling, text selection, wl cursors
This commit is contained in:
@@ -50,7 +50,7 @@ pub struct RoutedPointerEvent {
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PointerRouter {
|
||||
hovered: Option<HitTarget>,
|
||||
hovered: Vec<HitTarget>,
|
||||
pressed: Option<HitTarget>,
|
||||
}
|
||||
|
||||
@@ -60,7 +60,11 @@ impl PointerRouter {
|
||||
}
|
||||
|
||||
pub fn hovered_target(&self) -> Option<&HitTarget> {
|
||||
self.hovered.as_ref()
|
||||
self.hovered.last()
|
||||
}
|
||||
|
||||
pub fn hovered_targets(&self) -> &[HitTarget] {
|
||||
&self.hovered
|
||||
}
|
||||
|
||||
pub fn pressed_target(&self) -> Option<&HitTarget> {
|
||||
@@ -72,14 +76,21 @@ impl PointerRouter {
|
||||
interaction_tree: &InteractionTree,
|
||||
event: PointerEvent,
|
||||
) -> Vec<RoutedPointerEvent> {
|
||||
let hit_target = match event.kind {
|
||||
PointerEventKind::LeaveWindow => None,
|
||||
_ => interaction_tree.hit_test(event.position),
|
||||
let hovered_targets = match event.kind {
|
||||
PointerEventKind::LeaveWindow => Vec::new(),
|
||||
_ => interaction_tree.hit_path(event.position),
|
||||
};
|
||||
let hit_target = hovered_targets.last().cloned();
|
||||
|
||||
let mut routed = Vec::new();
|
||||
if self.hovered != hit_target {
|
||||
if let Some(previous) = self.hovered.take() {
|
||||
let shared_depth = self
|
||||
.hovered
|
||||
.iter()
|
||||
.zip(hovered_targets.iter())
|
||||
.take_while(|(previous, next)| previous == next)
|
||||
.count();
|
||||
if shared_depth != self.hovered.len() || shared_depth != hovered_targets.len() {
|
||||
for previous in self.hovered[shared_depth..].iter().rev().cloned() {
|
||||
routed.push(RoutedPointerEvent {
|
||||
kind: RoutedPointerEventKind::Leave,
|
||||
target: previous,
|
||||
@@ -87,20 +98,20 @@ impl PointerRouter {
|
||||
position: event.position,
|
||||
});
|
||||
}
|
||||
if let Some(target) = hit_target.clone() {
|
||||
for target in hovered_targets[shared_depth..].iter().cloned() {
|
||||
routed.push(RoutedPointerEvent {
|
||||
kind: RoutedPointerEventKind::Enter,
|
||||
target: target.clone(),
|
||||
target,
|
||||
pointer_id: event.pointer_id,
|
||||
position: event.position,
|
||||
});
|
||||
self.hovered = Some(target);
|
||||
}
|
||||
self.hovered = hovered_targets;
|
||||
}
|
||||
|
||||
match event.kind {
|
||||
PointerEventKind::Move => {
|
||||
if let Some(target) = hit_target {
|
||||
if let Some(target) = hit_target.clone() {
|
||||
routed.push(RoutedPointerEvent {
|
||||
kind: RoutedPointerEventKind::Move,
|
||||
target,
|
||||
@@ -144,7 +155,7 @@ mod tests {
|
||||
};
|
||||
use crate::layout::{InteractionTree, LayoutNode, LayoutPath};
|
||||
use crate::scene::{Point, Rect};
|
||||
use crate::tree::ElementId;
|
||||
use crate::tree::{CursorIcon, ElementId};
|
||||
|
||||
fn interaction_tree() -> InteractionTree {
|
||||
InteractionTree {
|
||||
@@ -153,12 +164,16 @@ mod tests {
|
||||
element_id: None,
|
||||
rect: Rect::new(0.0, 0.0, 200.0, 120.0),
|
||||
pointer_events: false,
|
||||
cursor: CursorIcon::Default,
|
||||
prepared_text: None,
|
||||
children: vec![
|
||||
LayoutNode {
|
||||
path: LayoutPath::root().child(0),
|
||||
element_id: Some(ElementId::new(1)),
|
||||
rect: Rect::new(0.0, 0.0, 120.0, 120.0),
|
||||
pointer_events: true,
|
||||
cursor: CursorIcon::Default,
|
||||
prepared_text: None,
|
||||
children: Vec::new(),
|
||||
},
|
||||
LayoutNode {
|
||||
@@ -166,6 +181,8 @@ mod tests {
|
||||
element_id: Some(ElementId::new(2)),
|
||||
rect: Rect::new(80.0, 0.0, 120.0, 120.0),
|
||||
pointer_events: true,
|
||||
cursor: CursorIcon::Default,
|
||||
prepared_text: None,
|
||||
children: Vec::new(),
|
||||
},
|
||||
],
|
||||
@@ -173,6 +190,36 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn nested_interaction_tree() -> InteractionTree {
|
||||
InteractionTree {
|
||||
root: LayoutNode {
|
||||
path: LayoutPath::root(),
|
||||
element_id: None,
|
||||
rect: Rect::new(0.0, 0.0, 200.0, 120.0),
|
||||
pointer_events: false,
|
||||
cursor: CursorIcon::Default,
|
||||
prepared_text: None,
|
||||
children: vec![LayoutNode {
|
||||
path: LayoutPath::root().child(0),
|
||||
element_id: Some(ElementId::new(1)),
|
||||
rect: Rect::new(0.0, 0.0, 160.0, 120.0),
|
||||
pointer_events: true,
|
||||
cursor: CursorIcon::Default,
|
||||
prepared_text: None,
|
||||
children: vec![LayoutNode {
|
||||
path: LayoutPath::root().child(0).child(0),
|
||||
element_id: Some(ElementId::new(2)),
|
||||
rect: Rect::new(16.0, 16.0, 80.0, 40.0),
|
||||
pointer_events: true,
|
||||
cursor: CursorIcon::Default,
|
||||
prepared_text: None,
|
||||
children: Vec::new(),
|
||||
}],
|
||||
}],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn router_emits_enter_and_move_for_new_hover_target() {
|
||||
let mut router = PointerRouter::new();
|
||||
@@ -223,4 +270,66 @@ mod tests {
|
||||
Some(ElementId::new(1))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn router_tracks_hovered_ancestors_for_nested_hits() {
|
||||
let mut router = PointerRouter::new();
|
||||
let routed = router.route(
|
||||
&nested_interaction_tree(),
|
||||
PointerEvent::new(0, Point::new(24.0, 24.0), PointerEventKind::Move),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
routed
|
||||
.iter()
|
||||
.filter(|event| event.kind == RoutedPointerEventKind::Enter)
|
||||
.map(|event| event.target.element_id)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![Some(ElementId::new(1)), Some(ElementId::new(2))]
|
||||
);
|
||||
assert_eq!(
|
||||
router
|
||||
.hovered_targets()
|
||||
.iter()
|
||||
.map(|target| target.element_id)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![Some(ElementId::new(1)), Some(ElementId::new(2))]
|
||||
);
|
||||
assert_eq!(
|
||||
router.hovered_target().unwrap().element_id,
|
||||
Some(ElementId::new(2))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn router_leaves_only_nested_child_when_pointer_moves_to_parent() {
|
||||
let mut router = PointerRouter::new();
|
||||
let tree = nested_interaction_tree();
|
||||
let _ = router.route(
|
||||
&tree,
|
||||
PointerEvent::new(0, Point::new(24.0, 24.0), PointerEventKind::Move),
|
||||
);
|
||||
|
||||
let routed = router.route(
|
||||
&tree,
|
||||
PointerEvent::new(0, Point::new(140.0, 24.0), PointerEventKind::Move),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
routed
|
||||
.iter()
|
||||
.filter(|event| event.kind == RoutedPointerEventKind::Leave)
|
||||
.map(|event| event.target.element_id)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![Some(ElementId::new(2))]
|
||||
);
|
||||
assert_eq!(
|
||||
router
|
||||
.hovered_targets()
|
||||
.iter()
|
||||
.map(|target| target.element_id)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![Some(ElementId::new(1))]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user