docs/bevy/examples/window/window_drag_move.rs 4.4 K · 144 lines · raw · history

1 //! This example illustrates drag move and drag resize without window
2 //! decorations.
3 //!
4 //! When window decorations are not present, the user cannot drag a window by
5 //! its titlebar to change its position. The `start_drag_move()` function
6 //! permits a user to drag a window by left clicking anywhere in the window;
7 //! left click must be pressed and other constraints can be imposed. For
8 //! instance an application could require a user to hold down alt and left click
9 //! to drag a window.
10 //!
11 //! The `start_drag_resize()` function behaves similarly but permits a window to
12 //! be resized.
13 use bevy::{math::CompassOctant, prelude::*};
14
15 /// Determine what do on left click.
16 #[derive(Resource, Debug)]
17 enum LeftClickAction {
18 /// Do nothing.
19 Nothing,
20 /// Move the window on left click.
21 Move,
22 /// Resize the window on left click.
23 Resize,
24 }
25
26 /// What direction index should the window resize toward.
27 #[derive(Resource)]
28 struct ResizeDir(usize);
29
30 /// Directions that the drag resizes the window toward.
31 const DIRECTIONS: [CompassOctant; 8] = [
32 CompassOctant::North,
33 CompassOctant::NorthEast,
34 CompassOctant::East,
35 CompassOctant::SouthEast,
36 CompassOctant::South,
37 CompassOctant::SouthWest,
38 CompassOctant::West,
39 CompassOctant::NorthWest,
40 ];
41
42 fn main() {
43 App::new()
44 .add_plugins(DefaultPlugins.set(WindowPlugin {
45 primary_window: Some(Window {
46 decorations: false,
47 ..default()
48 }),
49 ..default()
50 }))
51 .insert_resource(ResizeDir(7))
52 .insert_resource(LeftClickAction::Move)
53 .add_systems(Startup, setup)
54 .add_systems(Update, (handle_input, move_or_resize_windows))
55 .run();
56 }
57
58 fn setup(mut commands: Commands) {
59 // Camera
60 commands.spawn(Camera3d::default());
61
62 // UI
63 commands.spawn((
64 Node {
65 position_type: PositionType::Absolute,
66 padding: UiRect::all(px(5)),
67 ..default()
68 },
69 BackgroundColor(Color::BLACK.with_alpha(0.75)),
70 GlobalZIndex(i32::MAX),
71 children![(
72 Text::default(),
73 children![
74 TextSpan::new(
75 "Demonstrate drag move and drag resize without window decorations.\n\n",
76 ),
77 TextSpan::new("Controls:\n"),
78 TextSpan::new("A - change left click action ["),
79 TextSpan::new("Move"),
80 TextSpan::new("]\n"),
81 TextSpan::new("S / D - change resize direction ["),
82 TextSpan::new("NorthWest"),
83 TextSpan::new("]\n"),
84 ]
85 )],
86 ));
87 }
88
89 fn handle_input(
90 input: Res<ButtonInput<KeyCode>>,
91 mut action: ResMut<LeftClickAction>,
92 mut dir: ResMut<ResizeDir>,
93 example_text: Query<Entity, With<Text>>,
94 mut writer: TextUiWriter,
95 ) -> Result {
96 use LeftClickAction::*;
97 if input.just_pressed(KeyCode::KeyA) {
98 *action = match *action {
99 Move => Resize,
100 Resize => Nothing,
101 Nothing => Move,
102 };
103 *writer.text(example_text.single()?, 4) = format!("{:?}", *action);
104 }
105
106 if input.just_pressed(KeyCode::KeyS) {
107 dir.0 = dir
108 .0
109 .checked_sub(1)
110 .unwrap_or(DIRECTIONS.len().saturating_sub(1));
111 *writer.text(example_text.single()?, 7) = format!("{:?}", DIRECTIONS[dir.0]);
112 }
113
114 if input.just_pressed(KeyCode::KeyD) {
115 dir.0 = (dir.0 + 1) % DIRECTIONS.len();
116 *writer.text(example_text.single()?, 7) = format!("{:?}", DIRECTIONS[dir.0]);
117 }
118
119 Ok(())
120 }
121
122 fn move_or_resize_windows(
123 mut windows: Query<&mut Window>,
124 action: Res<LeftClickAction>,
125 input: Res<ButtonInput<MouseButton>>,
126 dir: Res<ResizeDir>,
127 ) {
128 // Both `start_drag_move()` and `start_drag_resize()` must be called after a
129 // left mouse button press as done here.
130 //
131 // winit 0.30.5 may panic when initiated without a left mouse button press.
132 if input.just_pressed(MouseButton::Left) {
133 for mut window in windows.iter_mut() {
134 match *action {
135 LeftClickAction::Nothing => (),
136 LeftClickAction::Move => window.start_drag_move(),
137 LeftClickAction::Resize => {
138 let d = DIRECTIONS[dir.0];
139 window.start_drag_resize(d);
140 }
141 }
142 }
143 }
144 }