-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add window drag move and drag resize without decoration example. (#15814
) # Objective Add an example for the new drag move and drag resize introduced by PR #15674 and fix #15734. ## Solution I created an example that allows the user to exercise drag move and drag resize separately. The user can also choose what direction the resize works in. ![Screenshot 2024-10-10 at 4 06 43 AM](https://github.com/user-attachments/assets/1da558ab-a80f-49af-8b7d-bb635b0f038f) ### Name The example is called `window_drag_move`. Happy to have that bikeshedded. ### Contentious Refactor? This PR removed the `ResizeDirection` enumeration in favor of using `CompassOctant` which had the same variants. Perhaps this is contentious. ### Unsafe? In PR #15674 I mentioned that `start_drag_move()` and `start_drag_resize()`'s requirement to only be called in the presence of a left-click looks like a compiler-unenforceable contract that can cause intermittent panics when not observed, so perhaps the functions should be marked them unsafe. **I have not made that change** here since I didn't see a clear consensus on that. ## Testing I exercised this on x86 macOS. However, winit for macOS does not support drag resize. It reports a good error when `start_drag_resize()` is called. I'd like to see it tested on Windows and Linux. --- ## Showcase Example window_drag_move shows how to drag or resize a window without decoration. --------- Co-authored-by: Alice Cecile <[email protected]>
- Loading branch information
1 parent
a09104b
commit 5157fef
Showing
5 changed files
with
172 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
//! This example illustrates drag move and drag resize without window | ||
//! decorations. | ||
//! | ||
//! When window decorations are not present, the user cannot drag a window by | ||
//! its titlebar to change its position. The `start_drag_move()` function | ||
//! permits a users to drag a window by left clicking anywhere in the window; | ||
//! left click must be pressed and other constraints can be imposed. For | ||
//! instance an application could require a user to hold down alt and left click | ||
//! to drag a window. | ||
//! | ||
//! The `start_drag_resize()` function behaves similarly but permits a window to | ||
//! be resized. | ||
use bevy::{math::CompassOctant, prelude::*}; | ||
|
||
/// Determine what do on left click. | ||
#[derive(Resource, Debug)] | ||
enum LeftClickAction { | ||
/// Do nothing. | ||
Nothing, | ||
/// Move the window on left click. | ||
Move, | ||
/// Resize the window on left click. | ||
Resize, | ||
} | ||
|
||
/// What direction index should the window resize toward. | ||
#[derive(Resource)] | ||
struct ResizeDir(usize); | ||
|
||
/// Directions that the drag resizes the window toward. | ||
const DIRECTIONS: [CompassOctant; 8] = [ | ||
CompassOctant::North, | ||
CompassOctant::NorthEast, | ||
CompassOctant::East, | ||
CompassOctant::SouthEast, | ||
CompassOctant::South, | ||
CompassOctant::SouthWest, | ||
CompassOctant::West, | ||
CompassOctant::NorthWest, | ||
]; | ||
|
||
fn main() { | ||
App::new() | ||
.add_plugins(DefaultPlugins.set(WindowPlugin { | ||
primary_window: Some(Window { | ||
decorations: false, | ||
..default() | ||
}), | ||
..default() | ||
})) | ||
.insert_resource(ResizeDir(7)) | ||
.insert_resource(LeftClickAction::Move) | ||
.add_systems(Startup, setup) | ||
.add_systems(Update, (handle_input, move_or_resize_windows)) | ||
.run(); | ||
} | ||
|
||
fn setup(mut commands: Commands) { | ||
// Camera | ||
commands.spawn(Camera3d::default()); | ||
|
||
// UI | ||
commands | ||
.spawn(( | ||
NodeBundle { | ||
style: Style { | ||
position_type: PositionType::Absolute, | ||
padding: UiRect::all(Val::Px(5.0)), | ||
..default() | ||
}, | ||
background_color: Color::BLACK.with_alpha(0.75).into(), | ||
..default() | ||
}, | ||
GlobalZIndex(i32::MAX), | ||
)) | ||
.with_children(|p| { | ||
p.spawn(Text::default()).with_children(|p| { | ||
p.spawn(TextSpan::new( | ||
"Demonstrate drag move and drag resize without window decorations.\n\n", | ||
)); | ||
p.spawn(TextSpan::new("Controls:\n")); | ||
p.spawn(TextSpan::new("A - change left click action [")); | ||
p.spawn(TextSpan::new("Move")); | ||
p.spawn(TextSpan::new("]\n")); | ||
p.spawn(TextSpan::new("S / D - change resize direction [")); | ||
p.spawn(TextSpan::new("NorthWest")); | ||
p.spawn(TextSpan::new("]\n")); | ||
}); | ||
}); | ||
} | ||
|
||
fn handle_input( | ||
input: Res<ButtonInput<KeyCode>>, | ||
mut action: ResMut<LeftClickAction>, | ||
mut dir: ResMut<ResizeDir>, | ||
example_text: Query<Entity, With<Text>>, | ||
mut writer: TextUiWriter, | ||
) { | ||
use LeftClickAction::*; | ||
if input.just_pressed(KeyCode::KeyA) { | ||
*action = match *action { | ||
Move => Resize, | ||
Resize => Nothing, | ||
Nothing => Move, | ||
}; | ||
*writer.text(example_text.single(), 4) = format!("{:?}", *action); | ||
} | ||
|
||
if input.just_pressed(KeyCode::KeyS) { | ||
dir.0 = dir | ||
.0 | ||
.checked_sub(1) | ||
.unwrap_or(DIRECTIONS.len().saturating_sub(1)); | ||
*writer.text(example_text.single(), 7) = format!("{:?}", DIRECTIONS[dir.0]); | ||
} | ||
|
||
if input.just_pressed(KeyCode::KeyD) { | ||
dir.0 = (dir.0 + 1) % DIRECTIONS.len(); | ||
*writer.text(example_text.single(), 7) = format!("{:?}", DIRECTIONS[dir.0]); | ||
} | ||
} | ||
|
||
fn move_or_resize_windows( | ||
mut windows: Query<&mut Window>, | ||
action: Res<LeftClickAction>, | ||
input: Res<ButtonInput<MouseButton>>, | ||
dir: Res<ResizeDir>, | ||
) { | ||
// Both `start_drag_move()` and `start_drag_resize()` must be called after a | ||
// left mouse button press as done here. | ||
// | ||
// winit 0.30.5 may panic when initiated without a left mouse button press. | ||
if input.just_pressed(MouseButton::Left) { | ||
for mut window in windows.iter_mut() { | ||
match *action { | ||
LeftClickAction::Nothing => (), | ||
LeftClickAction::Move => window.start_drag_move(), | ||
LeftClickAction::Resize => { | ||
let d = DIRECTIONS[dir.0]; | ||
window.start_drag_resize(d); | ||
} | ||
} | ||
} | ||
} | ||
} |