diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 6087ea3abc8..b8a112859e0 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -1507,6 +1507,11 @@ Ref create_editor_theme(const Ref p_theme) { style_theme_preview_bg_tab->set_expand_margin(SIDE_BOTTOM, 2 * EDSCALE); theme->set_stylebox("ThemeEditorPreviewBG", "EditorStyles", style_theme_preview_bg_tab); + Ref style_texture_region_bg = style_tree_bg->duplicate(); + style_texture_region_bg->set_content_margin_all(0); + theme->set_stylebox("TextureRegionPreviewBG", "EditorStyles", style_texture_region_bg); + theme->set_stylebox("TextureRegionPreviewFG", "EditorStyles", make_empty_stylebox(0, 0, 0, 0)); + // Separators theme->set_stylebox("separator", "HSeparator", make_line_stylebox(separator_color, MAX(Math::round(EDSCALE), border_width))); theme->set_stylebox("separator", "VSeparator", make_line_stylebox(separator_color, MAX(Math::round(EDSCALE), border_width), 0, 0, true)); diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 19df31a0b34..124cd791266 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -38,64 +38,46 @@ #include "editor/editor_undo_redo_manager.h" #include "scene/gui/check_box.h" #include "scene/gui/option_button.h" +#include "scene/gui/panel_container.h" #include "scene/gui/separator.h" #include "scene/gui/spin_box.h" #include "scene/gui/view_panner.h" #include "scene/resources/atlas_texture.h" -void draw_margin_line(Control *edit_draw, Vector2 from, Vector2 to) { - Vector2 line = (to - from).normalized() * 10; - - // Draw a translucent background line to make the foreground line visible on any background. - edit_draw->draw_line( - from, - to, - EditorNode::get_singleton()->get_theme_base()->get_theme_color(SNAME("mono_color"), SNAME("Editor")).inverted() * Color(1, 1, 1, 0.5), - Math::round(2 * EDSCALE)); - - while (from.distance_squared_to(to) > 200) { - edit_draw->draw_line( - from, - from + line, - EditorNode::get_singleton()->get_theme_base()->get_theme_color(SNAME("mono_color"), SNAME("Editor")), - Math::round(2 * EDSCALE)); - - from += line * 2; - } -} - -void TextureRegionEditor::_region_draw() { - Ref base_tex = nullptr; - if (atlas_tex.is_valid()) { - base_tex = atlas_tex->get_atlas(); - } else if (node_sprite_2d) { - base_tex = node_sprite_2d->get_texture(); - } else if (node_sprite_3d) { - base_tex = node_sprite_3d->get_texture(); - } else if (node_ninepatch) { - base_tex = node_ninepatch->get_texture(); - } else if (obj_styleBox.is_valid()) { - base_tex = obj_styleBox->get_texture(); - } - - if (base_tex.is_null()) { - return; - } - +Transform2D TextureRegionEditor::_get_offset_transform() const { Transform2D mtx; mtx.columns[2] = -draw_ofs * draw_zoom; mtx.scale_basis(Vector2(draw_zoom, draw_zoom)); - RS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), mtx); - edit_draw->draw_rect(Rect2(Point2(), preview_tex->get_size()), Color(0.5, 0.5, 0.5, 0.5), false); - edit_draw->draw_texture(preview_tex, Point2()); - RS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), Transform2D()); + return mtx; +} +void TextureRegionEditor::_texture_preview_draw() { + Ref object_texture = _get_edited_object_texture(); + if (object_texture.is_null()) { + return; + } + + Transform2D mtx = _get_offset_transform(); + + RS::get_singleton()->canvas_item_add_set_transform(texture_preview->get_canvas_item(), mtx); + texture_preview->draw_rect(Rect2(Point2(), object_texture->get_size()), Color(0.5, 0.5, 0.5, 0.5), false); + texture_preview->draw_texture(object_texture, Point2()); + RS::get_singleton()->canvas_item_add_set_transform(texture_preview->get_canvas_item(), Transform2D()); +} + +void TextureRegionEditor::_texture_overlay_draw() { + Ref object_texture = _get_edited_object_texture(); + if (object_texture.is_null()) { + return; + } + + Transform2D mtx = _get_offset_transform(); const Color color = get_theme_color(SNAME("mono_color"), SNAME("Editor")); if (snap_mode == SNAP_GRID) { const Color grid_color = Color(color.r, color.g, color.b, color.a * 0.15); - Size2 s = edit_draw->get_size(); + Size2 s = texture_overlay->get_size(); int last_cell = 0; if (snap_step.x != 0) { @@ -106,7 +88,7 @@ void TextureRegionEditor::_region_draw() { last_cell = cell; } if (last_cell != cell) { - edit_draw->draw_line(Point2(i, 0), Point2(i, s.height), grid_color); + texture_overlay->draw_line(Point2(i, 0), Point2(i, s.height), grid_color); } last_cell = cell; } @@ -117,7 +99,7 @@ void TextureRegionEditor::_region_draw() { last_cell = cell; } if (last_cell != cell) { - edit_draw->draw_rect(Rect2(i - snap_separation.x * draw_zoom, 0, snap_separation.x * draw_zoom, s.height), grid_color); + texture_overlay->draw_rect(Rect2(i - snap_separation.x * draw_zoom, 0, snap_separation.x * draw_zoom, s.height), grid_color); } last_cell = cell; } @@ -132,7 +114,7 @@ void TextureRegionEditor::_region_draw() { last_cell = cell; } if (last_cell != cell) { - edit_draw->draw_line(Point2(0, i), Point2(s.width, i), grid_color); + texture_overlay->draw_line(Point2(0, i), Point2(s.width, i), grid_color); } last_cell = cell; } @@ -143,7 +125,7 @@ void TextureRegionEditor::_region_draw() { last_cell = cell; } if (last_cell != cell) { - edit_draw->draw_rect(Rect2(0, i - snap_separation.y * draw_zoom, s.width, snap_separation.y * draw_zoom), grid_color); + texture_overlay->draw_rect(Rect2(0, i - snap_separation.y * draw_zoom, s.width, snap_separation.y * draw_zoom), grid_color); } last_cell = cell; } @@ -159,14 +141,14 @@ void TextureRegionEditor::_region_draw() { }; for (int i = 0; i < 4; i++) { int next = (i + 1) % 4; - edit_draw->draw_line(endpoints[i] - draw_ofs * draw_zoom, endpoints[next] - draw_ofs * draw_zoom, Color(0.3, 0.7, 1, 1), 2); + texture_overlay->draw_line(endpoints[i] - draw_ofs * draw_zoom, endpoints[next] - draw_ofs * draw_zoom, Color(0.3, 0.7, 1, 1), 2); } } } Ref select_handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons")); - Rect2 scroll_rect(Point2(), base_tex->get_size()); + Rect2 scroll_rect(Point2(), object_texture->get_size()); const Vector2 raw_endpoints[4] = { rect.position, @@ -187,23 +169,23 @@ void TextureRegionEditor::_region_draw() { Vector2 ofs = ((endpoints[i] - endpoints[prev]).normalized() + ((endpoints[i] - endpoints[next]).normalized())).normalized(); ofs *= Math_SQRT2 * (select_handle->get_size().width / 2); - edit_draw->draw_line(endpoints[i] - draw_ofs * draw_zoom, endpoints[next] - draw_ofs * draw_zoom, color, 2); + texture_overlay->draw_line(endpoints[i] - draw_ofs * draw_zoom, endpoints[next] - draw_ofs * draw_zoom, color, 2); if (snap_mode != SNAP_AUTOSLICE) { - edit_draw->draw_texture(select_handle, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor() - draw_ofs * draw_zoom); + texture_overlay->draw_texture(select_handle, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor() - draw_ofs * draw_zoom); } ofs = (endpoints[next] - endpoints[i]) / 2; ofs += (endpoints[next] - endpoints[i]).orthogonal().normalized() * (select_handle->get_size().width / 2); if (snap_mode != SNAP_AUTOSLICE) { - edit_draw->draw_texture(select_handle, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor() - draw_ofs * draw_zoom); + texture_overlay->draw_texture(select_handle, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor() - draw_ofs * draw_zoom); } scroll_rect.expand_to(raw_endpoints[i]); } - const Size2 scroll_margin = edit_draw->get_size() / draw_zoom; + const Size2 scroll_margin = texture_overlay->get_size() / draw_zoom; scroll_rect.position -= scroll_margin; scroll_rect.size += scroll_margin * 2; @@ -244,21 +226,22 @@ void TextureRegionEditor::_region_draw() { vscroll->set_value((vscroll->get_min() + vscroll->get_max() - vscroll->get_page()) / 2); // This ensures that the view is updated correctly. callable_mp(this, &TextureRegionEditor::_pan_callback).bind(Vector2(1, 0)).call_deferred(); + callable_mp(this, &TextureRegionEditor::_scroll_changed).bind(0.0).call_deferred(); request_center = false; } - if (node_ninepatch || obj_styleBox.is_valid()) { + if (node_ninepatch || res_stylebox.is_valid()) { float margins[4] = { 0 }; if (node_ninepatch) { margins[0] = node_ninepatch->get_patch_margin(SIDE_TOP); margins[1] = node_ninepatch->get_patch_margin(SIDE_BOTTOM); margins[2] = node_ninepatch->get_patch_margin(SIDE_LEFT); margins[3] = node_ninepatch->get_patch_margin(SIDE_RIGHT); - } else if (obj_styleBox.is_valid()) { - margins[0] = obj_styleBox->get_texture_margin(SIDE_TOP); - margins[1] = obj_styleBox->get_texture_margin(SIDE_BOTTOM); - margins[2] = obj_styleBox->get_texture_margin(SIDE_LEFT); - margins[3] = obj_styleBox->get_texture_margin(SIDE_RIGHT); + } else if (res_stylebox.is_valid()) { + margins[0] = res_stylebox->get_texture_margin(SIDE_TOP); + margins[1] = res_stylebox->get_texture_margin(SIDE_BOTTOM); + margins[2] = res_stylebox->get_texture_margin(SIDE_LEFT); + margins[3] = res_stylebox->get_texture_margin(SIDE_RIGHT); } Vector2 pos[4] = { @@ -268,14 +251,36 @@ void TextureRegionEditor::_region_draw() { -mtx.basis_xform(Vector2(margins[3], 0)) + Vector2(endpoints[2].x - draw_ofs.x * draw_zoom, 0) }; - draw_margin_line(edit_draw, pos[0], pos[0] + Vector2(edit_draw->get_size().x, 0)); - draw_margin_line(edit_draw, pos[1], pos[1] + Vector2(edit_draw->get_size().x, 0)); - draw_margin_line(edit_draw, pos[2], pos[2] + Vector2(0, edit_draw->get_size().y)); - draw_margin_line(edit_draw, pos[3], pos[3] + Vector2(0, edit_draw->get_size().y)); + _draw_margin_line(pos[0], pos[0] + Vector2(texture_overlay->get_size().x, 0)); + _draw_margin_line(pos[1], pos[1] + Vector2(texture_overlay->get_size().x, 0)); + _draw_margin_line(pos[2], pos[2] + Vector2(0, texture_overlay->get_size().y)); + _draw_margin_line(pos[3], pos[3] + Vector2(0, texture_overlay->get_size().y)); } } -void TextureRegionEditor::_region_input(const Ref &p_input) { +void TextureRegionEditor::_draw_margin_line(Vector2 p_from, Vector2 p_to) { + // Margin line is a dashed line with a normalized dash length. This method works + // for both vertical and horizontal lines. + + Vector2 dash_size = (p_to - p_from).normalized() * 10; + const int dash_thickness = Math::round(2 * EDSCALE); + const Color dash_color = get_theme_color(SNAME("mono_color"), SNAME("Editor")); + const Color dash_bg_color = dash_color.inverted() * Color(1, 1, 1, 0.5); + const int line_threshold = 200; + + // Draw a translucent background line to make the foreground line visible on any background. + texture_overlay->draw_line(p_from, p_to, dash_bg_color, dash_thickness); + + Vector2 dash_start = p_from; + while (dash_start.distance_squared_to(p_to) > line_threshold) { + texture_overlay->draw_line(dash_start, dash_start + dash_size, dash_color, dash_thickness); + + // Skip two size lengths, one for the drawn dash and one for the gap. + dash_start += dash_size * 2; + } +} + +void TextureRegionEditor::_texture_overlay_input(const Ref &p_input) { if (panner->gui_input(p_input)) { return; } @@ -284,112 +289,28 @@ void TextureRegionEditor::_region_input(const Ref &p_input) { mtx.columns[2] = -draw_ofs * draw_zoom; mtx.scale_basis(Vector2(draw_zoom, draw_zoom)); - const real_t handle_radius = 8 * EDSCALE; - const real_t handle_offset = 4 * EDSCALE; - - // Position of selection handles. - const Vector2 endpoints[8] = { - mtx.xform(rect.position) + Vector2(-handle_offset, -handle_offset), - mtx.xform(rect.position + Vector2(rect.size.x / 2, 0)) + Vector2(0, -handle_offset), - mtx.xform(rect.position + Vector2(rect.size.x, 0)) + Vector2(handle_offset, -handle_offset), - mtx.xform(rect.position + Vector2(rect.size.x, rect.size.y / 2)) + Vector2(handle_offset, 0), - mtx.xform(rect.position + rect.size) + Vector2(handle_offset, handle_offset), - mtx.xform(rect.position + Vector2(rect.size.x / 2, rect.size.y)) + Vector2(0, handle_offset), - mtx.xform(rect.position + Vector2(0, rect.size.y)) + Vector2(-handle_offset, handle_offset), - mtx.xform(rect.position + Vector2(0, rect.size.y / 2)) + Vector2(-handle_offset, 0) - }; - EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); Ref mb = p_input; if (mb.is_valid()) { if (mb->get_button_index() == MouseButton::LEFT) { if (mb->is_pressed() && !panner->is_panning()) { - if (node_ninepatch || obj_styleBox.is_valid()) { - edited_margin = -1; - float margins[4] = { 0 }; - if (node_ninepatch) { - margins[0] = node_ninepatch->get_patch_margin(SIDE_TOP); - margins[1] = node_ninepatch->get_patch_margin(SIDE_BOTTOM); - margins[2] = node_ninepatch->get_patch_margin(SIDE_LEFT); - margins[3] = node_ninepatch->get_patch_margin(SIDE_RIGHT); - } else if (obj_styleBox.is_valid()) { - margins[0] = obj_styleBox->get_texture_margin(SIDE_TOP); - margins[1] = obj_styleBox->get_texture_margin(SIDE_BOTTOM); - margins[2] = obj_styleBox->get_texture_margin(SIDE_LEFT); - margins[3] = obj_styleBox->get_texture_margin(SIDE_RIGHT); - } + // Check if we click on any handle first. + { + const real_t handle_radius = 16 * EDSCALE; + const real_t handle_offset = 8 * EDSCALE; - Vector2 pos[4] = { - mtx.basis_xform(rect.position + Vector2(0, margins[0])) - draw_ofs * draw_zoom, - mtx.basis_xform(rect.position + rect.size - Vector2(0, margins[1])) - draw_ofs * draw_zoom, - mtx.basis_xform(rect.position + Vector2(margins[2], 0)) - draw_ofs * draw_zoom, - mtx.basis_xform(rect.position + rect.size - Vector2(margins[3], 0)) - draw_ofs * draw_zoom + // Position of selection handles. + const Vector2 endpoints[8] = { + mtx.xform(rect.position) + Vector2(-handle_offset, -handle_offset), + mtx.xform(rect.position + Vector2(rect.size.x / 2, 0)) + Vector2(0, -handle_offset), + mtx.xform(rect.position + Vector2(rect.size.x, 0)) + Vector2(handle_offset, -handle_offset), + mtx.xform(rect.position + Vector2(rect.size.x, rect.size.y / 2)) + Vector2(handle_offset, 0), + mtx.xform(rect.position + rect.size) + Vector2(handle_offset, handle_offset), + mtx.xform(rect.position + Vector2(rect.size.x / 2, rect.size.y)) + Vector2(0, handle_offset), + mtx.xform(rect.position + Vector2(0, rect.size.y)) + Vector2(-handle_offset, handle_offset), + mtx.xform(rect.position + Vector2(0, rect.size.y / 2)) + Vector2(-handle_offset, 0) }; - if (Math::abs(mb->get_position().y - pos[0].y) < 8) { - edited_margin = 0; - prev_margin = margins[0]; - } else if (Math::abs(mb->get_position().y - pos[1].y) < 8) { - edited_margin = 1; - prev_margin = margins[1]; - } else if (Math::abs(mb->get_position().x - pos[2].x) < 8) { - edited_margin = 2; - prev_margin = margins[2]; - } else if (Math::abs(mb->get_position().x - pos[3].x) < 8) { - edited_margin = 3; - prev_margin = margins[3]; - } - if (edited_margin >= 0) { - drag_from = mb->get_position(); - drag = true; - } - } - if (edited_margin < 0 && snap_mode == SNAP_AUTOSLICE) { - Vector2 point = mtx.affine_inverse().xform(mb->get_position()); - for (const Rect2 &E : autoslice_cache) { - if (E.has_point(point)) { - rect = E; - if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !(Input::get_singleton()->is_key_pressed(Key(Key::SHIFT | Key::ALT)))) { - Rect2 r; - if (atlas_tex.is_valid()) { - r = atlas_tex->get_region(); - } else if (node_sprite_2d) { - r = node_sprite_2d->get_region_rect(); - } else if (node_sprite_3d) { - r = node_sprite_3d->get_region_rect(); - } else if (node_ninepatch) { - r = node_ninepatch->get_region_rect(); - } else if (obj_styleBox.is_valid()) { - r = obj_styleBox->get_region_rect(); - } - rect.expand_to(r.position); - rect.expand_to(r.get_end()); - } - undo_redo->create_action(TTR("Set Region Rect")); - if (atlas_tex.is_valid()) { - undo_redo->add_do_method(atlas_tex.ptr(), "set_region", rect); - undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region()); - } else if (node_sprite_2d) { - undo_redo->add_do_method(node_sprite_2d, "set_region_rect", rect); - undo_redo->add_undo_method(node_sprite_2d, "set_region_rect", node_sprite_2d->get_region_rect()); - } else if (node_sprite_3d) { - undo_redo->add_do_method(node_sprite_3d, "set_region_rect", rect); - undo_redo->add_undo_method(node_sprite_3d, "set_region_rect", node_sprite_3d->get_region_rect()); - } else if (node_ninepatch) { - undo_redo->add_do_method(node_ninepatch, "set_region_rect", rect); - undo_redo->add_undo_method(node_ninepatch, "set_region_rect", node_ninepatch->get_region_rect()); - } else if (obj_styleBox.is_valid()) { - undo_redo->add_do_method(obj_styleBox.ptr(), "set_region_rect", rect); - undo_redo->add_undo_method(obj_styleBox.ptr(), "set_region_rect", obj_styleBox->get_region_rect()); - } - undo_redo->add_do_method(this, "_update_rect"); - undo_redo->add_undo_method(this, "_update_rect"); - undo_redo->add_do_method(edit_draw, "queue_redraw"); - undo_redo->add_undo_method(edit_draw, "queue_redraw"); - undo_redo->commit_action(); - break; - } - } - } else if (edited_margin < 0) { + drag_from = mtx.affine_inverse().xform(mb->get_position()); if (snap_mode == SNAP_PIXEL) { drag_from = drag_from.snapped(Vector2(1, 1)); @@ -397,17 +318,8 @@ void TextureRegionEditor::_region_input(const Ref &p_input) { drag_from = snap_point(drag_from); } drag = true; - if (atlas_tex.is_valid()) { - rect_prev = atlas_tex->get_region(); - } else if (node_sprite_2d) { - rect_prev = node_sprite_2d->get_region_rect(); - } else if (node_sprite_3d) { - rect_prev = node_sprite_3d->get_region_rect(); - } else if (node_ninepatch) { - rect_prev = node_ninepatch->get_region_rect(); - } else if (obj_styleBox.is_valid()) { - rect_prev = obj_styleBox->get_region_rect(); - } + + rect_prev = _get_edited_object_region(); for (int i = 0; i < 8; i++) { Vector2 tuv = endpoints[i]; @@ -415,10 +327,109 @@ void TextureRegionEditor::_region_input(const Ref &p_input) { drag_index = i; } } + } - if (drag_index == -1) { - creating = true; - rect = Rect2(drag_from, Size2()); + // We didn't hit any handle, try other options. + if (drag_index < 0) { + if (node_ninepatch || res_stylebox.is_valid()) { + // For ninepatchable objects check if we are clicking on margin bars. + + edited_margin = -1; + float margins[4] = { 0 }; + if (node_ninepatch) { + margins[0] = node_ninepatch->get_patch_margin(SIDE_TOP); + margins[1] = node_ninepatch->get_patch_margin(SIDE_BOTTOM); + margins[2] = node_ninepatch->get_patch_margin(SIDE_LEFT); + margins[3] = node_ninepatch->get_patch_margin(SIDE_RIGHT); + } else if (res_stylebox.is_valid()) { + margins[0] = res_stylebox->get_texture_margin(SIDE_TOP); + margins[1] = res_stylebox->get_texture_margin(SIDE_BOTTOM); + margins[2] = res_stylebox->get_texture_margin(SIDE_LEFT); + margins[3] = res_stylebox->get_texture_margin(SIDE_RIGHT); + } + + Vector2 pos[4] = { + mtx.basis_xform(rect.position + Vector2(0, margins[0])) - draw_ofs * draw_zoom, + mtx.basis_xform(rect.position + rect.size - Vector2(0, margins[1])) - draw_ofs * draw_zoom, + mtx.basis_xform(rect.position + Vector2(margins[2], 0)) - draw_ofs * draw_zoom, + mtx.basis_xform(rect.position + rect.size - Vector2(margins[3], 0)) - draw_ofs * draw_zoom + }; + if (Math::abs(mb->get_position().y - pos[0].y) < 8) { + edited_margin = 0; + prev_margin = margins[0]; + } else if (Math::abs(mb->get_position().y - pos[1].y) < 8) { + edited_margin = 1; + prev_margin = margins[1]; + } else if (Math::abs(mb->get_position().x - pos[2].x) < 8) { + edited_margin = 2; + prev_margin = margins[2]; + } else if (Math::abs(mb->get_position().x - pos[3].x) < 8) { + edited_margin = 3; + prev_margin = margins[3]; + } + if (edited_margin >= 0) { + drag_from = mb->get_position(); + drag = true; + } + } + + if (edited_margin < 0 && snap_mode == SNAP_AUTOSLICE) { + // We didn't hit anything, but we're in the autoslice mode. Handle it. + + Vector2 point = mtx.affine_inverse().xform(mb->get_position()); + for (const Rect2 &E : autoslice_cache) { + if (E.has_point(point)) { + rect = E; + if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !(Input::get_singleton()->is_key_pressed(Key(Key::SHIFT | Key::ALT)))) { + Rect2 r; + if (node_sprite_2d) { + r = node_sprite_2d->get_region_rect(); + } else if (node_sprite_3d) { + r = node_sprite_3d->get_region_rect(); + } else if (node_ninepatch) { + r = node_ninepatch->get_region_rect(); + } else if (res_stylebox.is_valid()) { + r = res_stylebox->get_region_rect(); + } else if (res_atlas_texture.is_valid()) { + r = res_atlas_texture->get_region(); + } + rect.expand_to(r.position); + rect.expand_to(r.get_end()); + } + + undo_redo->create_action(TTR("Set Region Rect")); + if (node_sprite_2d) { + undo_redo->add_do_method(node_sprite_2d, "set_region_rect", rect); + undo_redo->add_undo_method(node_sprite_2d, "set_region_rect", node_sprite_2d->get_region_rect()); + } else if (node_sprite_3d) { + undo_redo->add_do_method(node_sprite_3d, "set_region_rect", rect); + undo_redo->add_undo_method(node_sprite_3d, "set_region_rect", node_sprite_3d->get_region_rect()); + } else if (node_ninepatch) { + undo_redo->add_do_method(node_ninepatch, "set_region_rect", rect); + undo_redo->add_undo_method(node_ninepatch, "set_region_rect", node_ninepatch->get_region_rect()); + } else if (res_stylebox.is_valid()) { + undo_redo->add_do_method(res_stylebox.ptr(), "set_region_rect", rect); + undo_redo->add_undo_method(res_stylebox.ptr(), "set_region_rect", res_stylebox->get_region_rect()); + } else if (res_atlas_texture.is_valid()) { + undo_redo->add_do_method(res_atlas_texture.ptr(), "set_region", rect); + undo_redo->add_undo_method(res_atlas_texture.ptr(), "set_region", res_atlas_texture->get_region()); + } + + undo_redo->add_do_method(this, "_update_rect"); + undo_redo->add_undo_method(this, "_update_rect"); + undo_redo->add_do_method(texture_overlay, "queue_redraw"); + undo_redo->add_undo_method(texture_overlay, "queue_redraw"); + undo_redo->commit_action(); + break; + } + } + } else if (edited_margin < 0) { + // We didn't hit anything and it's not autoslice, which means we try to create a new region. + + if (drag_index == -1) { + creating = true; + rect = Rect2(drag_from, Size2()); + } } } @@ -429,18 +440,15 @@ void TextureRegionEditor::_region_input(const Ref &p_input) { if (node_ninepatch) { undo_redo->add_do_method(node_ninepatch, "set_patch_margin", side[edited_margin], node_ninepatch->get_patch_margin(side[edited_margin])); undo_redo->add_undo_method(node_ninepatch, "set_patch_margin", side[edited_margin], prev_margin); - } else if (obj_styleBox.is_valid()) { - undo_redo->add_do_method(obj_styleBox.ptr(), "set_texture_margin", side[edited_margin], obj_styleBox->get_texture_margin(side[edited_margin])); - undo_redo->add_undo_method(obj_styleBox.ptr(), "set_texture_margin", side[edited_margin], prev_margin); - obj_styleBox->emit_changed(); + } else if (res_stylebox.is_valid()) { + undo_redo->add_do_method(res_stylebox.ptr(), "set_texture_margin", side[edited_margin], res_stylebox->get_texture_margin(side[edited_margin])); + undo_redo->add_undo_method(res_stylebox.ptr(), "set_texture_margin", side[edited_margin], prev_margin); + res_stylebox->emit_changed(); } edited_margin = -1; } else { undo_redo->create_action(TTR("Set Region Rect")); - if (atlas_tex.is_valid()) { - undo_redo->add_do_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region()); - undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", rect_prev); - } else if (node_sprite_2d) { + if (node_sprite_2d) { undo_redo->add_do_method(node_sprite_2d, "set_region_rect", node_sprite_2d->get_region_rect()); undo_redo->add_undo_method(node_sprite_2d, "set_region_rect", rect_prev); } else if (node_sprite_3d) { @@ -449,16 +457,19 @@ void TextureRegionEditor::_region_input(const Ref &p_input) { } else if (node_ninepatch) { undo_redo->add_do_method(node_ninepatch, "set_region_rect", node_ninepatch->get_region_rect()); undo_redo->add_undo_method(node_ninepatch, "set_region_rect", rect_prev); - } else if (obj_styleBox.is_valid()) { - undo_redo->add_do_method(obj_styleBox.ptr(), "set_region_rect", obj_styleBox->get_region_rect()); - undo_redo->add_undo_method(obj_styleBox.ptr(), "set_region_rect", rect_prev); + } else if (res_stylebox.is_valid()) { + undo_redo->add_do_method(res_stylebox.ptr(), "set_region_rect", res_stylebox->get_region_rect()); + undo_redo->add_undo_method(res_stylebox.ptr(), "set_region_rect", rect_prev); + } else if (res_atlas_texture.is_valid()) { + undo_redo->add_do_method(res_atlas_texture.ptr(), "set_region", res_atlas_texture->get_region()); + undo_redo->add_undo_method(res_atlas_texture.ptr(), "set_region", rect_prev); } drag_index = -1; } undo_redo->add_do_method(this, "_update_rect"); undo_redo->add_undo_method(this, "_update_rect"); - undo_redo->add_do_method(edit_draw, "queue_redraw"); - undo_redo->add_undo_method(edit_draw, "queue_redraw"); + undo_redo->add_do_method(texture_overlay, "queue_redraw"); + undo_redo->add_undo_method(texture_overlay, "queue_redraw"); undo_redo->commit_action(); drag = false; creating = false; @@ -472,14 +483,15 @@ void TextureRegionEditor::_region_input(const Ref &p_input) { if (node_ninepatch) { node_ninepatch->set_patch_margin(side[edited_margin], prev_margin); } - if (obj_styleBox.is_valid()) { - obj_styleBox->set_texture_margin(side[edited_margin], prev_margin); + if (res_stylebox.is_valid()) { + res_stylebox->set_texture_margin(side[edited_margin], prev_margin); } edited_margin = -1; } else { - apply_rect(rect_prev); + _apply_rect(rect_prev); rect = rect_prev; - edit_draw->queue_redraw(); + texture_preview->queue_redraw(); + texture_overlay->queue_redraw(); drag_index = -1; } } @@ -533,8 +545,8 @@ void TextureRegionEditor::_region_input(const Ref &p_input) { if (node_ninepatch) { node_ninepatch->set_patch_margin(side[edited_margin], new_margin); } - if (obj_styleBox.is_valid()) { - obj_styleBox->set_texture_margin(side[edited_margin], new_margin); + if (res_stylebox.is_valid()) { + res_stylebox->set_texture_margin(side[edited_margin], new_margin); } } else { Vector2 new_pos = mtx.affine_inverse().xform(mm->get_position()); @@ -547,8 +559,9 @@ void TextureRegionEditor::_region_input(const Ref &p_input) { if (creating) { rect = Rect2(drag_from, Size2()); rect.expand_to(new_pos); - apply_rect(rect); - edit_draw->queue_redraw(); + _apply_rect(rect); + texture_preview->queue_redraw(); + texture_overlay->queue_redraw(); return; } @@ -557,53 +570,54 @@ void TextureRegionEditor::_region_input(const Ref &p_input) { Vector2 p = rect_prev.get_end(); rect = Rect2(p, Size2()); rect.expand_to(new_pos); - apply_rect(rect); + _apply_rect(rect); } break; case 1: { Vector2 p = rect_prev.position + Vector2(0, rect_prev.size.y); rect = Rect2(p, Size2(rect_prev.size.x, 0)); rect.expand_to(new_pos); - apply_rect(rect); + _apply_rect(rect); } break; case 2: { Vector2 p = rect_prev.position + Vector2(0, rect_prev.size.y); rect = Rect2(p, Size2()); rect.expand_to(new_pos); - apply_rect(rect); + _apply_rect(rect); } break; case 3: { Vector2 p = rect_prev.position; rect = Rect2(p, Size2(0, rect_prev.size.y)); rect.expand_to(new_pos); - apply_rect(rect); + _apply_rect(rect); } break; case 4: { Vector2 p = rect_prev.position; rect = Rect2(p, Size2()); rect.expand_to(new_pos); - apply_rect(rect); + _apply_rect(rect); } break; case 5: { Vector2 p = rect_prev.position; rect = Rect2(p, Size2(rect_prev.size.x, 0)); rect.expand_to(new_pos); - apply_rect(rect); + _apply_rect(rect); } break; case 6: { Vector2 p = rect_prev.position + Vector2(rect_prev.size.x, 0); rect = Rect2(p, Size2()); rect.expand_to(new_pos); - apply_rect(rect); + _apply_rect(rect); } break; case 7: { Vector2 p = rect_prev.position + Vector2(rect_prev.size.x, 0); rect = Rect2(p, Size2(0, rect_prev.size.y)); rect.expand_to(new_pos); - apply_rect(rect); + _apply_rect(rect); } break; } } - edit_draw->queue_redraw(); + texture_preview->queue_redraw(); + texture_overlay->queue_redraw(); } } @@ -636,53 +650,50 @@ void TextureRegionEditor::_scroll_changed(float) { draw_ofs.x = hscroll->get_value(); draw_ofs.y = vscroll->get_value(); - edit_draw->queue_redraw(); + + texture_preview->queue_redraw(); + texture_overlay->queue_redraw(); } void TextureRegionEditor::_set_snap_mode(int p_mode) { - snap_mode = p_mode; - - if (snap_mode == SNAP_GRID) { - hb_grid->show(); - } else { - hb_grid->hide(); - } + snap_mode = (SnapMode)p_mode; + hb_grid->set_visible(snap_mode == SNAP_GRID); if (snap_mode == SNAP_AUTOSLICE && is_visible() && autoslice_is_dirty) { _update_autoslice(); } - edit_draw->queue_redraw(); + texture_overlay->queue_redraw(); } void TextureRegionEditor::_set_snap_off_x(float p_val) { snap_offset.x = p_val; - edit_draw->queue_redraw(); + texture_overlay->queue_redraw(); } void TextureRegionEditor::_set_snap_off_y(float p_val) { snap_offset.y = p_val; - edit_draw->queue_redraw(); + texture_overlay->queue_redraw(); } void TextureRegionEditor::_set_snap_step_x(float p_val) { snap_step.x = p_val; - edit_draw->queue_redraw(); + texture_overlay->queue_redraw(); } void TextureRegionEditor::_set_snap_step_y(float p_val) { snap_step.y = p_val; - edit_draw->queue_redraw(); + texture_overlay->queue_redraw(); } void TextureRegionEditor::_set_snap_sep_x(float p_val) { snap_separation.x = p_val; - edit_draw->queue_redraw(); + texture_overlay->queue_redraw(); } void TextureRegionEditor::_set_snap_sep_y(float p_val) { snap_separation.y = p_val; - edit_draw->queue_redraw(); + texture_overlay->queue_redraw(); } void TextureRegionEditor::_zoom_on_position(float p_zoom, Point2 p_position) { @@ -696,79 +707,52 @@ void TextureRegionEditor::_zoom_on_position(float p_zoom, Point2 p_position) { ofs = ofs / prev_zoom - ofs / draw_zoom; draw_ofs = (draw_ofs + ofs).round(); - edit_draw->queue_redraw(); + texture_preview->queue_redraw(); + texture_overlay->queue_redraw(); } void TextureRegionEditor::_zoom_in() { - _zoom_on_position(draw_zoom * 1.5, edit_draw->get_size() / 2.0); + _zoom_on_position(draw_zoom * 1.5, texture_overlay->get_size() / 2.0); } void TextureRegionEditor::_zoom_reset() { - _zoom_on_position(1.0, edit_draw->get_size() / 2.0); + _zoom_on_position(1.0, texture_overlay->get_size() / 2.0); } void TextureRegionEditor::_zoom_out() { - _zoom_on_position(draw_zoom / 1.5, edit_draw->get_size() / 2.0); + _zoom_on_position(draw_zoom / 1.5, texture_overlay->get_size() / 2.0); } -void TextureRegionEditor::apply_rect(const Rect2 &p_rect) { - if (atlas_tex.is_valid()) { - atlas_tex->set_region(p_rect); - } else if (node_sprite_2d) { +void TextureRegionEditor::_apply_rect(const Rect2 &p_rect) { + if (node_sprite_2d) { node_sprite_2d->set_region_rect(p_rect); } else if (node_sprite_3d) { node_sprite_3d->set_region_rect(p_rect); } else if (node_ninepatch) { node_ninepatch->set_region_rect(p_rect); - } else if (obj_styleBox.is_valid()) { - obj_styleBox->set_region_rect(p_rect); + } else if (res_stylebox.is_valid()) { + res_stylebox->set_region_rect(p_rect); + } else if (res_atlas_texture.is_valid()) { + res_atlas_texture->set_region(p_rect); } } void TextureRegionEditor::_update_rect() { - if (atlas_tex.is_valid()) { - rect = atlas_tex->get_region(); - } else if (node_sprite_2d) { - rect = node_sprite_2d->get_region_rect(); - } else if (node_sprite_3d) { - rect = node_sprite_3d->get_region_rect(); - } else if (node_ninepatch) { - rect = node_ninepatch->get_region_rect(); - if (rect == Rect2()) { - rect = Rect2(Vector2(), node_ninepatch->get_texture()->get_size()); - } - } else if (obj_styleBox.is_valid()) { - rect = obj_styleBox->get_region_rect(); - if (rect == Rect2()) { - rect = Rect2(Vector2(), obj_styleBox->get_texture()->get_size()); - } - } + rect = _get_edited_object_region(); } void TextureRegionEditor::_update_autoslice() { autoslice_is_dirty = false; autoslice_cache.clear(); - Ref texture = nullptr; - if (atlas_tex.is_valid()) { - texture = atlas_tex->get_atlas(); - } else if (node_sprite_2d) { - texture = node_sprite_2d->get_texture(); - } else if (node_sprite_3d) { - texture = node_sprite_3d->get_texture(); - } else if (node_ninepatch) { - texture = node_ninepatch->get_texture(); - } else if (obj_styleBox.is_valid()) { - texture = obj_styleBox->get_texture(); - } - - if (texture.is_null()) { + Ref object_texture = _get_edited_object_texture(); + if (object_texture.is_null()) { return; } - for (int y = 0; y < texture->get_height(); y++) { - for (int x = 0; x < texture->get_width(); x++) { - if (texture->is_pixel_opaque(x, y)) { + for (int y = 0; y < object_texture->get_height(); y++) { + for (int x = 0; x < object_texture->get_width(); x++) { + if (object_texture->is_pixel_opaque(x, y)) { bool found = false; for (Rect2 &E : autoslice_cache) { Rect2 grown = E.grow(1.5); @@ -813,34 +797,37 @@ void TextureRegionEditor::_update_autoslice() { } } } - cache_map[texture->get_rid()] = autoslice_cache; + cache_map[object_texture->get_rid()] = autoslice_cache; } void TextureRegionEditor::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_EXIT_TREE: { - get_tree()->disconnect("node_removed", callable_mp(this, &TextureRegionEditor::_node_removed)); + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning"))); } break; case NOTIFICATION_ENTER_TREE: { get_tree()->connect("node_removed", callable_mp(this, &TextureRegionEditor::_node_removed)); - [[fallthrough]]; - } - case NOTIFICATION_THEME_CHANGED: { - edit_draw->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + + panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning"))); + + hb_grid->set_visible(snap_mode == SNAP_GRID); + if (snap_mode == SNAP_AUTOSLICE && is_visible() && autoslice_is_dirty) { + _update_autoslice(); + } } break; - case NOTIFICATION_READY: { + case NOTIFICATION_EXIT_TREE: { + get_tree()->disconnect("node_removed", callable_mp(this, &TextureRegionEditor::_node_removed)); + } break; + + case NOTIFICATION_THEME_CHANGED: { + texture_preview->add_theme_style_override("panel", get_theme_stylebox(SNAME("TextureRegionPreviewBG"), SNAME("EditorStyles"))); + texture_overlay->add_theme_style_override("panel", get_theme_stylebox(SNAME("TextureRegionPreviewFG"), SNAME("EditorStyles"))); + zoom_out->set_icon(get_theme_icon(SNAME("ZoomLess"), SNAME("EditorIcons"))); zoom_reset->set_icon(get_theme_icon(SNAME("ZoomReset"), SNAME("EditorIcons"))); zoom_in->set_icon(get_theme_icon(SNAME("ZoomMore"), SNAME("EditorIcons"))); - - vscroll->set_anchors_and_offsets_preset(Control::PRESET_RIGHT_WIDE); - hscroll->set_anchors_and_offsets_preset(Control::PRESET_BOTTOM_WIDE); - [[fallthrough]]; - } - case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { - panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning"))); } break; case NOTIFICATION_VISIBILITY_CHANGED: { @@ -864,41 +851,19 @@ void TextureRegionEditor::_notification(int p_what) { } } -void TextureRegionEditor::_node_removed(Object *p_obj) { - if (p_obj == node_sprite_2d || p_obj == node_sprite_3d || p_obj == node_ninepatch || p_obj == obj_styleBox.ptr() || p_obj == atlas_tex.ptr()) { - node_sprite_2d = nullptr; - node_sprite_3d = nullptr; - node_ninepatch = nullptr; - obj_styleBox = Ref(nullptr); - atlas_tex = Ref(nullptr); +void TextureRegionEditor::_node_removed(Node *p_node) { + if (p_node == node_sprite_2d || p_node == node_sprite_3d || p_node == node_ninepatch) { + _clear_edited_object(); hide(); } } -void TextureRegionEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_edit_region"), &TextureRegionEditor::_edit_region); - ClassDB::bind_method(D_METHOD("_zoom_on_position"), &TextureRegionEditor::_zoom_on_position); - ClassDB::bind_method(D_METHOD("_update_rect"), &TextureRegionEditor::_update_rect); -} - -bool TextureRegionEditor::is_stylebox() { - return obj_styleBox.is_valid(); -} - -bool TextureRegionEditor::is_atlas_texture() { - return atlas_tex.is_valid(); -} - -bool TextureRegionEditor::is_ninepatch() { - return node_ninepatch != nullptr; -} - -Sprite2D *TextureRegionEditor::get_sprite_2d() { - return node_sprite_2d; -} - -Sprite3D *TextureRegionEditor::get_sprite_3d() { - return node_sprite_3d; +void TextureRegionEditor::_clear_edited_object() { + node_sprite_2d = nullptr; + node_sprite_3d = nullptr; + node_ninepatch = nullptr; + res_stylebox = Ref(); + res_atlas_texture = Ref(); } void TextureRegionEditor::edit(Object *p_obj) { @@ -911,18 +876,14 @@ void TextureRegionEditor::edit(Object *p_obj) { if (node_ninepatch) { node_ninepatch->disconnect("texture_changed", callable_mp(this, &TextureRegionEditor::_texture_changed)); } - if (obj_styleBox.is_valid()) { - obj_styleBox->disconnect_changed(callable_mp(this, &TextureRegionEditor::_texture_changed)); + if (res_stylebox.is_valid()) { + res_stylebox->disconnect_changed(callable_mp(this, &TextureRegionEditor::_texture_changed)); } - if (atlas_tex.is_valid()) { - atlas_tex->disconnect_changed(callable_mp(this, &TextureRegionEditor::_texture_changed)); + if (res_atlas_texture.is_valid()) { + res_atlas_texture->disconnect_changed(callable_mp(this, &TextureRegionEditor::_texture_changed)); } - node_sprite_2d = nullptr; - node_sprite_3d = nullptr; - node_ninepatch = nullptr; - obj_styleBox = Ref(nullptr); - atlas_tex = Ref(nullptr); + _clear_edited_object(); if (p_obj) { node_sprite_2d = Object::cast_to(p_obj); @@ -931,11 +892,11 @@ void TextureRegionEditor::edit(Object *p_obj) { bool is_resource = false; if (Object::cast_to(p_obj)) { - obj_styleBox = Ref(Object::cast_to(p_obj)); + res_stylebox = Ref(p_obj); is_resource = true; } if (Object::cast_to(p_obj)) { - atlas_tex = Ref(Object::cast_to(p_obj)); + res_atlas_texture = Ref(p_obj); is_resource = true; } @@ -947,11 +908,54 @@ void TextureRegionEditor::edit(Object *p_obj) { _edit_region(); } - edit_draw->queue_redraw(); + texture_preview->queue_redraw(); + texture_overlay->queue_redraw(); popup_centered_ratio(0.5); request_center = true; } +Ref TextureRegionEditor::_get_edited_object_texture() const { + if (node_sprite_2d) { + return node_sprite_2d->get_texture(); + } + if (node_sprite_3d) { + return node_sprite_3d->get_texture(); + } + if (node_ninepatch) { + return node_ninepatch->get_texture(); + } + if (res_stylebox.is_valid()) { + return res_stylebox->get_texture(); + } + if (res_atlas_texture.is_valid()) { + return res_atlas_texture->get_atlas(); + } + + return Ref(); +} + +Rect2 TextureRegionEditor::_get_edited_object_region() const { + Rect2 region; + + if (node_sprite_2d) { + region = node_sprite_2d->get_region_rect(); + } else if (node_sprite_3d) { + region = node_sprite_3d->get_region_rect(); + } else if (node_ninepatch) { + region = node_ninepatch->get_region_rect(); + } else if (res_stylebox.is_valid()) { + region = res_stylebox->get_region_rect(); + } else if (res_atlas_texture.is_valid()) { + region = res_atlas_texture->get_region(); + } + + if (region == Rect2()) { + region = Rect2(Vector2(), _get_edited_object_texture()->get_size()); + } + + return region; +} + void TextureRegionEditor::_texture_changed() { if (!is_visible()) { return; @@ -960,17 +964,20 @@ void TextureRegionEditor::_texture_changed() { } void TextureRegionEditor::_edit_region() { - CanvasItem::TextureFilter filter = CanvasItem::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS; + Ref object_texture = _get_edited_object_texture(); + if (object_texture.is_null()) { + _zoom_reset(); + hscroll->hide(); + vscroll->hide(); + texture_preview->queue_redraw(); + texture_overlay->queue_redraw(); + return; + } - Ref texture = nullptr; - if (atlas_tex.is_valid()) { - texture = atlas_tex->get_atlas(); - } else if (node_sprite_2d) { - texture = node_sprite_2d->get_texture(); + CanvasItem::TextureFilter filter = CanvasItem::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS; + if (node_sprite_2d) { filter = node_sprite_2d->get_texture_filter_in_tree(); } else if (node_sprite_3d) { - texture = node_sprite_3d->get_texture(); - StandardMaterial3D::TextureFilter filter_3d = node_sprite_3d->get_texture_filter(); switch (filter_3d) { @@ -998,10 +1005,7 @@ void TextureRegionEditor::_edit_region() { break; } } else if (node_ninepatch) { - texture = node_ninepatch->get_texture(); filter = node_ninepatch->get_texture_filter_in_tree(); - } else if (obj_styleBox.is_valid()) { - texture = obj_styleBox->get_texture(); } // occurs when get_texture_filter_in_tree reaches the scene root @@ -1032,20 +1036,11 @@ void TextureRegionEditor::_edit_region() { } } - if (texture.is_null()) { - preview_tex->set_diffuse_texture(nullptr); - _zoom_reset(); - hscroll->hide(); - vscroll->hide(); - edit_draw->queue_redraw(); - return; - } + texture_preview->set_texture_filter(filter); + texture_preview->set_texture_repeat(CanvasItem::TEXTURE_REPEAT_DISABLED); - preview_tex->set_texture_filter(filter); - preview_tex->set_diffuse_texture(texture); - - if (cache_map.has(texture->get_rid())) { - autoslice_cache = cache_map[texture->get_rid()]; + if (cache_map.has(object_texture->get_rid())) { + autoslice_cache = cache_map[object_texture->get_rid()]; autoslice_is_dirty = false; } else { if (is_visible() && snap_mode == SNAP_AUTOSLICE) { @@ -1056,7 +1051,8 @@ void TextureRegionEditor::_edit_region() { } _update_rect(); - edit_draw->queue_redraw(); + texture_preview->queue_redraw(); + texture_overlay->queue_redraw(); } Vector2 TextureRegionEditor::snap_point(Vector2 p_target) const { @@ -1068,25 +1064,24 @@ Vector2 TextureRegionEditor::snap_point(Vector2 p_target) const { return p_target; } -TextureRegionEditor::TextureRegionEditor() { - set_ok_button_text(TTR("Close")); - VBoxContainer *vb = memnew(VBoxContainer); - add_child(vb); - node_sprite_2d = nullptr; - node_sprite_3d = nullptr; - node_ninepatch = nullptr; - obj_styleBox = Ref(nullptr); - atlas_tex = Ref(nullptr); +void TextureRegionEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("_update_rect"), &TextureRegionEditor::_update_rect); +} - preview_tex = Ref(memnew(CanvasTexture)); +TextureRegionEditor::TextureRegionEditor() { + set_title(TTR("Region Editor")); + set_ok_button_text(TTR("Close")); // A power-of-two value works better as a default grid size. snap_step = EditorSettings::get_singleton()->get_project_metadata("texture_region_editor", "snap_step", Vector2(8, 8)); snap_separation = EditorSettings::get_singleton()->get_project_metadata("texture_region_editor", "snap_separation", Vector2()); - snap_mode = EditorSettings::get_singleton()->get_project_metadata("texture_region_editor", "snap_mode", SNAP_NONE); - edited_margin = -1; - drag_index = -1; - drag = false; + snap_mode = (SnapMode)(int)EditorSettings::get_singleton()->get_project_metadata("texture_region_editor", "snap_mode", SNAP_NONE); + + panner.instantiate(); + panner->set_callbacks(callable_mp(this, &TextureRegionEditor::_pan_callback), callable_mp(this, &TextureRegionEditor::_zoom_callback)); + + VBoxContainer *vb = memnew(VBoxContainer); + add_child(vb); HBoxContainer *hb_tools = memnew(HBoxContainer); vb->add_child(hb_tools); @@ -1169,22 +1164,21 @@ TextureRegionEditor::TextureRegionEditor() { hb_grid->hide(); - panner.instantiate(); - panner->set_callbacks(callable_mp(this, &TextureRegionEditor::_pan_callback), callable_mp(this, &TextureRegionEditor::_zoom_callback)); + texture_preview = memnew(PanelContainer); + vb->add_child(texture_preview); + texture_preview->set_v_size_flags(Control::SIZE_EXPAND_FILL); + texture_preview->set_clip_contents(true); + texture_preview->connect("draw", callable_mp(this, &TextureRegionEditor::_texture_preview_draw)); - edit_draw = memnew(Panel); - vb->add_child(edit_draw); - edit_draw->set_v_size_flags(Control::SIZE_EXPAND_FILL); - edit_draw->connect("draw", callable_mp(this, &TextureRegionEditor::_region_draw)); - edit_draw->connect("gui_input", callable_mp(this, &TextureRegionEditor::_region_input)); - edit_draw->connect("focus_exited", callable_mp(panner.ptr(), &ViewPanner::release_pan_key)); - edit_draw->set_focus_mode(Control::FOCUS_CLICK); - - draw_zoom = 1.0; - edit_draw->set_clip_contents(true); + texture_overlay = memnew(Panel); + texture_preview->add_child(texture_overlay); + texture_overlay->set_focus_mode(Control::FOCUS_CLICK); + texture_overlay->connect("draw", callable_mp(this, &TextureRegionEditor::_texture_overlay_draw)); + texture_overlay->connect("gui_input", callable_mp(this, &TextureRegionEditor::_texture_overlay_input)); + texture_overlay->connect("focus_exited", callable_mp(panner.ptr(), &ViewPanner::release_pan_key)); HBoxContainer *zoom_hb = memnew(HBoxContainer); - edit_draw->add_child(zoom_hb); + texture_overlay->add_child(zoom_hb); zoom_hb->set_begin(Point2(5, 5)); zoom_out = memnew(Button); @@ -1206,18 +1200,16 @@ TextureRegionEditor::TextureRegionEditor() { zoom_hb->add_child(zoom_in); vscroll = memnew(VScrollBar); + vscroll->set_anchors_and_offsets_preset(Control::PRESET_RIGHT_WIDE); vscroll->set_step(0.001); - edit_draw->add_child(vscroll); vscroll->connect("value_changed", callable_mp(this, &TextureRegionEditor::_scroll_changed)); + texture_overlay->add_child(vscroll); + hscroll = memnew(HScrollBar); + hscroll->set_anchors_and_offsets_preset(Control::PRESET_BOTTOM_WIDE); hscroll->set_step(0.001); - edit_draw->add_child(hscroll); hscroll->connect("value_changed", callable_mp(this, &TextureRegionEditor::_scroll_changed)); - - updating_scroll = false; - autoslice_is_dirty = true; - - set_title(TTR("Region Editor")); + texture_overlay->add_child(hscroll); } //////////////////////// diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h index 6b7a198246d..eeae9dc2058 100644 --- a/editor/plugins/texture_region_editor_plugin.h +++ b/editor/plugins/texture_region_editor_plugin.h @@ -42,6 +42,7 @@ class AtlasTexture; class OptionButton; +class PanelContainer; class ViewPanner; class TextureRegionEditor : public AcceptDialog { @@ -66,16 +67,18 @@ class TextureRegionEditor : public AcceptDialog { SpinBox *sb_off_x = nullptr; SpinBox *sb_sep_y = nullptr; SpinBox *sb_sep_x = nullptr; - Panel *edit_draw = nullptr; + + PanelContainer *texture_preview = nullptr; + Panel *texture_overlay = nullptr; VScrollBar *vscroll = nullptr; HScrollBar *hscroll = nullptr; Vector2 draw_ofs; - float draw_zoom = 0.0; + float draw_zoom = 1.0; bool updating_scroll = false; - int snap_mode = 0; + SnapMode snap_mode = SNAP_NONE; Vector2 snap_offset; Vector2 snap_step; Vector2 snap_separation; @@ -83,28 +86,28 @@ class TextureRegionEditor : public AcceptDialog { Sprite2D *node_sprite_2d = nullptr; Sprite3D *node_sprite_3d = nullptr; NinePatchRect *node_ninepatch = nullptr; - Ref obj_styleBox; - Ref atlas_tex; - - Ref preview_tex; + Ref res_stylebox; + Ref res_atlas_texture; Rect2 rect; Rect2 rect_prev; float prev_margin = 0.0f; - int edited_margin = 0; + int edited_margin = -1; HashMap> cache_map; List autoslice_cache; - bool autoslice_is_dirty = false; + bool autoslice_is_dirty = true; bool drag = false; bool creating = false; Vector2 drag_from; - int drag_index = 0; + int drag_index = -1; bool request_center = false; Ref panner; void _pan_callback(Vector2 p_scroll_vec, Ref p_event); void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref p_event); + void _scroll_changed(float); + Transform2D _get_offset_transform() const; void _set_snap_mode(int p_mode); void _set_snap_off_x(float p_val); @@ -113,35 +116,39 @@ class TextureRegionEditor : public AcceptDialog { void _set_snap_step_y(float p_val); void _set_snap_sep_x(float p_val); void _set_snap_sep_y(float p_val); + void _zoom_on_position(float p_zoom, Point2 p_position = Point2()); void _zoom_in(); void _zoom_reset(); void _zoom_out(); - void apply_rect(const Rect2 &p_rect); + + void _apply_rect(const Rect2 &p_rect); void _update_rect(); void _update_autoslice(); + Ref _get_edited_object_texture() const; + Rect2 _get_edited_object_region() const; void _texture_changed(); + void _node_removed(Node *p_node); + + void _edit_region(); + void _clear_edited_object(); + + void _draw_margin_line(Vector2 p_from, Vector2 p_to); protected: void _notification(int p_what); - void _node_removed(Object *p_obj); static void _bind_methods(); + void _texture_preview_draw(); + void _texture_overlay_draw(); + void _texture_overlay_input(const Ref &p_input); + Vector2 snap_point(Vector2 p_target) const; public: - void _edit_region(); - void _region_draw(); - void _region_input(const Ref &p_input); - void _scroll_changed(float); - bool is_stylebox(); - bool is_atlas_texture(); - bool is_ninepatch(); - Sprite2D *get_sprite_2d(); - Sprite3D *get_sprite_3d(); - void edit(Object *p_obj); + TextureRegionEditor(); }; diff --git a/scene/resources/atlas_texture.cpp b/scene/resources/atlas_texture.cpp index 24bf25f2db9..6aed68849b7 100644 --- a/scene/resources/atlas_texture.cpp +++ b/scene/resources/atlas_texture.cpp @@ -245,11 +245,16 @@ bool AtlasTexture::is_pixel_opaque(int p_x, int p_y) const { } Ref AtlasTexture::get_image() const { - if (!atlas.is_valid() || !atlas->get_image().is_valid()) { + if (atlas.is_null() || region.size.x <= 0 || region.size.y <= 0) { return Ref(); } - return atlas->get_image()->get_region(region); + Ref atlas_image = atlas->get_image(); + if (atlas_image.is_null()) { + return Ref(); + } + + return atlas_image->get_region(region); } AtlasTexture::AtlasTexture() {}