feat: Add `Scene::drag_pan_buttons` option. Allows specifying which pointer buttons pan the scene by dragging. (#5892)

This adds an option for specifying the set of pointer buttons that can
be used to pan the scene via clicking and dragging.

The original behaviour where all buttons can pan the scene by default is
maintained.

Addresses part of #5891.

---

Edit: It looks like the failing test is unrelated and also appears on
master:
https://github.com/emilk/egui/actions/runs/14330259861/job/40164414607.

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
mitchmindtree 2025-04-22 12:42:24 +03:00 committed by GitHub
parent 114460c1de
commit cd318f0e55
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 46 additions and 3 deletions

View File

@ -29,7 +29,7 @@ pub use {
panel::{CentralPanel, SidePanel, TopBottomPanel},
popup::*,
resize::Resize,
scene::Scene,
scene::{DragPanButtons, Scene},
scroll_area::ScrollArea,
sides::Sides,
tooltip::*,

View File

@ -3,7 +3,8 @@ use core::f32;
use emath::{GuiRounding, Pos2};
use crate::{
emath::TSTransform, InnerResponse, LayerId, Rangef, Rect, Response, Sense, Ui, UiBuilder, Vec2,
emath::TSTransform, InnerResponse, LayerId, PointerButton, Rangef, Rect, Response, Sense, Ui,
UiBuilder, Vec2,
};
/// Creates a transformation that fits a given scene rectangle into the available screen size.
@ -45,6 +46,30 @@ fn fit_to_rect_in_scene(
pub struct Scene {
zoom_range: Rangef,
max_inner_size: Vec2,
drag_pan_buttons: DragPanButtons,
}
/// Specifies which pointer buttons can be used to pan the scene by dragging.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct DragPanButtons(u8);
bitflags::bitflags! {
impl DragPanButtons: u8 {
/// [PointerButton::Primary]
const PRIMARY = 1 << 0;
/// [PointerButton::Secondary]
const SECONDARY = 1 << 1;
/// [PointerButton::Middle]
const MIDDLE = 1 << 2;
/// [PointerButton::Extra1]
const EXTRA_1 = 1 << 3;
/// [PointerButton::Extra2]
const EXTRA_2 = 1 << 4;
}
}
impl Default for Scene {
@ -52,6 +77,7 @@ impl Default for Scene {
Self {
zoom_range: Rangef::new(f32::EPSILON, 1.0),
max_inner_size: Vec2::splat(1000.0),
drag_pan_buttons: DragPanButtons::all(),
}
}
}
@ -82,6 +108,15 @@ impl Scene {
self
}
/// Specify which pointer buttons can be used to pan by clicking and dragging.
///
/// By default, this is `DragPanButtons::all()`.
#[inline]
pub fn drag_pan_buttons(mut self, flags: DragPanButtons) -> Self {
self.drag_pan_buttons = flags;
self
}
/// `scene_rect` contains the view bounds of the inner [`Ui`].
///
/// `scene_rect` will be mutated by any panning/zooming done by the user.
@ -179,7 +214,15 @@ impl Scene {
/// Helper function to handle pan and zoom interactions on a response.
pub fn register_pan_and_zoom(&self, ui: &Ui, resp: &mut Response, to_global: &mut TSTransform) {
if resp.dragged() {
let dragged = self.drag_pan_buttons.iter().any(|button| match button {
DragPanButtons::PRIMARY => resp.dragged_by(PointerButton::Primary),
DragPanButtons::SECONDARY => resp.dragged_by(PointerButton::Secondary),
DragPanButtons::MIDDLE => resp.dragged_by(PointerButton::Middle),
DragPanButtons::EXTRA_1 => resp.dragged_by(PointerButton::Extra1),
DragPanButtons::EXTRA_2 => resp.dragged_by(PointerButton::Extra2),
_ => false,
});
if dragged {
to_global.translation += to_global.scaling * resp.drag_delta();
resp.mark_changed();
}