mirror of
https://github.com/bevyengine/bevy
synced 2024-11-24 21:53:07 +00:00
Add the functions start_drag_move
and start_drag_resize
to Window
(#15674)
# Objective Expose the `winit` functions [drag_window](https://docs.rs/winit/latest/winit/window/struct.Window.html#method.drag_window) and [resize_window](https://docs.rs/winit/latest/winit/window/struct.Window.html#method.drag_resize_window). Which allows implementing move & resize for windows without decorations. ## Solution Add the functions `start_drag_move` and `start_drag_resize` to `bevy_window::Window`, which are then assigned to fields in `InternalWindowState`, and propagated to `winit` in the `changed_windows` system. ## Testing I've tested that both functions works on x11 and wayland. Not sure if someone needs to test on windows/mac? --- ## Showcase [Screencast from 2024-10-06 11-49-58 (trimmed).webm](https://github.com/user-attachments/assets/1cdee7b1-22bd-41d3-8a0a-6872a6ebf62c) (The flickering in the video is some issue with resizing without decorations on x11) <details> <summary>Click to view showcase</summary> Not the same code used in the video, but simple way to test moving a window without decorations. ```rust use bevy::prelude::*; fn main() { App::new() .add_plugins(DefaultPlugins.set(WindowPlugin { primary_window: Some(Window { decorations: false, ..default() }), ..default() })) .add_systems(Update, move_windows) .run(); } fn move_windows(mut windows: Query<&mut Window>, input: Res<ButtonInput<MouseButton>>) { if input.pressed(MouseButton::Left) { for mut window in windows.iter_mut() { window.start_drag_move(); } } } ``` </details> --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
parent
99b9a2fcd7
commit
82aa2e3161
3 changed files with 88 additions and 2 deletions
|
@ -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<bool>,
|
||||
/// If this is true then next frame we will ask to maximize/un-maximize the window depending on `maximized`.
|
||||
maximize_request: Option<bool>,
|
||||
/// 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<ResizeDirection>,
|
||||
/// Unscaled cursor position.
|
||||
physical_cursor_position: Option<DVec2>,
|
||||
}
|
||||
|
@ -924,6 +970,16 @@ impl InternalWindowState {
|
|||
pub fn take_minimize_request(&mut self) -> Option<bool> {
|
||||
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<ResizeDirection> {
|
||||
self.drag_resize_request.take()
|
||||
}
|
||||
}
|
||||
|
||||
/// References a screen monitor.
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue