Expose set_cursor_hittest() from winit (#6664)
# Objective
- Bevy should be usable to create 'overlay' type apps, where the input is not captured by Bevy, but passed down/into a target app, or to allow passive displays/widgets etc.
 
## Solution
- the `winit:🪟:Window` already has a `set_cursor_hittest()` which basically does this for mouse input events, so I've exposed it (trying to copy the style laid out in the existing wrappings, and added a simple demo.
---
## Changelog
- Added `hittest` to `WindowAttributes`
- Added the `hittest`'s setters/getters
- Modified the `WindowBuilder`
- Modifed the `WindowDescriptor`'s `Default` impl.
- Added an example `cargo run --example fallthrough`
			
			
This commit is contained in:
		
							parent
							
								
									55ca7fc88e
								
							
						
					
					
						commit
						b3e45b75d6
					
				
							
								
								
									
										10
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								Cargo.toml
									
									
									
									
									
								
							@ -1442,6 +1442,16 @@ description = "Illustrates creating and updating a button"
 | 
			
		||||
category = "UI (User Interface)"
 | 
			
		||||
wasm = true
 | 
			
		||||
 | 
			
		||||
[[example]]
 | 
			
		||||
name = "window_fallthrough"
 | 
			
		||||
path = "examples/ui/window_fallthrough.rs"
 | 
			
		||||
 | 
			
		||||
[package.metadata.example.window_fallthrough]
 | 
			
		||||
name = "Window Fallthrough"
 | 
			
		||||
description = "Illustrates how to access `winit::window::Window`'s `hittest` functionality."
 | 
			
		||||
category = "UI (User Interface)"
 | 
			
		||||
wasm = false
 | 
			
		||||
 | 
			
		||||
[[example]]
 | 
			
		||||
name = "font_atlas_debug"
 | 
			
		||||
path = "examples/ui/font_atlas_debug.rs"
 | 
			
		||||
 | 
			
		||||
@ -286,6 +286,7 @@ pub struct Window {
 | 
			
		||||
    cursor_icon: CursorIcon,
 | 
			
		||||
    cursor_visible: bool,
 | 
			
		||||
    cursor_grab_mode: CursorGrabMode,
 | 
			
		||||
    hittest: bool,
 | 
			
		||||
    physical_cursor_position: Option<DVec2>,
 | 
			
		||||
    raw_handle: Option<RawHandleWrapper>,
 | 
			
		||||
    focused: bool,
 | 
			
		||||
@ -351,6 +352,10 @@ pub enum WindowCommand {
 | 
			
		||||
    SetCursorPosition {
 | 
			
		||||
        position: Vec2,
 | 
			
		||||
    },
 | 
			
		||||
    /// Set whether or not mouse events within *this* window are captured, or fall through to the Window below.
 | 
			
		||||
    SetCursorHitTest {
 | 
			
		||||
        hittest: bool,
 | 
			
		||||
    },
 | 
			
		||||
    /// Set whether or not the window is maximized.
 | 
			
		||||
    SetMaximized {
 | 
			
		||||
        maximized: bool,
 | 
			
		||||
@ -435,6 +440,7 @@ impl Window {
 | 
			
		||||
            cursor_visible: window_descriptor.cursor_visible,
 | 
			
		||||
            cursor_grab_mode: window_descriptor.cursor_grab_mode,
 | 
			
		||||
            cursor_icon: CursorIcon::Default,
 | 
			
		||||
            hittest: true,
 | 
			
		||||
            physical_cursor_position: None,
 | 
			
		||||
            raw_handle,
 | 
			
		||||
            focused: false,
 | 
			
		||||
@ -777,7 +783,20 @@ impl Window {
 | 
			
		||||
        self.command_queue
 | 
			
		||||
            .push(WindowCommand::SetCursorPosition { position });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Modifies whether the window catches cursor events.
 | 
			
		||||
    ///
 | 
			
		||||
    /// If true, the window will catch the cursor events.
 | 
			
		||||
    /// If false, events are passed through the window such that any other window behind it receives them. By default hittest is enabled.
 | 
			
		||||
    pub fn set_cursor_hittest(&mut self, hittest: bool) {
 | 
			
		||||
        self.hittest = hittest;
 | 
			
		||||
        self.command_queue
 | 
			
		||||
            .push(WindowCommand::SetCursorHitTest { hittest });
 | 
			
		||||
    }
 | 
			
		||||
    /// Get whether or not the hittest is active.
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn hittest(&self) -> bool {
 | 
			
		||||
        self.hittest
 | 
			
		||||
    }
 | 
			
		||||
    #[allow(missing_docs)]
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn update_focused_status_from_backend(&mut self, focused: bool) {
 | 
			
		||||
@ -961,6 +980,8 @@ pub struct WindowDescriptor {
 | 
			
		||||
    pub cursor_visible: bool,
 | 
			
		||||
    /// Sets whether and how the window grabs the cursor.
 | 
			
		||||
    pub cursor_grab_mode: CursorGrabMode,
 | 
			
		||||
    /// Sets whether or not the window listens for 'hits' of mouse activity over _this_ window.
 | 
			
		||||
    pub hittest: bool,
 | 
			
		||||
    /// Sets the [`WindowMode`](crate::WindowMode).
 | 
			
		||||
    ///
 | 
			
		||||
    /// The monitor to go fullscreen on can be selected with the `monitor` field.
 | 
			
		||||
@ -1013,6 +1034,7 @@ impl Default for WindowDescriptor {
 | 
			
		||||
            decorations: true,
 | 
			
		||||
            cursor_grab_mode: CursorGrabMode::None,
 | 
			
		||||
            cursor_visible: true,
 | 
			
		||||
            hittest: true,
 | 
			
		||||
            mode: WindowMode::Windowed,
 | 
			
		||||
            transparent: false,
 | 
			
		||||
            canvas: None,
 | 
			
		||||
 | 
			
		||||
@ -230,6 +230,10 @@ fn change_window(
 | 
			
		||||
                    let window = winit_windows.get_window(id).unwrap();
 | 
			
		||||
                    window.set_always_on_top(always_on_top);
 | 
			
		||||
                }
 | 
			
		||||
                bevy_window::WindowCommand::SetCursorHitTest { hittest } => {
 | 
			
		||||
                    let window = winit_windows.get_window(id).unwrap();
 | 
			
		||||
                    window.set_cursor_hittest(hittest).unwrap();
 | 
			
		||||
                }
 | 
			
		||||
                bevy_window::WindowCommand::Close => {
 | 
			
		||||
                    // Since we have borrowed `windows` to iterate through them, we can't remove the window from it.
 | 
			
		||||
                    // Add the removal requests to a queue to solve this
 | 
			
		||||
 | 
			
		||||
@ -319,6 +319,7 @@ Example | Description
 | 
			
		||||
[UI](../examples/ui/ui.rs) | Illustrates various features of Bevy UI
 | 
			
		||||
[UI Scaling](../examples/ui/ui_scaling.rs) | Illustrates how to scale the UI
 | 
			
		||||
[UI Z-Index](../examples/ui/z_index.rs) | Demonstrates how to control the relative depth (z-position) of UI elements
 | 
			
		||||
[Window Fallthrough](../examples/ui/window_fallthrough.rs) | Illustrates how to access `winit::window::Window`'s `hittest` functionality.
 | 
			
		||||
 | 
			
		||||
## Window
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										60
									
								
								examples/ui/window_fallthrough.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								examples/ui/window_fallthrough.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,60 @@
 | 
			
		||||
//! This example illustrates how have a mouse's clicks/wheel/movement etc fall through the spawned transparent window to a window below.
 | 
			
		||||
//! If you build this, and hit 'P' it should toggle on/off the mouse's passthrough.
 | 
			
		||||
 | 
			
		||||
use bevy::prelude::*;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    // Set the window's parameters, note we're setting always_on_top to be true.
 | 
			
		||||
    let window_desc = WindowDescriptor {
 | 
			
		||||
        transparent: true,
 | 
			
		||||
        decorations: true,
 | 
			
		||||
        always_on_top: true,
 | 
			
		||||
        ..default()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    App::new()
 | 
			
		||||
        .insert_resource(ClearColor(Color::NONE)) // Use a transparent window, to make effects obvious.
 | 
			
		||||
        .add_plugins(DefaultPlugins.set(WindowPlugin {
 | 
			
		||||
            window: window_desc,
 | 
			
		||||
            ..default()
 | 
			
		||||
        }))
 | 
			
		||||
        .add_startup_system(setup)
 | 
			
		||||
        .add_system(toggle_mouse_passthrough) // This allows us to hit 'P' to toggle on/off the mouse's passthrough
 | 
			
		||||
        .run();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
 | 
			
		||||
    // UI camera
 | 
			
		||||
    commands.spawn(Camera2dBundle::default());
 | 
			
		||||
    // Text with one section
 | 
			
		||||
    commands.spawn((
 | 
			
		||||
        // Create a TextBundle that has a Text with a single section.
 | 
			
		||||
        TextBundle::from_section(
 | 
			
		||||
            // Accepts a `String` or any type that converts into a `String`, such as `&str`
 | 
			
		||||
            "Hit 'P' then scroll/click around!",
 | 
			
		||||
            TextStyle {
 | 
			
		||||
                font: asset_server.load("fonts/FiraSans-Bold.ttf"),
 | 
			
		||||
                font_size: 100.0, // Nice and big so you can see it!
 | 
			
		||||
                color: Color::WHITE,
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
        // Set the style of the TextBundle itself.
 | 
			
		||||
        .with_style(Style {
 | 
			
		||||
            position_type: PositionType::Absolute,
 | 
			
		||||
            position: UiRect {
 | 
			
		||||
                bottom: Val::Px(5.),
 | 
			
		||||
                right: Val::Px(10.),
 | 
			
		||||
                ..default()
 | 
			
		||||
            },
 | 
			
		||||
            ..default()
 | 
			
		||||
        }),
 | 
			
		||||
    ));
 | 
			
		||||
}
 | 
			
		||||
// A simple system to handle some keyboard input and toggle on/off the hittest.
 | 
			
		||||
fn toggle_mouse_passthrough(keyboard_input: Res<Input<KeyCode>>, mut windows: ResMut<Windows>) {
 | 
			
		||||
    if keyboard_input.just_pressed(KeyCode::P) {
 | 
			
		||||
        let window = windows.primary_mut();
 | 
			
		||||
        let hittest: bool = window.hittest();
 | 
			
		||||
        window.set_cursor_hittest(!hittest);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user