Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

masonry: set pointer-captured ancestors of hover target as hot #572

Closed
wants to merge 2 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions masonry/src/passes/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,30 @@ pub(crate) fn run_update_pointer_pass(root: &mut RenderRoot, root_state: &mut Wi

// -- UPDATE HOVERED WIDGETS --

let mut next_hovered_widget = if let Some(pos) = pointer_pos {
let next_hovered_widget = if let Some(pos) = pointer_pos {
// TODO - Apply scale?
root.get_root_widget()
.find_widget_at_pos(pos)
.map(|widget| widget.id())
} else {
None
};
// If the pointer is captured, it can either hover its capture target or nothing.
if let Some(capture_target) = root.state.pointer_capture_target {
if next_hovered_widget != Some(capture_target) {
next_hovered_widget = None;
}
}

// "Hovered path" means the widget which is considered hovered, and all its parents.
let prev_hovered_path = std::mem::take(&mut root.state.hovered_path);
let next_hovered_path = get_id_path(root, next_hovered_widget);
let next_hovered_path = {
let next_hovered_path = get_id_path(root, next_hovered_widget);
if let Some(capture_target) = root.state.pointer_capture_target {
// If the pointer is captured, it can only hover its capture target (and the capture
// target's ancestors) or nothing.
next_hovered_path
.into_iter()
.skip_while(|id| *id != capture_target)
.collect()
Copy link
Member Author

@tomcur tomcur Sep 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a potentially expensive memory operation that might be avoidable. We could short-circuit if there is a pointer capture target by traversing up the tree from that target, and then traverse downwards again to determine whether the pointer is inside the widget's and its ancestors' layout boxes. The search with find_widget_at_pos is then also unnecessary.

(For keyboard focus, the focus chain is kept in the widget state, something similar could be considered for pointer capture targets.)

} else {
next_hovered_path
}
};

let mut hovered_set = HashSet::new();
for widget_id in &next_hovered_path {
Expand Down