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);