diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index d0cf8017a80..ede9a5f6993 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -582,6 +582,9 @@
If [code]true[/code], warps the mouse around the 2D viewport while panning in the 2D editor. This makes it possible to pan over a large area without having to exit panning and adjust the mouse cursor.
+
+ The mouse cursor movement direction to use when drag-zooming in any editor (except 3D scene editor) by moving the mouse. This does not affect zooming with the mouse wheel.
+
The delay in seconds until more complex and performance costly polygon editors commit their outlines, e.g. the 2D navigation polygon editor rebakes the navigation mesh polygons. A negative value stops the auto bake.
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index a4d5d496210..12bbad791d7 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -920,6 +920,7 @@ void EditorSettings::_load_defaults(Ref p_extra_config) {
_initial_set("editors/panning/simple_panning", false);
_initial_set("editors/panning/warped_mouse_panning", true);
_initial_set("editors/panning/2d_editor_pan_speed", 20, true);
+ EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "editors/panning/zoom_style", 0, "Vertical,Horizontal");
// Tiles editor
_initial_set("editors/tiles_editor/display_grid", true);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 156919c07a9..00fa7d06b81 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -4129,6 +4129,7 @@ void CanvasItemEditor::_update_editor_settings() {
panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/2d_editor_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
panner->set_scroll_speed(EDITOR_GET("editors/panning/2d_editor_pan_speed"));
panner->setup_warped_panning(get_viewport(), EDITOR_GET("editors/panning/warped_mouse_panning"));
+ panner->set_zoom_style((ViewPanner::ZoomStyle)EDITOR_GET("editors/panning/zoom_style").operator int());
}
void CanvasItemEditor::_project_settings_changed() {
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index 24272a188a6..466660d99d9 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -52,7 +52,7 @@ void TileAtlasView::_pan_callback(Vector2 p_scroll_vec, Ref p_event)
void TileAtlasView::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref p_event) {
zoom_widget->set_zoom(zoom_widget->get_zoom() * p_zoom_factor);
- _update_zoom_and_panning(true);
+ _update_zoom_and_panning(true, p_origin);
emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning);
}
@@ -92,7 +92,7 @@ Size2i TileAtlasView::_compute_alternative_tiles_control_size() {
return size;
}
-void TileAtlasView::_update_zoom_and_panning(bool p_zoom_on_mouse_pos) {
+void TileAtlasView::_update_zoom_and_panning(bool p_zoom_on_mouse_pos, const Vector2 &p_mouse_pos) {
if (tile_set_atlas_source.is_null()) {
return;
}
@@ -132,8 +132,7 @@ void TileAtlasView::_update_zoom_and_panning(bool p_zoom_on_mouse_pos) {
// Zoom on the position.
if (p_zoom_on_mouse_pos) {
- // Offset the panning relative to the center of panel.
- Vector2 relative_mpos = get_local_mouse_position() - get_size() / 2;
+ Vector2 relative_mpos = p_mouse_pos - get_size() / 2;
panning = (panning - relative_mpos) * zoom / previous_zoom + relative_mpos;
} else {
// Center of panel.
diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h
index 781447cfa46..1824fb20a3d 100644
--- a/editor/plugins/tiles/tile_atlas_view.h
+++ b/editor/plugins/tiles/tile_atlas_view.h
@@ -58,7 +58,7 @@ private:
Button *button_center_view = nullptr;
CenterContainer *center_container = nullptr;
Vector2 panning;
- void _update_zoom_and_panning(bool p_zoom_on_mouse_pos = false);
+ void _update_zoom_and_panning(bool p_zoom_on_mouse_pos = false, const Vector2 &p_mouse_pos = Vector2());
void _zoom_widget_changed();
void _center_view();
virtual void gui_input(const Ref &p_event) override;
diff --git a/scene/gui/view_panner.cpp b/scene/gui/view_panner.cpp
index ebc91ac03df..df7dc3f8a3a 100644
--- a/scene/gui/view_panner.cpp
+++ b/scene/gui/view_panner.cpp
@@ -92,16 +92,26 @@ bool ViewPanner::gui_input(const Ref &p_event, Rect2 p_canvas_rect)
return false;
}
- bool is_drag_event = mb->get_button_index() == MouseButton::MIDDLE ||
+ drag_type = DragType::DRAG_TYPE_NONE;
+
+ bool is_drag_zoom_event = mb->get_button_index() == MouseButton::MIDDLE && mb->is_ctrl_pressed();
+
+ if (is_drag_zoom_event) {
+ if (mb->is_pressed()) {
+ drag_type = DragType::DRAG_TYPE_ZOOM;
+ drag_zoom_position = mb->get_position();
+ }
+ return true;
+ }
+
+ bool is_drag_pan_event = mb->get_button_index() == MouseButton::MIDDLE ||
(enable_rmb && mb->get_button_index() == MouseButton::RIGHT) ||
(!simple_panning_enabled && mb->get_button_index() == MouseButton::LEFT && is_panning()) ||
(force_drag && mb->get_button_index() == MouseButton::LEFT);
- if (is_drag_event) {
+ if (is_drag_pan_event) {
if (mb->is_pressed()) {
- is_dragging = true;
- } else {
- is_dragging = false;
+ drag_type = DragType::DRAG_TYPE_PAN;
}
return mb->get_button_index() != MouseButton::LEFT || mb->is_pressed(); // Don't consume LMB release events (it fixes some selection problems).
}
@@ -109,13 +119,23 @@ bool ViewPanner::gui_input(const Ref &p_event, Rect2 p_canvas_rect)
Ref mm = p_event;
if (mm.is_valid()) {
- if (is_dragging) {
+ if (drag_type == DragType::DRAG_TYPE_PAN) {
if (warped_panning_viewport && p_canvas_rect.has_area()) {
pan_callback.call(warped_panning_viewport->wrap_mouse_in_rect(mm->get_relative(), p_canvas_rect), p_event);
} else {
pan_callback.call(mm->get_relative(), p_event);
}
return true;
+ } else if (drag_type == DragType::DRAG_TYPE_ZOOM) {
+ float drag_zoom_distance = 0.0;
+ if (zoom_style == ZoomStyle::ZOOM_VERTICAL) {
+ drag_zoom_distance = mm->get_relative().y;
+ } else if (zoom_style == ZoomStyle::ZOOM_HORIZONTAL) {
+ drag_zoom_distance = mm->get_relative().x * -1.0; // Needs to be flipped to match the 3D horizontal zoom style.
+ }
+ float drag_zoom_factor = 1.0 + (drag_zoom_distance * scroll_zoom_factor * drag_zoom_sensitivity_factor);
+ zoom_callback.call(drag_zoom_factor, drag_zoom_position, p_event);
+ return true;
}
}
@@ -157,7 +177,11 @@ bool ViewPanner::gui_input(const Ref &p_event, Rect2 p_canvas_rect)
if (pan_view_shortcut.is_valid() && pan_view_shortcut->matches_event(k)) {
pan_key_pressed = k->is_pressed();
if (simple_panning_enabled || Input::get_singleton()->get_mouse_button_mask().has_flag(MouseButtonMask::LEFT)) {
- is_dragging = pan_key_pressed;
+ if (pan_key_pressed) {
+ drag_type = DragType::DRAG_TYPE_PAN;
+ } else if (drag_type == DragType::DRAG_TYPE_PAN) {
+ drag_type = DragType::DRAG_TYPE_NONE;
+ }
}
return true;
}
@@ -168,7 +192,9 @@ bool ViewPanner::gui_input(const Ref &p_event, Rect2 p_canvas_rect)
void ViewPanner::release_pan_key() {
pan_key_pressed = false;
- is_dragging = false;
+ if (drag_type == DragType::DRAG_TYPE_PAN) {
+ drag_type = DragType::DRAG_TYPE_NONE;
+ }
}
void ViewPanner::set_callbacks(Callable p_pan_callback, Callable p_zoom_callback) {
@@ -207,6 +233,10 @@ void ViewPanner::set_pan_axis(PanAxis p_pan_axis) {
pan_axis = p_pan_axis;
}
+void ViewPanner::set_zoom_style(ZoomStyle p_zoom_style) {
+ zoom_style = p_zoom_style;
+}
+
void ViewPanner::setup(ControlScheme p_scheme, Ref p_shortcut, bool p_simple_panning) {
set_control_scheme(p_scheme);
set_pan_shortcut(p_shortcut);
@@ -218,7 +248,7 @@ void ViewPanner::setup_warped_panning(Viewport *p_viewport, bool p_allowed) {
}
bool ViewPanner::is_panning() const {
- return is_dragging || pan_key_pressed;
+ return (drag_type == DragType::DRAG_TYPE_PAN) || pan_key_pressed;
}
void ViewPanner::set_force_drag(bool p_force) {
diff --git a/scene/gui/view_panner.h b/scene/gui/view_panner.h
index 942d940dc0b..df097c06b13 100644
--- a/scene/gui/view_panner.h
+++ b/scene/gui/view_panner.h
@@ -51,15 +51,32 @@ public:
PAN_AXIS_VERTICAL,
};
+ enum DragType {
+ DRAG_TYPE_NONE,
+ DRAG_TYPE_PAN,
+ DRAG_TYPE_ZOOM,
+ };
+
+ enum ZoomStyle {
+ ZOOM_VERTICAL,
+ ZOOM_HORIZONTAL,
+ };
+
private:
int scroll_speed = 32;
float scroll_zoom_factor = 1.1;
PanAxis pan_axis = PAN_AXIS_BOTH;
- bool is_dragging = false;
bool pan_key_pressed = false;
bool force_drag = false;
+ DragType drag_type = DragType::DRAG_TYPE_NONE;
+
+ ZoomStyle zoom_style = ZoomStyle::ZOOM_VERTICAL;
+
+ Vector2 drag_zoom_position;
+ float drag_zoom_sensitivity_factor = -0.01f;
+
bool enable_rmb = false;
bool simple_panning_enabled = false;
@@ -80,6 +97,7 @@ public:
void set_scroll_speed(int p_scroll_speed);
void set_scroll_zoom_factor(float p_scroll_zoom_factor);
void set_pan_axis(PanAxis p_pan_axis);
+ void set_zoom_style(ZoomStyle p_zoom_style);
void setup(ControlScheme p_scheme, Ref p_shortcut, bool p_simple_panning);
void setup_warped_panning(Viewport *p_viewport, bool p_allowed);