From e75763620e06b7935f6ce9cf7782daa34b4d038b Mon Sep 17 00:00:00 2001 From: Jer Date: Thu, 17 Nov 2022 21:16:05 +0800 Subject: [PATCH 01/15] expose winit::window::Window's set_cursor_hittest --- crates/bevy_window/src/window.rs | 12 ++++++++++++ crates/bevy_winit/src/lib.rs | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index f0603771373cd..2bf8355d6ad58 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -286,6 +286,7 @@ pub struct Window { cursor_icon: CursorIcon, cursor_visible: bool, cursor_grab_mode: CursorGrabMode, + hittest: bool, physical_cursor_position: Option, raw_handle: Option, 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, @@ -724,6 +730,12 @@ impl Window { self.command_queue .push(WindowCommand::SetCursorGrabMode { grab_mode }); } + /// 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; + } /// Get whether or not the cursor is visible. /// /// ## Platform-specific diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 0b1b544eec17b..bb44b7c75878f 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -237,6 +237,10 @@ fn change_window( // No need to run any further commands - this drops the rest of the commands, although the `bevy_window::Window` will be dropped later anyway break; } + bevy_window::WindowCommand::SetCursorHitTest { hittest } => { + let window = winit_windows.get_window(id).unwrap(); + window.set_cursor_hittest(hittest).unwrap(); + } } } } From f51becdfde7f9935be39afe5ee4dccbd7e229e25 Mon Sep 17 00:00:00 2001 From: Jer Date: Thu, 17 Nov 2022 23:36:59 +0800 Subject: [PATCH 02/15] add WindowCommand to proper spot also regroup logic into the right places. --- crates/bevy_window/src/window.rs | 23 ++++++++++++++++------- crates/bevy_winit/src/lib.rs | 8 ++++---- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index 2bf8355d6ad58..a00467c44a20f 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -730,12 +730,6 @@ impl Window { self.command_queue .push(WindowCommand::SetCursorGrabMode { grab_mode }); } - /// 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; - } /// Get whether or not the cursor is visible. /// /// ## Platform-specific @@ -789,7 +783,19 @@ 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) { @@ -973,6 +979,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. @@ -1025,6 +1033,7 @@ impl Default for WindowDescriptor { decorations: true, cursor_grab_mode: CursorGrabMode::None, cursor_visible: true, + hittest: true, mode: WindowMode::Windowed, transparent: false, canvas: None, diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index bb44b7c75878f..01143e5fed3bb 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -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 @@ -237,10 +241,6 @@ fn change_window( // No need to run any further commands - this drops the rest of the commands, although the `bevy_window::Window` will be dropped later anyway break; } - bevy_window::WindowCommand::SetCursorHitTest { hittest } => { - let window = winit_windows.get_window(id).unwrap(); - window.set_cursor_hittest(hittest).unwrap(); - } } } } From ad6880cc247e5998e0b33e529312e9105f7d7639 Mon Sep 17 00:00:00 2001 From: Jer Date: Thu, 17 Nov 2022 23:58:39 +0800 Subject: [PATCH 03/15] add example add example --- Cargo.toml | 4 +++ examples/ui/fallthrough.rs | 71 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 examples/ui/fallthrough.rs diff --git a/Cargo.toml b/Cargo.toml index 251e47609645d..426b00d9c0cfe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1442,6 +1442,10 @@ description = "Illustrates creating and updating a button" category = "UI (User Interface)" wasm = true +[[example]] +name = "fallthrough" +path = "examples/ui/fallthrough.rs" + [[example]] name = "font_atlas_debug" path = "examples/ui/font_atlas_debug.rs" diff --git a/examples/ui/fallthrough.rs b/examples/ui/fallthrough.rs new file mode 100644 index 0000000000000..996d4f9c0c756 --- /dev/null +++ b/examples/ui/fallthrough.rs @@ -0,0 +1,71 @@ +//! 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::*; + +const WIDTH: f32 = 1920.; +const HEIGHT: f32 = 1080.; + +fn main() { + let window_desc = WindowDescriptor { + width: WIDTH, + height: HEIGHT, + 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) { + // 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(HEIGHT / 4.), + right: Val::Px(WIDTH / 4.), + ..default() + }, + ..default() + }), + )); +} +fn toggle_mouse_passthrough(keyboard_input: Res>, mut windows: ResMut) { + if keyboard_input.just_pressed(KeyCode::P) { + let window = windows.primary_mut(); + + let hittest: bool = window.hittest(); + if hittest { + info!("Hittesting the window."); + } else { + info!("Hittesting off."); + } + + window.set_cursor_hittest(!hittest); + } +} From 46e2a1c5c9272b1129d5b220d97e1c3808978845 Mon Sep 17 00:00:00 2001 From: Jer Date: Fri, 18 Nov 2022 00:18:31 +0800 Subject: [PATCH 04/15] add ; --- crates/bevy_window/src/window.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index a00467c44a20f..c0d528a274749 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -789,7 +789,7 @@ impl Window { pub fn set_cursor_hittest(&mut self, hittest: bool) { self.hittest = hittest; self.command_queue - .push(WindowCommand::SetCursorHitTest { hittest }) + .push(WindowCommand::SetCursorHitTest { hittest }); } /// Get whether or not the hittest is active. #[inline] From 6a69b33f3a3c89656430476189d79be6afa6fea2 Mon Sep 17 00:00:00 2001 From: Jer Date: Fri, 18 Nov 2022 00:18:41 +0800 Subject: [PATCH 05/15] remove empty docstrings --- examples/ui/fallthrough.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/ui/fallthrough.rs b/examples/ui/fallthrough.rs index 996d4f9c0c756..a757c3c4b16d0 100644 --- a/examples/ui/fallthrough.rs +++ b/examples/ui/fallthrough.rs @@ -1,7 +1,5 @@ //! 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::*; From 5af560259463bba286c4d77e4d3a189bec46bab7 Mon Sep 17 00:00:00 2001 From: Jer Date: Fri, 18 Nov 2022 07:40:56 +0800 Subject: [PATCH 06/15] Add example package.metadata --- Cargo.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 426b00d9c0cfe..e5e84c3d79786 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1446,6 +1446,11 @@ wasm = true name = "fallthrough" path = "examples/ui/fallthrough.rs" +[package.metadata.example.fallthrough] +name = "Fallthrough" +description = "Illustrates how to access `winit::window::Window`'s `hittest` functionality." +category = "UI (User Interface)" + [[example]] name = "font_atlas_debug" path = "examples/ui/font_atlas_debug.rs" From df6e72d55bfb0e342b4129735caa2c9a8cdd870e Mon Sep 17 00:00:00 2001 From: Jer Date: Fri, 18 Nov 2022 07:41:03 +0800 Subject: [PATCH 07/15] cargo fmt --- examples/ui/fallthrough.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/ui/fallthrough.rs b/examples/ui/fallthrough.rs index a757c3c4b16d0..fdb83a759ae0a 100644 --- a/examples/ui/fallthrough.rs +++ b/examples/ui/fallthrough.rs @@ -7,6 +7,7 @@ const WIDTH: f32 = 1920.; const HEIGHT: f32 = 1080.; fn main() { + // Set the window's parameters, note we're setting always_on_top to be true. let window_desc = WindowDescriptor { width: WIDTH, height: HEIGHT, @@ -15,6 +16,7 @@ fn main() { 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 { @@ -53,6 +55,7 @@ fn setup(mut commands: Commands, asset_server: Res) { }), )); } +// A simple system to handle some keyboard input and toggle on/off the hittest. fn toggle_mouse_passthrough(keyboard_input: Res>, mut windows: ResMut) { if keyboard_input.just_pressed(KeyCode::P) { let window = windows.primary_mut(); From 98ebdc3a192fa19ac8448e7a40502103277cff4d Mon Sep 17 00:00:00 2001 From: Jer Date: Fri, 18 Nov 2022 07:41:12 +0800 Subject: [PATCH 08/15] bolster docs --- crates/bevy_window/src/window.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index c0d528a274749..ab76fa1dc379a 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -785,7 +785,8 @@ impl Window { } /// 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. + /// 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 From 14883d736c7805f307b0c1fdf8231602fe92229d Mon Sep 17 00:00:00 2001 From: Jer Date: Fri, 18 Nov 2022 10:58:48 +0800 Subject: [PATCH 09/15] remove syntatic sugar for unused_result --- crates/bevy_winit/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 01143e5fed3bb..5f5dd3538138c 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -232,7 +232,7 @@ fn change_window( } bevy_window::WindowCommand::SetCursorHitTest { hittest } => { let window = winit_windows.get_window(id).unwrap(); - _ = window.set_cursor_hittest(!hittest).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. From 3fd9e4a04311b4e1f6720bb80436807d7129ceec Mon Sep 17 00:00:00 2001 From: Jer Date: Fri, 18 Nov 2022 18:46:10 +0800 Subject: [PATCH 10/15] Update Cargo.toml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e5e84c3d79786..cb1763c936192 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1443,7 +1443,7 @@ category = "UI (User Interface)" wasm = true [[example]] -name = "fallthrough" +name = "window_fallthrough" path = "examples/ui/fallthrough.rs" [package.metadata.example.fallthrough] From d2db566a6eb5507be94ac820dddd817e4526aab6 Mon Sep 17 00:00:00 2001 From: Jer Date: Fri, 18 Nov 2022 18:46:55 +0800 Subject: [PATCH 11/15] Update crates/bevy_winit/src/lib.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François --- crates/bevy_winit/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 5f5dd3538138c..ec8478ea6e448 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -232,7 +232,7 @@ fn change_window( } bevy_window::WindowCommand::SetCursorHitTest { hittest } => { let window = winit_windows.get_window(id).unwrap(); - window.set_cursor_hittest(!hittest).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. From b3ee683adbf487a8512b4b2335d41b0dcf8ec4ba Mon Sep 17 00:00:00 2001 From: Jer Date: Fri, 18 Nov 2022 18:51:30 +0800 Subject: [PATCH 12/15] mockersf's suggestions - remove arbitrary width/height consts from example. - remove logging from example - rename example --- Cargo.toml | 2 +- .../ui/{fallthrough.rs => window_fallthrough.rs} | 16 ++-------------- 2 files changed, 3 insertions(+), 15 deletions(-) rename examples/ui/{fallthrough.rs => window_fallthrough.rs} (87%) diff --git a/Cargo.toml b/Cargo.toml index cb1763c936192..052481d6fc1c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1444,7 +1444,7 @@ wasm = true [[example]] name = "window_fallthrough" -path = "examples/ui/fallthrough.rs" +path = "examples/ui/window_fallthrough.rs" [package.metadata.example.fallthrough] name = "Fallthrough" diff --git a/examples/ui/fallthrough.rs b/examples/ui/window_fallthrough.rs similarity index 87% rename from examples/ui/fallthrough.rs rename to examples/ui/window_fallthrough.rs index fdb83a759ae0a..eba60c1e0a137 100644 --- a/examples/ui/fallthrough.rs +++ b/examples/ui/window_fallthrough.rs @@ -3,14 +3,9 @@ use bevy::prelude::*; -const WIDTH: f32 = 1920.; -const HEIGHT: f32 = 1080.; - fn main() { // Set the window's parameters, note we're setting always_on_top to be true. let window_desc = WindowDescriptor { - width: WIDTH, - height: HEIGHT, transparent: true, decorations: true, always_on_top: true, @@ -47,8 +42,8 @@ fn setup(mut commands: Commands, asset_server: Res) { .with_style(Style { position_type: PositionType::Absolute, position: UiRect { - bottom: Val::Px(HEIGHT / 4.), - right: Val::Px(WIDTH / 4.), + bottom: Val::Px(5.), + right: Val::Px(10.), ..default() }, ..default() @@ -59,14 +54,7 @@ fn setup(mut commands: Commands, asset_server: Res) { fn toggle_mouse_passthrough(keyboard_input: Res>, mut windows: ResMut) { if keyboard_input.just_pressed(KeyCode::P) { let window = windows.primary_mut(); - let hittest: bool = window.hittest(); - if hittest { - info!("Hittesting the window."); - } else { - info!("Hittesting off."); - } - window.set_cursor_hittest(!hittest); } } From 361351aa2bef22b8e418f51fad1905f1da46f488 Mon Sep 17 00:00:00 2001 From: Jer Date: Sat, 19 Nov 2022 14:52:35 +0800 Subject: [PATCH 13/15] Update Cargo.toml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 052481d6fc1c3..dfd6c89ba805d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1446,8 +1446,8 @@ wasm = true name = "window_fallthrough" path = "examples/ui/window_fallthrough.rs" -[package.metadata.example.fallthrough] -name = "Fallthrough" +[package.metadata.example.window_fallthrough] +name = "Window Fallthrough" description = "Illustrates how to access `winit::window::Window`'s `hittest` functionality." category = "UI (User Interface)" From 6049f8eae026932cf4d3d2f63429f8906e4bd586 Mon Sep 17 00:00:00 2001 From: Jer Date: Sat, 19 Nov 2022 17:48:38 +0800 Subject: [PATCH 14/15] Update Cargo.toml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add wasm=false flag Co-authored-by: François --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index dfd6c89ba805d..97069bad9ab00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1450,6 +1450,7 @@ path = "examples/ui/window_fallthrough.rs" 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" From f1f2894cc0ac4743fe4404bb2c279a97d972d219 Mon Sep 17 00:00:00 2001 From: jer Date: Sun, 20 Nov 2022 17:17:43 +0800 Subject: [PATCH 15/15] fix: update docs --- examples/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/README.md b/examples/README.md index 6b57cf3aec06e..e354e6f283120 100644 --- a/examples/README.md +++ b/examples/README.md @@ -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