Merge pull request #105625 from zmn-hamid/zoom_drag_2d

Add drag zoom feature with CTRL+MiddleMouseButton
This commit is contained in:
Thaddeus Crews
2025-05-01 14:27:20 -05:00
7 changed files with 67 additions and 15 deletions

View File

@ -582,6 +582,9 @@
<member name="editors/panning/warped_mouse_panning" type="bool" setter="" getter="">
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.
</member>
<member name="editors/panning/zoom_style" type="int" setter="" getter="">
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.
</member>
<member name="editors/polygon_editor/auto_bake_delay" type="float" setter="" getter="">
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.
</member>

View File

@ -920,6 +920,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> 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);

View File

@ -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() {

View File

@ -52,7 +52,7 @@ void TileAtlasView::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event)
void TileAtlasView::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> 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.

View File

@ -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<InputEvent> &p_event) override;

View File

@ -92,16 +92,26 @@ bool ViewPanner::gui_input(const Ref<InputEvent> &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<InputEvent> &p_event, Rect2 p_canvas_rect)
Ref<InputEventMouseMotion> 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<InputEvent> &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<InputEvent> &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<Shortcut> 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) {

View File

@ -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<Shortcut> p_shortcut, bool p_simple_panning);
void setup_warped_panning(Viewport *p_viewport, bool p_allowed);