diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index 8a6dcdc5ee423..34781501e65a8 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -367,6 +367,22 @@ impl Window { self.internal.minimize_request = Some(minimized); } + /// Calling this will attempt to start a drag-move of the window. + /// + /// There is no guarantee that this will work unless the left mouse button was + /// pressed immediately before this function was called. + pub fn start_drag_move(&mut self) { + self.internal.drag_move_request = true; + } + + /// Calling this will attempt to start a drag-resize of the window. + /// + /// There is no guarantee that this will work unless the left mouse button was + /// pressed immediately before this function was called. + pub fn start_drag_resize(&mut self, direction: ResizeDirection) { + self.internal.drag_resize_request = Some(direction); + } + /// The window's client area width in logical pixels. /// /// See [`WindowResolution`] for an explanation about logical/physical sizes. @@ -897,6 +913,32 @@ pub enum CursorGrabMode { Locked, } +/// Defines the orientation in which a window resize will be performed. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Reflect)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] +pub enum ResizeDirection { + /// Resize the window to the west. + West, + /// Resize the window to the north. + North, + /// Resize the window to the east. + East, + /// Resize the window to the south. + South, + /// Resize the window to the northwest. + Northwest, + /// Resize the window to the northeast. + Northeast, + /// Resize the window to the southwest. + Southwest, + /// Resize the window to the southeast. + Southeast, +} + /// Stores internal [`Window`] state that isn't directly accessible. #[derive(Default, Debug, Copy, Clone, PartialEq, Reflect)] #[cfg_attr( @@ -910,6 +952,10 @@ pub struct InternalWindowState { minimize_request: Option, /// If this is true then next frame we will ask to maximize/un-maximize the window depending on `maximized`. maximize_request: Option, + /// If this is true then next frame we will ask to drag-move the window. + drag_move_request: bool, + /// If this is `Some` then the next frame we will ask to drag-resize the window. + drag_resize_request: Option, /// Unscaled cursor position. physical_cursor_position: Option, } @@ -924,6 +970,16 @@ impl InternalWindowState { pub fn take_minimize_request(&mut self) -> Option { self.minimize_request.take() } + + /// Consumes the current move request, if it exists. This should only be called by window backends. + pub fn take_move_request(&mut self) -> bool { + core::mem::take(&mut self.drag_move_request) + } + + /// Consumes the current resize request, if it exists. This should only be called by window backends. + pub fn take_resize_request(&mut self) -> Option { + self.drag_resize_request.take() + } } /// References a screen monitor. diff --git a/crates/bevy_winit/src/converters.rs b/crates/bevy_winit/src/converters.rs index 691113bbbed8e..fc5ff5c29a10d 100644 --- a/crates/bevy_winit/src/converters.rs +++ b/crates/bevy_winit/src/converters.rs @@ -8,7 +8,7 @@ use bevy_input::{ use bevy_math::Vec2; #[cfg(feature = "custom_cursor")] use bevy_window::SystemCursorIcon; -use bevy_window::{EnabledButtons, WindowLevel, WindowTheme}; +use bevy_window::{EnabledButtons, ResizeDirection, WindowLevel, WindowTheme}; use winit::keyboard::{Key, NamedKey, NativeKey}; pub fn convert_keyboard_input( @@ -706,3 +706,18 @@ pub fn convert_enabled_buttons(enabled_buttons: EnabledButtons) -> winit::window } window_buttons } + +pub fn convert_resize_direction( + resize_direction: ResizeDirection, +) -> winit::window::ResizeDirection { + match resize_direction { + ResizeDirection::West => winit::window::ResizeDirection::West, + ResizeDirection::North => winit::window::ResizeDirection::North, + ResizeDirection::East => winit::window::ResizeDirection::East, + ResizeDirection::South => winit::window::ResizeDirection::South, + ResizeDirection::Northwest => winit::window::ResizeDirection::NorthWest, + ResizeDirection::Northeast => winit::window::ResizeDirection::NorthEast, + ResizeDirection::Southwest => winit::window::ResizeDirection::SouthWest, + ResizeDirection::Southeast => winit::window::ResizeDirection::SouthEast, + } +} diff --git a/crates/bevy_winit/src/system.rs b/crates/bevy_winit/src/system.rs index 34a4dddc51eb1..6348f050ad758 100644 --- a/crates/bevy_winit/src/system.rs +++ b/crates/bevy_winit/src/system.rs @@ -28,7 +28,8 @@ use winit::platform::web::WindowExtWebSys; use crate::{ converters::{ - convert_enabled_buttons, convert_window_level, convert_window_theme, convert_winit_theme, + convert_enabled_buttons, convert_resize_direction, convert_window_level, + convert_window_theme, convert_winit_theme, }, get_best_videomode, get_fitting_videomode, select_monitor, state::react_to_resize, @@ -462,6 +463,20 @@ pub(crate) fn changed_windows( winit_window.set_minimized(minimized); } + if window.internal.take_move_request() { + if let Err(e) = winit_window.drag_window() { + warn!("Winit returned an error while attempting to drag the window: {e}"); + } + } + + if let Some(resize_direction) = window.internal.take_resize_request() { + if let Err(e) = + winit_window.drag_resize_window(convert_resize_direction(resize_direction)) + { + warn!("Winit returned an error while attempting to drag resize the window: {e}"); + } + } + if window.focused != cache.window.focused && window.focused { winit_window.focus_window(); }