Skip to content

Commit

Permalink
The Bevy UI backend doesn't check for clipping, and allows interactio…
Browse files Browse the repository at this point in the history
…n with clipped non-visible sections of UI nodes.

This PR intersects the node rect with its calculated clip rect (if it has one) and then checks if the clipped node contains the cursor.
  • Loading branch information
ickshonpe committed Nov 27, 2023
1 parent 1471a9f commit 4df4b1c
Showing 1 changed file with 8 additions and 18 deletions.
26 changes: 8 additions & 18 deletions backends/bevy_picking_ui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ pub fn ui_picking(
cameras: Query<(Entity, &Camera, Option<&UiCameraConfig>)>,
primary_window: Query<Entity, With<PrimaryWindow>>,
ui_stack: Res<UiStack>,
ui_scale: Res<UiScale>,
mut node_query: Query<NodeQuery>,
mut output: EventWriter<PointerHits>,
) {
Expand Down Expand Up @@ -120,24 +121,13 @@ pub fn ui_picking(
}
}

let position = node.global_transform.translation();
let ui_position = position.truncate();
let extents = node.node.size() / 2.0;
let mut min = ui_position - extents;
if let Some(clip) = node.calculated_clip {
min = Vec2::max(min, clip.clip.min);
}

// The mouse position relative to the node
// (0., 0.) is the top-left corner, (1., 1.) is the bottom-right corner
let relative_cursor_position = Vec2::new(
(location.position.x - min.x) / node.node.size().x,
(location.position.y - min.y) / node.node.size().y,
);

if (0.0..1.).contains(&relative_cursor_position.x)
&& (0.0..1.).contains(&relative_cursor_position.y)
{
let node_rect = node.node.logical_rect(node.global_transform);
let visible_rect = node
.calculated_clip
.map(|clip| node_rect.intersect(clip.clip))
.unwrap_or(node_rect);
let cursor_position = location.position / ui_scale.0 as f32;
if visible_rect.contains(cursor_position) {
Some(*entity)
} else {
None
Expand Down

0 comments on commit 4df4b1c

Please sign in to comment.