From 5bdb5f5c3779742dec0ac3b44a9830c134b751c4 Mon Sep 17 00:00:00 2001 From: aXu-AP <1621768+aXu-AP@users.noreply.github.com> Date: Sat, 21 Oct 2023 13:23:35 +0300 Subject: [PATCH] Improve UV editor zoom behavior Scrolling focuses towards mouse like in canvas editor. Center view on opening. Adjust scroll area to include polygons larger than texture. Change zoom slider to EditorZoomWidget. --- editor/plugins/polygon_2d_editor_plugin.cpp | 152 ++++++++++---------- editor/plugins/polygon_2d_editor_plugin.h | 9 +- 2 files changed, 80 insertions(+), 81 deletions(-) diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index f8e6c71a4ccc..148ba7d7cae8 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -36,6 +36,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/gui/editor_zoom_widget.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "scene/2d/skeleton_2d.h" #include "scene/gui/check_box.h" @@ -96,10 +97,14 @@ void Polygon2DEditor::_notification(int p_what) { b_snap_grid->set_icon(get_editor_theme_icon(SNAME("Grid"))); b_snap_enable->set_icon(get_editor_theme_icon(SNAME("SnapGrid"))); - uv_icon_zoom->set_texture(get_editor_theme_icon(SNAME("Zoom"))); uv_vscroll->set_anchors_and_offsets_preset(PRESET_RIGHT_WIDE); uv_hscroll->set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE); + // Avoid scrollbar overlapping. + Size2 hmin = uv_hscroll->get_combined_minimum_size(); + Size2 vmin = uv_vscroll->get_combined_minimum_size(); + uv_hscroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, -vmin.width); + uv_vscroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -hmin.height); [[fallthrough]]; } case NOTIFICATION_THEME_CHANGED: { @@ -317,6 +322,7 @@ void Polygon2DEditor::_menu_option(int p_option) { uv_edit->popup_centered_ratio(0.85); } _update_bone_list(); + get_tree()->connect("process_frame", callable_mp(this, &Polygon2DEditor::_center_view), CONNECT_ONE_SHOT); } break; case UVEDIT_POLYGON_TO_UV: { Vector points = node->get_polygon(); @@ -470,7 +476,7 @@ void Polygon2DEditor::_uv_input(const Ref &p_input) { } Transform2D mtx; - mtx.columns[2] = -uv_draw_ofs; + mtx.columns[2] = -uv_draw_ofs * uv_draw_zoom; mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom)); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); @@ -941,36 +947,79 @@ void Polygon2DEditor::_uv_input(const Ref &p_input) { uv_edit_draw->queue_redraw(); } } +} - Ref magnify_gesture = p_input; - if (magnify_gesture.is_valid()) { - uv_zoom->set_value(uv_zoom->get_value() * magnify_gesture->get_factor()); +void Polygon2DEditor::_center_view() { + Size2 texture_size; + if (node->get_texture().is_valid()) { + texture_size = node->get_texture()->get_size(); + Vector2 zoom_factor = (uv_edit_draw->get_size() - Vector2(1, 1) * 50 * EDSCALE) / texture_size; + zoom_widget->set_zoom(MIN(zoom_factor.x, zoom_factor.y)); + } else { + zoom_widget->set_zoom(EDSCALE); } + // Recalculate scroll limits. + _update_zoom_and_pan(false); - Ref pan_gesture = p_input; - if (pan_gesture.is_valid()) { - uv_hscroll->set_value(uv_hscroll->get_value() + uv_hscroll->get_page() * pan_gesture->get_delta().x / 8); - uv_vscroll->set_value(uv_vscroll->get_value() + uv_vscroll->get_page() * pan_gesture->get_delta().y / 8); - } + Size2 offset = (texture_size - uv_edit_draw->get_size() / uv_draw_zoom) / 2; + uv_hscroll->set_value_no_signal(offset.x); + uv_vscroll->set_value_no_signal(offset.y); + _update_zoom_and_pan(false); } void Polygon2DEditor::_uv_pan_callback(Vector2 p_scroll_vec, Ref p_event) { - uv_hscroll->set_value(uv_hscroll->get_value() - p_scroll_vec.x); - uv_vscroll->set_value(uv_vscroll->get_value() - p_scroll_vec.y); + uv_hscroll->set_value_no_signal(uv_hscroll->get_value() - p_scroll_vec.x / uv_draw_zoom); + uv_vscroll->set_value_no_signal(uv_vscroll->get_value() - p_scroll_vec.y / uv_draw_zoom); + _update_zoom_and_pan(false); } void Polygon2DEditor::_uv_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref p_event) { - uv_zoom->set_value(uv_zoom->get_value() * p_zoom_factor); + zoom_widget->set_zoom(uv_draw_zoom * p_zoom_factor); + uv_draw_ofs += p_origin / uv_draw_zoom - p_origin / zoom_widget->get_zoom(); + uv_hscroll->set_value_no_signal(uv_draw_ofs.x); + uv_vscroll->set_value_no_signal(uv_draw_ofs.y); + _update_zoom_and_pan(false); } -void Polygon2DEditor::_uv_scroll_changed(real_t) { - if (updating_uv_scroll) { - return; +void Polygon2DEditor::_update_zoom_and_pan(bool p_zoom_at_center) { + uv_draw_ofs = Vector2(uv_hscroll->get_value(), uv_vscroll->get_value()); + real_t previous_zoom = uv_draw_zoom; + uv_draw_zoom = zoom_widget->get_zoom(); + if (p_zoom_at_center) { + Vector2 center = uv_edit_draw->get_size() / 2; + uv_draw_ofs += center / previous_zoom - center / uv_draw_zoom; } - uv_draw_ofs.x = uv_hscroll->get_value(); - uv_draw_ofs.y = uv_vscroll->get_value(); - uv_draw_zoom = uv_zoom->get_value(); + Point2 min_corner; + Point2 max_corner; + if (node->get_texture().is_valid()) { + max_corner += node->get_texture()->get_size(); + } + + Vector points = uv_edit_mode[0]->is_pressed() ? node->get_uv() : node->get_polygon(); + for (int i = 0; i < points.size(); i++) { + min_corner = min_corner.min(points[i]); + max_corner = max_corner.max(points[i]); + } + Size2 page_size = uv_edit_draw->get_size() / uv_draw_zoom; + Vector2 margin = Vector2(50, 50) * EDSCALE / uv_draw_zoom; + min_corner -= page_size - margin; + max_corner += page_size - margin; + + uv_hscroll->set_block_signals(true); + uv_hscroll->set_min(min_corner.x); + uv_hscroll->set_max(max_corner.x); + uv_hscroll->set_page(page_size.x); + uv_hscroll->set_value(uv_draw_ofs.x); + uv_hscroll->set_block_signals(false); + + uv_vscroll->set_block_signals(true); + uv_vscroll->set_min(min_corner.y); + uv_vscroll->set_max(max_corner.y); + uv_vscroll->set_page(page_size.y); + uv_vscroll->set_value(uv_draw_ofs.y); + uv_vscroll->set_block_signals(false); + uv_edit_draw->queue_redraw(); } @@ -987,7 +1036,7 @@ void Polygon2DEditor::_uv_draw() { String warning; Transform2D mtx; - mtx.columns[2] = -uv_draw_ofs; + mtx.columns[2] = -uv_draw_ofs * uv_draw_zoom; mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom)); // Draw texture as a background if editing uvs or no uv mapping exist. @@ -1094,7 +1143,6 @@ void Polygon2DEditor::_uv_draw() { polygon_fill_color.push_back(pf); } Color prev_color = Color(0.5, 0.5, 0.5); - Rect2 rect; int uv_draw_max = uvs.size(); @@ -1222,40 +1270,6 @@ void Polygon2DEditor::_uv_draw() { //draw paint circle uv_edit_draw->draw_circle(bone_paint_pos, bone_paint_radius->get_value() * EDSCALE, Color(1, 1, 1, 0.1)); } - - rect.position = -uv_edit_draw->get_size(); - rect.size = uv_edit_draw->get_size() * 2.0 + base_tex->get_size() * uv_draw_zoom; - - updating_uv_scroll = true; - - uv_hscroll->set_min(rect.position.x); - uv_hscroll->set_max(rect.position.x + rect.size.x); - if (ABS(rect.position.x - (rect.position.x + rect.size.x)) <= uv_edit_draw->get_size().x) { - uv_hscroll->hide(); - } else { - uv_hscroll->show(); - uv_hscroll->set_page(uv_edit_draw->get_size().x); - uv_hscroll->set_value(uv_draw_ofs.x); - } - - uv_vscroll->set_min(rect.position.y); - uv_vscroll->set_max(rect.position.y + rect.size.y); - if (ABS(rect.position.y - (rect.position.y + rect.size.y)) <= uv_edit_draw->get_size().y) { - uv_vscroll->hide(); - } else { - uv_vscroll->show(); - uv_vscroll->set_page(uv_edit_draw->get_size().y); - uv_vscroll->set_value(uv_draw_ofs.y); - } - - Size2 hmin = uv_hscroll->get_combined_minimum_size(); - Size2 vmin = uv_vscroll->get_combined_minimum_size(); - - // Avoid scrollbar overlapping. - uv_hscroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, uv_vscroll->is_visible() ? -vmin.width : 0); - uv_vscroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, uv_hscroll->is_visible() ? -hmin.height : 0); - - updating_uv_scroll = false; } void Polygon2DEditor::_bind_methods() { @@ -1480,33 +1494,20 @@ Polygon2DEditor::Polygon2DEditor() { sb_step_y->connect("value_changed", callable_mp(this, &Polygon2DEditor::_set_snap_step_y)); grid_settings_vb->add_margin_child(TTR("Grid Step Y:"), sb_step_y); - uv_mode_hb->add_child(memnew(VSeparator)); - uv_icon_zoom = memnew(TextureRect); - uv_icon_zoom->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); - uv_mode_hb->add_child(uv_icon_zoom); - uv_zoom = memnew(HSlider); - uv_zoom->set_min(0.01); - uv_zoom->set_max(16); - uv_zoom->set_value(1); - uv_zoom->set_step(0.01); - uv_zoom->set_v_size_flags(SIZE_SHRINK_CENTER); - - uv_mode_hb->add_child(uv_zoom); - uv_zoom->set_custom_minimum_size(Size2(80 * EDSCALE, 0)); - uv_zoom_value = memnew(SpinBox); - uv_zoom->share(uv_zoom_value); - uv_zoom_value->set_custom_minimum_size(Size2(50, 0)); - uv_mode_hb->add_child(uv_zoom_value); - uv_zoom->connect("value_changed", callable_mp(this, &Polygon2DEditor::_uv_scroll_changed)); + zoom_widget = memnew(EditorZoomWidget); + uv_edit_draw->add_child(zoom_widget); + zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE); + zoom_widget->connect("zoom_changed", callable_mp(this, &Polygon2DEditor::_update_zoom_and_pan).unbind(1).bind(true)); + zoom_widget->set_shortcut_context(nullptr); uv_vscroll = memnew(VScrollBar); uv_vscroll->set_step(0.001); uv_edit_draw->add_child(uv_vscroll); - uv_vscroll->connect("value_changed", callable_mp(this, &Polygon2DEditor::_uv_scroll_changed)); + uv_vscroll->connect("value_changed", callable_mp(this, &Polygon2DEditor::_update_zoom_and_pan).unbind(1).bind(false)); uv_hscroll = memnew(HScrollBar); uv_hscroll->set_step(0.001); uv_edit_draw->add_child(uv_hscroll); - uv_hscroll->connect("value_changed", callable_mp(this, &Polygon2DEditor::_uv_scroll_changed)); + uv_hscroll->connect("value_changed", callable_mp(this, &Polygon2DEditor::_update_zoom_and_pan).unbind(1).bind(false)); bone_scroll_main_vb = memnew(VBoxContainer); bone_scroll_main_vb->hide(); @@ -1535,7 +1536,6 @@ Polygon2DEditor::Polygon2DEditor() { point_drag_index = -1; uv_drag = false; uv_create = false; - updating_uv_scroll = false; bone_painting = false; error = memnew(AcceptDialog); diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h index 8c52984b593c..164aa3eccc83 100644 --- a/editor/plugins/polygon_2d_editor_plugin.h +++ b/editor/plugins/polygon_2d_editor_plugin.h @@ -35,6 +35,7 @@ class AcceptDialog; class ButtonGroup; +class EditorZoomWidget; class HScrollBar; class HSlider; class Label; @@ -85,12 +86,10 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { Panel *uv_edit_background = nullptr; Polygon2D *preview_polygon = nullptr; Control *uv_edit_draw = nullptr; - HSlider *uv_zoom = nullptr; - SpinBox *uv_zoom_value = nullptr; + EditorZoomWidget *zoom_widget = nullptr; HScrollBar *uv_hscroll = nullptr; VScrollBar *uv_vscroll = nullptr; MenuButton *uv_menu = nullptr; - TextureRect *uv_icon_zoom = nullptr; Ref uv_panner; void _uv_pan_callback(Vector2 p_scroll_vec, Ref p_event); @@ -129,7 +128,6 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { Vector polygon_create; UVMode uv_move_current; Vector2 uv_drag_from; - bool updating_uv_scroll; AcceptDialog *error = nullptr; @@ -145,7 +143,8 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { void _cancel_editing(); void _update_polygon_editing_state(); - void _uv_scroll_changed(real_t); + void _center_view(); + void _update_zoom_and_pan(bool p_zoom_at_center); void _uv_input(const Ref &p_input); void _uv_draw(); void _uv_mode(int p_mode);