From 83afcb5a2b4581b1e28d3707837593acb4035c52 Mon Sep 17 00:00:00 2001 From: Jannik Obermann <50554200+jannik4@users.noreply.github.com> Date: Tue, 1 Jul 2025 00:46:56 +0200 Subject: [PATCH] Fix ui picking outside the viewport (#19744) # Objective Fixes #19692 ## Solution - Skip pointers outside the viewport. ## Testing Tested with the following example:
Click to expand code ```rust use bevy::{ prelude::*, render::camera::Viewport, window::SystemCursorIcon, winit::cursor::CursorIcon, }; fn main() -> AppExit { App::new() .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .insert_resource(ClearColor(Color::BLACK)) .run() } fn setup(mut commands: Commands, window: Single<&Window>) { // commands.spawn(( Camera2d, Camera { clear_color: ClearColorConfig::Custom(Color::WHITE), viewport: Some(Viewport { physical_position: UVec2::new( window.physical_width() / 4, window.physical_height() / 4, ), physical_size: UVec2::new( window.physical_width() / 2, window.physical_height() / 2, ), ..default() }), ..default() }, )); commands .spawn(( Node { top: Val::Px(100.0), left: Val::Px(100.0), width: Val::Px(200.0), height: Val::Px(200.0), ..default() }, BackgroundColor(Color::srgb(1.0, 0.0, 0.0)), )) .observe(|trigger: On>, mut node: Query<&mut Node>| { let mut node = node.get_mut(trigger.target()).unwrap(); node.left = Val::Px(px(node.left) + trigger.delta.x); node.top = Val::Px(px(node.top) + trigger.delta.y); }) .observe( |_: On>, window: Single>, mut commands: Commands| { commands .entity(*window) .insert(CursorIcon::from(SystemCursorIcon::Grabbing)); }, ) .observe( |_: On>, window: Single>, mut commands: Commands| { commands.entity(*window).remove::(); }, ); } fn px(val: Val) -> f32 { match val { Val::Px(px) => px, _ => 0.0, } } ```
## Additional information This is at least also broken on the sprite picking backend. I guess the fix for other backends are also trivial if this is correct. (Sprite picking: #19747) --- crates/bevy_ui/src/picking_backend.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/bevy_ui/src/picking_backend.rs b/crates/bevy_ui/src/picking_backend.rs index 5ca59ceeaf..ccd61a3807 100644 --- a/crates/bevy_ui/src/picking_backend.rs +++ b/crates/bevy_ui/src/picking_backend.rs @@ -140,6 +140,10 @@ pub fn ui_picking( let mut pointer_pos = pointer_location.position * camera_data.target_scaling_factor().unwrap_or(1.); if let Some(viewport) = camera_data.physical_viewport_rect() { + if !viewport.as_rect().contains(pointer_pos) { + // The pointer is outside the viewport, skip it + continue; + } pointer_pos -= viewport.min.as_vec2(); } pointer_pos_by_camera