Skip to content

Commit

Permalink
bevy_ui: Check clip when handling interactions (#3461)
Browse files Browse the repository at this point in the history
# Objective

Fix a bug: UI nodes that are clipped could still be interacted with in the clipped area.

## Solution

Clip the position calculation in `ui_focus_system`
  • Loading branch information
Davier committed Dec 28, 2021
1 parent 3a9d5a6 commit 601cc0c
Showing 1 changed file with 12 additions and 5 deletions.
17 changes: 12 additions & 5 deletions crates/bevy_ui/src/focus.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::Node;
use crate::{CalculatedClip, Node};
use bevy_core::FloatOrd;
use bevy_ecs::{
entity::Entity,
Expand All @@ -7,6 +7,7 @@ use bevy_ecs::{
system::{Local, Query, Res},
};
use bevy_input::{mouse::MouseButton, touch::Touches, Input};
use bevy_math::Vec2;
use bevy_reflect::{Reflect, ReflectDeserialize};
use bevy_transform::components::GlobalTransform;
use bevy_window::Windows;
Expand Down Expand Up @@ -57,6 +58,7 @@ pub fn ui_focus_system(
&GlobalTransform,
Option<&mut Interaction>,
Option<&FocusPolicy>,
Option<&CalculatedClip>,
)>,
) {
let cursor_position = if let Some(cursor_position) = windows
Expand All @@ -78,7 +80,8 @@ pub fn ui_focus_system(
let mouse_released =
mouse_button_input.just_released(MouseButton::Left) || touches_input.just_released(0);
if mouse_released {
for (_entity, _node, _global_transform, interaction, _focus_policy) in node_query.iter_mut()
for (_entity, _node, _global_transform, interaction, _focus_policy, _clip) in
node_query.iter_mut()
{
if let Some(mut interaction) = interaction {
if *interaction == Interaction::Clicked {
Expand All @@ -94,12 +97,16 @@ pub fn ui_focus_system(
let mut moused_over_z_sorted_nodes = node_query
.iter_mut()
.filter_map(
|(entity, node, global_transform, interaction, focus_policy)| {
|(entity, node, global_transform, interaction, focus_policy, clip)| {
let position = global_transform.translation;
let ui_position = position.truncate();
let extents = node.size / 2.0;
let min = ui_position - extents;
let max = ui_position + extents;
let mut min = ui_position - extents;
let mut max = ui_position + extents;
if let Some(clip) = clip {
min = Vec2::max(min, clip.clip.min);
max = Vec2::min(max, clip.clip.max);
}
// if the current cursor position is within the bounds of the node, consider it for
// clicking
if (min.x..max.x).contains(&cursor_position.x)
Expand Down

0 comments on commit 601cc0c

Please sign in to comment.