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)"
 | 
					category = "UI (User Interface)"
 | 
				
			||||||
wasm = true
 | 
					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]]
 | 
					[[example]]
 | 
				
			||||||
name = "font_atlas_debug"
 | 
					name = "font_atlas_debug"
 | 
				
			||||||
path = "examples/ui/font_atlas_debug.rs"
 | 
					path = "examples/ui/font_atlas_debug.rs"
 | 
				
			||||||
 | 
				
			|||||||
@ -286,6 +286,7 @@ pub struct Window {
 | 
				
			|||||||
    cursor_icon: CursorIcon,
 | 
					    cursor_icon: CursorIcon,
 | 
				
			||||||
    cursor_visible: bool,
 | 
					    cursor_visible: bool,
 | 
				
			||||||
    cursor_grab_mode: CursorGrabMode,
 | 
					    cursor_grab_mode: CursorGrabMode,
 | 
				
			||||||
 | 
					    hittest: bool,
 | 
				
			||||||
    physical_cursor_position: Option<DVec2>,
 | 
					    physical_cursor_position: Option<DVec2>,
 | 
				
			||||||
    raw_handle: Option<RawHandleWrapper>,
 | 
					    raw_handle: Option<RawHandleWrapper>,
 | 
				
			||||||
    focused: bool,
 | 
					    focused: bool,
 | 
				
			||||||
@ -351,6 +352,10 @@ pub enum WindowCommand {
 | 
				
			|||||||
    SetCursorPosition {
 | 
					    SetCursorPosition {
 | 
				
			||||||
        position: Vec2,
 | 
					        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.
 | 
					    /// Set whether or not the window is maximized.
 | 
				
			||||||
    SetMaximized {
 | 
					    SetMaximized {
 | 
				
			||||||
        maximized: bool,
 | 
					        maximized: bool,
 | 
				
			||||||
@ -435,6 +440,7 @@ impl Window {
 | 
				
			|||||||
            cursor_visible: window_descriptor.cursor_visible,
 | 
					            cursor_visible: window_descriptor.cursor_visible,
 | 
				
			||||||
            cursor_grab_mode: window_descriptor.cursor_grab_mode,
 | 
					            cursor_grab_mode: window_descriptor.cursor_grab_mode,
 | 
				
			||||||
            cursor_icon: CursorIcon::Default,
 | 
					            cursor_icon: CursorIcon::Default,
 | 
				
			||||||
 | 
					            hittest: true,
 | 
				
			||||||
            physical_cursor_position: None,
 | 
					            physical_cursor_position: None,
 | 
				
			||||||
            raw_handle,
 | 
					            raw_handle,
 | 
				
			||||||
            focused: false,
 | 
					            focused: false,
 | 
				
			||||||
@ -777,7 +783,20 @@ impl Window {
 | 
				
			|||||||
        self.command_queue
 | 
					        self.command_queue
 | 
				
			||||||
            .push(WindowCommand::SetCursorPosition { position });
 | 
					            .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)]
 | 
					    #[allow(missing_docs)]
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub fn update_focused_status_from_backend(&mut self, focused: bool) {
 | 
					    pub fn update_focused_status_from_backend(&mut self, focused: bool) {
 | 
				
			||||||
@ -961,6 +980,8 @@ pub struct WindowDescriptor {
 | 
				
			|||||||
    pub cursor_visible: bool,
 | 
					    pub cursor_visible: bool,
 | 
				
			||||||
    /// Sets whether and how the window grabs the cursor.
 | 
					    /// Sets whether and how the window grabs the cursor.
 | 
				
			||||||
    pub cursor_grab_mode: CursorGrabMode,
 | 
					    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).
 | 
					    /// Sets the [`WindowMode`](crate::WindowMode).
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// The monitor to go fullscreen on can be selected with the `monitor` field.
 | 
					    /// The monitor to go fullscreen on can be selected with the `monitor` field.
 | 
				
			||||||
@ -1013,6 +1034,7 @@ impl Default for WindowDescriptor {
 | 
				
			|||||||
            decorations: true,
 | 
					            decorations: true,
 | 
				
			||||||
            cursor_grab_mode: CursorGrabMode::None,
 | 
					            cursor_grab_mode: CursorGrabMode::None,
 | 
				
			||||||
            cursor_visible: true,
 | 
					            cursor_visible: true,
 | 
				
			||||||
 | 
					            hittest: true,
 | 
				
			||||||
            mode: WindowMode::Windowed,
 | 
					            mode: WindowMode::Windowed,
 | 
				
			||||||
            transparent: false,
 | 
					            transparent: false,
 | 
				
			||||||
            canvas: None,
 | 
					            canvas: None,
 | 
				
			||||||
 | 
				
			|||||||
@ -230,6 +230,10 @@ fn change_window(
 | 
				
			|||||||
                    let window = winit_windows.get_window(id).unwrap();
 | 
					                    let window = winit_windows.get_window(id).unwrap();
 | 
				
			||||||
                    window.set_always_on_top(always_on_top);
 | 
					                    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 => {
 | 
					                bevy_window::WindowCommand::Close => {
 | 
				
			||||||
                    // Since we have borrowed `windows` to iterate through them, we can't remove the window from it.
 | 
					                    // 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
 | 
					                    // 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](../examples/ui/ui.rs) | Illustrates various features of Bevy UI
 | 
				
			||||||
[UI Scaling](../examples/ui/ui_scaling.rs) | Illustrates how to scale the 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
 | 
					[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
 | 
					## 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