bevy/crates/bevy_ui
Jannik Obermann 83afcb5a2b
Fix ui picking outside the viewport (#19744)
# Objective

Fixes #19692 

## Solution

- Skip pointers outside the viewport.

## Testing

Tested with the following example:

<details>
<summary>Click to expand code</summary>

```rust
use bevy::{
    prelude::*, render:📷: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<Pointer<Drag>>, 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<Pointer<DragStart>>,
             window: Single<Entity, With<Window>>,
             mut commands: Commands| {
                commands
                    .entity(*window)
                    .insert(CursorIcon::from(SystemCursorIcon::Grabbing));
            },
        )
        .observe(
            |_: On<Pointer<DragEnd>>,
             window: Single<Entity, With<Window>>,
             mut commands: Commands| {
                commands.entity(*window).remove::<CursorIcon>();
            },
        );
}

fn px(val: Val) -> f32 {
    match val {
        Val::Px(px) => px,
        _ => 0.0,
    }
}
```
</details>

## 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)
2025-06-30 22:46:56 +00:00
..
src Fix ui picking outside the viewport (#19744) 2025-06-30 22:46:56 +00:00
Cargo.toml Update derive_more requirement from 1 to 2 (#19671) 2025-06-24 11:13:04 +00:00
LICENSE-APACHE Cleanup publish process (#17728) 2025-02-09 17:46:19 +00:00
LICENSE-MIT Cleanup publish process (#17728) 2025-02-09 17:46:19 +00:00
README.md Add README.md to all crates (#13184) 2024-05-02 18:56:00 +00:00

Bevy UI

License Crates.io Downloads Docs Discord