Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve UV editor zoom behavior #83731

Merged
merged 1 commit into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 76 additions & 76 deletions editor/plugins/polygon_2d_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -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<Vector2> points = node->get_polygon();
Expand Down Expand Up @@ -470,7 +476,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &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();
Expand Down Expand Up @@ -941,36 +947,79 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
uv_edit_draw->queue_redraw();
}
}
}

Ref<InputEventMagnifyGesture> 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<InputEventPanGesture> 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<InputEvent> 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<InputEvent> 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;
}

Point2 min_corner;
Point2 max_corner;
if (node->get_texture().is_valid()) {
max_corner += node->get_texture()->get_size();
}

Vector<Vector2> 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_draw_ofs.x = uv_hscroll->get_value();
uv_draw_ofs.y = uv_vscroll->get_value();
uv_draw_zoom = uv_zoom->get_value();
uv_edit_draw->queue_redraw();
}

Expand All @@ -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.
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified and moved this scroll updating logic to _update_zoom_and_pan, since there's no reason to update it on every redraw, only when zoom gets changed. Also helps solving problem of setting scroll position to value which gets clamped by scrollbar, then updating scrollbar limits.
Logic for hiding scrollbars isn't needed, even in this original implementation it never triggers.

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() {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand Down
9 changes: 4 additions & 5 deletions editor/plugins/polygon_2d_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

class AcceptDialog;
class ButtonGroup;
class EditorZoomWidget;
class HScrollBar;
class HSlider;
class Label;
Expand Down Expand Up @@ -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<ViewPanner> uv_panner;
void _uv_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event);
Expand Down Expand Up @@ -129,7 +128,6 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
Vector<int> polygon_create;
UVMode uv_move_current;
Vector2 uv_drag_from;
bool updating_uv_scroll;

AcceptDialog *error = nullptr;

Expand All @@ -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<InputEvent> &p_input);
void _uv_draw();
void _uv_mode(int p_mode);
Expand Down
Loading