Skip to content

Commit c8bf935

Browse files
authored
Zoom with mouse button + motion (#129)
1 parent ba3a46c commit c8bf935

File tree

3 files changed

+58
-4
lines changed

3 files changed

+58
-4
lines changed

examples/advanced.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//! Controls:
55
//! Orbit: Middle click
66
//! Pan: Shift + Middle click
7-
//! Zoom: Mousewheel
7+
//! Zoom: Mousewheel OR Right click + move mouse up/down
88
99
use bevy::prelude::*;
1010
use bevy_panorbit_camera::{PanOrbitCamera, PanOrbitCameraPlugin, TouchControls};
@@ -71,6 +71,10 @@ fn setup(
7171
button_orbit: MouseButton::Middle,
7272
button_pan: MouseButton::Middle,
7373
modifier_pan: Some(KeyCode::ShiftLeft),
74+
// Also enable zooming by holding right click and moving the mouse
75+
button_zoom: Some(MouseButton::Right),
76+
// Optionally configure button zoom to use left-right mouse movement
77+
// button_zoom_axis: ButtonZoomAxis::X,
7478
// Reverse the zoom direction
7579
reversed_zoom: true,
7680
// Use alternate touch controls

src/input.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use bevy::input::gestures::PinchGesture;
22
use bevy::input::mouse::{MouseMotion, MouseScrollUnit, MouseWheel};
33
use bevy::prelude::*;
44

5-
use crate::{ActiveCameraData, PanOrbitCamera, TrackpadBehavior};
5+
use crate::{ActiveCameraData, ButtonZoomAxis, PanOrbitCamera, TrackpadBehavior};
66

77
#[derive(Resource, Default, Debug)]
88
pub struct MouseKeyTracker {
@@ -52,6 +52,18 @@ pub fn mouse_key_tracker(
5252
// Process pinch events
5353
let pinch_zoom = process_pinch_events(&mut pinch_events, pan_orbit, &key_input);
5454

55+
// If zoom button set, apply zoom based on mouse movement
56+
let mouse_zoom = if button_zoom_pressed(pan_orbit, &mouse_input) {
57+
let delta = match pan_orbit.button_zoom_axis {
58+
ButtonZoomAxis::X => mouse_delta.x,
59+
ButtonZoomAxis::Y => -mouse_delta.y,
60+
ButtonZoomAxis::XY => mouse_delta.x + -mouse_delta.y,
61+
};
62+
delta * 0.03
63+
} else {
64+
0.0
65+
};
66+
5567
// Handle mouse movement for orbiting and panning
5668
if orbit_pressed(pan_orbit, &mouse_input, &key_input) {
5769
orbit += mouse_delta;
@@ -67,7 +79,7 @@ pub fn mouse_key_tracker(
6779
camera_movement.orbit = orbit;
6880
camera_movement.pan = pan;
6981
camera_movement.scroll_line = scroll_result.scroll_line;
70-
camera_movement.scroll_pixel = scroll_result.scroll_pixel + pinch_zoom;
82+
camera_movement.scroll_pixel = scroll_result.scroll_pixel + pinch_zoom + mouse_zoom;
7183
camera_movement.orbit_button_changed = orbit_button_changed;
7284
}
7385

@@ -264,3 +276,21 @@ pub fn pan_just_pressed(
264276
.modifier_orbit
265277
.is_none_or(|modifier| !key_input.pressed(modifier))
266278
}
279+
280+
pub fn button_zoom_pressed(
281+
pan_orbit: &PanOrbitCamera,
282+
mouse_input: &Res<ButtonInput<MouseButton>>,
283+
) -> bool {
284+
pan_orbit
285+
.button_zoom
286+
.is_some_and(|btn| mouse_input.pressed(btn))
287+
}
288+
289+
pub fn button_zoom_just_pressed(
290+
pan_orbit: &PanOrbitCamera,
291+
mouse_input: &Res<ButtonInput<MouseButton>>,
292+
) -> bool {
293+
pan_orbit
294+
.button_zoom
295+
.is_some_and(|btn| mouse_input.just_pressed(btn))
296+
}

src/lib.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use bevy_egui::EguiPreUpdateSet;
1414

1515
#[cfg(feature = "bevy_egui")]
1616
pub use crate::egui::{EguiFocusIncludesHover, EguiWantsFocus};
17-
use crate::input::{mouse_key_tracker, MouseKeyTracker};
17+
use crate::input::{button_zoom_just_pressed, mouse_key_tracker, MouseKeyTracker};
1818
pub use crate::touch::TouchControls;
1919
use crate::touch::{touch_tracker, TouchGestures, TouchTracker};
2020
use crate::traits::OptionalClamp;
@@ -217,6 +217,12 @@ pub struct PanOrbitCamera {
217217
/// Button used to pan the camera.
218218
/// Defaults to `Button::Right`.
219219
pub button_pan: MouseButton,
220+
/// Button used to zoom the camera, by holding it down and moving the mouse forward and back.
221+
/// Defaults to `None`.
222+
pub button_zoom: Option<MouseButton>,
223+
/// Which axis should zoom the camera when using `button_zoom`.
224+
/// Defaults to `ButtonZoomAxis::Y`.
225+
pub button_zoom_axis: ButtonZoomAxis,
220226
/// Key that must be pressed for `button_orbit` to work.
221227
/// Defaults to `None` (no modifier).
222228
pub modifier_orbit: Option<KeyCode>,
@@ -293,6 +299,8 @@ impl Default for PanOrbitCamera {
293299
zoom_smoothness: 0.1,
294300
button_orbit: MouseButton::Left,
295301
button_pan: MouseButton::Right,
302+
button_zoom: None,
303+
button_zoom_axis: ButtonZoomAxis::Y,
296304
modifier_orbit: None,
297305
modifier_pan: None,
298306
touch_enabled: true,
@@ -357,6 +365,17 @@ pub enum FocusBoundsShape {
357365
Cuboid(Cuboid),
358366
}
359367

368+
/// The shape to restrict the camera's focus inside.
369+
#[derive(Clone, PartialEq, Debug, Reflect, Copy)]
370+
pub enum ButtonZoomAxis {
371+
/// Zoom by moving the mouse along the x-axis.
372+
X,
373+
/// Zoom by moving the mouse along the y-axis.
374+
Y,
375+
/// Zoom by moving the mouse along either the x-axis or the y-axis.
376+
XY,
377+
}
378+
360379
impl From<Sphere> for FocusBoundsShape {
361380
fn from(value: Sphere) -> Self {
362381
Self::Sphere(value)
@@ -420,6 +439,7 @@ fn active_viewport_data(
420439
|| input::pan_just_pressed(pan_orbit, &mouse_input, &key_input)
421440
|| !pinch_events.is_empty()
422441
|| !scroll_events.is_empty()
442+
|| button_zoom_just_pressed(pan_orbit, &mouse_input)
423443
|| (touches.iter_just_pressed().count() > 0
424444
&& touches.iter_just_pressed().count() == touches.iter().count());
425445

0 commit comments

Comments
 (0)