Skip to content

Commit

Permalink
Add viewport override to 2D editor
Browse files Browse the repository at this point in the history
  • Loading branch information
KoBeWi committed Dec 27, 2024
1 parent 99a8ab7 commit 9ef9844
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 23 deletions.
175 changes: 152 additions & 23 deletions editor/plugins/canvas_item_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
#include "scene/gui/separator.h"
#include "scene/gui/split_container.h"
#include "scene/gui/subviewport_container.h"
#include "scene/gui/texture_rect.h"
#include "scene/gui/view_panner.h"
#include "scene/main/canvas_layer.h"
#include "scene/main/window.h"
Expand Down Expand Up @@ -606,6 +607,21 @@ Rect2 CanvasItemEditor::_get_encompassing_rect(const Node *p_node) {
return rect;
}

Vector2 CanvasItemEditor::_get_screen_size() const {
if (!_is_viewport_overridden()) {
return Vector2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
}
SubViewport *svp = Object::cast_to<SubViewport>(current_viewport);
if (svp) {
return svp->get_size();
}
Window *w = Object::cast_to<Window>(current_viewport);
if (w) {
return w->get_size();
}
return Vector2();
}

void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
if (!p_node) {
return;
Expand All @@ -618,7 +634,7 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no
if (CanvasLayer *cl = Object::cast_to<CanvasLayer>(p_node)) {
xform = cl->get_transform();
} else if (Viewport *vp = Object::cast_to<Viewport>(p_node)) {
if (!vp->is_visible_subviewport()) {
if (!_is_usable_viewport(vp)) {
return;
}
xform = vp->get_popup_base_transform();
Expand All @@ -639,6 +655,10 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no
}
}

if (_is_viewport_overridden() && p_node->get_viewport() != current_viewport) {
return;
}

if (ci && ci->is_visible_in_tree()) {
if (!ci->is_set_as_top_level()) {
xform *= p_parent_xform;
Expand Down Expand Up @@ -721,7 +741,7 @@ void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_n
if (CanvasLayer *cl = Object::cast_to<CanvasLayer>(p_node)) {
xform = cl->get_transform();
} else if (Viewport *vp = Object::cast_to<Viewport>(p_node)) {
if (!vp->is_visible_subviewport()) {
if (!_is_usable_viewport(vp)) {
return;
}
xform = vp->get_popup_base_transform();
Expand Down Expand Up @@ -804,7 +824,7 @@ List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool p_retrieve_lo
if (ci) {
if (ci->is_visible_in_tree() && (p_retrieve_locked || !_is_node_locked(ci))) {
Viewport *vp = ci->get_viewport();
if (vp && !vp->is_visible_subviewport()) {
if (!_is_usable_viewport(vp)) {
continue;
}
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci);
Expand Down Expand Up @@ -1066,6 +1086,47 @@ void CanvasItemEditor::_on_grid_menu_id_pressed(int p_id) {
viewport->queue_redraw();
}

void CanvasItemEditor::_set_viewport_override(Viewport *p_viewport) {
if (p_viewport && p_viewport == current_viewport) {
return;
}

const Callable update_size = callable_mp(this, &CanvasItemEditor::_update_viewport_size);
const Callable redraw = callable_mp((CanvasItem *)viewport, &CanvasItem::queue_redraw);

if (current_viewport && _is_viewport_overridden()) {
current_viewport->disconnect("size_changed", update_size);
current_viewport->disconnect("size_changed", redraw);
}

if (p_viewport) {
p_viewport->connect("size_changed", update_size);
p_viewport->connect("size_changed", redraw);
scene_view_display->set_global_canvas_transform(EditorNode::get_singleton()->get_scene_root()->get_global_canvas_transform());
} else {
p_viewport = EditorNode::get_singleton()->get_scene_root();
p_viewport->set_global_canvas_transform(scene_view_display->get_global_canvas_transform());
scene_view_display->set_global_canvas_transform(Transform2D());
}

current_viewport = p_viewport;
scene_view->set_texture(p_viewport->get_texture());
_update_viewport_size();
viewport->queue_redraw();
}

void CanvasItemEditor::_update_viewport_size() {
EditorNode::get_singleton()->get_scene_root()->set_size(scene_tree->get_size());
}

bool CanvasItemEditor::_is_usable_viewport(const Viewport *p_viewport) const {
return p_viewport && p_viewport == current_viewport && p_viewport->is_visible_subviewport();
}

bool CanvasItemEditor::_is_viewport_overridden() const {
return current_viewport != EditorNode::get_singleton()->get_scene_root();
}

void CanvasItemEditor::_switch_theme_preview(int p_mode) {
view_menu->get_popup()->hide();

Expand Down Expand Up @@ -3793,13 +3854,13 @@ void CanvasItemEditor::_draw_axis() {

Color area_axis_color = EDITOR_GET("editors/2d/viewport_border_color");

Size2 screen_size = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
Size2 viewport_size = _get_screen_size();

Vector2 screen_endpoints[4] = {
transform.xform(Vector2(0, 0)),
transform.xform(Vector2(screen_size.width, 0)),
transform.xform(Vector2(screen_size.width, screen_size.height)),
transform.xform(Vector2(0, screen_size.height))
transform.xform(Vector2(viewport_size.width, 0)),
transform.xform(Vector2(viewport_size.width, viewport_size.height)),
transform.xform(Vector2(0, viewport_size.height))
};

for (int i = 0; i < 4; i++) {
Expand Down Expand Up @@ -3829,7 +3890,7 @@ void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Trans
parent_xform = Transform2D();
canvas_xform = cl->get_transform();
} else if (Viewport *vp = Object::cast_to<Viewport>(p_node)) {
if (!vp->is_visible_subviewport()) {
if (_is_usable_viewport(vp)) {
return;
}
parent_xform = Transform2D();
Expand Down Expand Up @@ -3964,7 +4025,7 @@ void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p
parent_xform = Transform2D();
canvas_xform = cl->get_transform();
} else if (Viewport *vp = Object::cast_to<Viewport>(p_node)) {
if (!vp->is_visible_subviewport()) {
if (!_is_usable_viewport(vp)) {
return;
}
parent_xform = Transform2D();
Expand Down Expand Up @@ -3998,7 +4059,11 @@ void CanvasItemEditor::_draw_viewport() {
transform = Transform2D();
transform.scale_basis(Size2(zoom, zoom));
transform.columns[2] = -view_offset * zoom;
EditorNode::get_singleton()->get_scene_root()->set_global_canvas_transform(transform);
if (_is_viewport_overridden()) {
scene_view_display->set_global_canvas_transform(transform);
} else {
current_viewport->set_global_canvas_transform(transform);
}

_draw_grid();
_draw_ruler_tool();
Expand Down Expand Up @@ -4054,6 +4119,7 @@ void CanvasItemEditor::_update_editor_settings() {
grid_snap_button->set_button_icon(get_editor_theme_icon(SNAME("SnapGrid")));
snap_config_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
skeleton_menu->set_button_icon(get_editor_theme_icon(SNAME("Bone")));
override_viewport_button->set_button_icon(get_editor_theme_icon(SNAME("Viewport")));
pan_button->set_button_icon(get_editor_theme_icon(SNAME("ToolPan")));
ruler_button->set_button_icon(get_editor_theme_icon(SNAME("Ruler")));
pivot_button->set_button_icon(get_editor_theme_icon(SNAME("EditPivot")));
Expand Down Expand Up @@ -4084,7 +4150,7 @@ void CanvasItemEditor::_update_editor_settings() {
}

void CanvasItemEditor::_project_settings_changed() {
EditorNode::get_singleton()->get_scene_root()->set_snap_controls_to_pixels(GLOBAL_GET("gui/common/snap_controls_to_pixels"));
current_viewport->set_snap_controls_to_pixels(GLOBAL_GET("gui/common/snap_controls_to_pixels"));
}

void CanvasItemEditor::_notification(int p_what) {
Expand Down Expand Up @@ -4224,6 +4290,10 @@ void CanvasItemEditor::edit(CanvasItem *p_canvas_item) {
}
}

void CanvasItemEditor::edit_viewport(Viewport *p_viewport) {
_update_override_viewport_button(p_viewport);
}

void CanvasItemEditor::_update_scrollbars() {
updating_scroll = true;

Expand All @@ -4236,7 +4306,7 @@ void CanvasItemEditor::_update_scrollbars() {
Size2 vmin = v_scroll->get_minimum_size();

// Get the visible frame.
Size2 screen_rect = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
Size2 screen_rect = _get_screen_size();
Rect2 local_rect = Rect2(Point2(), viewport->get_size() - Size2(vmin.width, hmin.height));

// Calculate scrollable area.
Expand Down Expand Up @@ -4347,6 +4417,17 @@ void CanvasItemEditor::_button_toggle_grid_snap(bool p_status) {
viewport->queue_redraw();
}

void CanvasItemEditor::_button_override_viewport(bool p_pressed) {
if (p_pressed) {
Viewport *vp = Object::cast_to<Viewport>(override_viewport_button->get_meta("viewport"));
_set_viewport_override(vp);
override_viewport_button->set_tooltip_text(TTR("Editor Viewport Override\nEditor viewport is overridden. Press to disable override."));
} else {
_set_viewport_override(nullptr);
override_viewport_button->set_tooltip_text(TTR("Editor Viewport Override\nMakes editor use selected SubViewport instead of the main viewport, allowing to edit nodes inside it."));
}
}

void CanvasItemEditor::_button_tool_select(int p_index) {
Button *tb[TOOL_MAX] = { select_button, list_select_button, move_button, scale_button, rotate_button, pivot_button, pan_button, ruler_button };
for (int i = 0; i < TOOL_MAX; i++) {
Expand Down Expand Up @@ -4384,7 +4465,7 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation,
continue;
}

if (ci->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
if (ci->get_viewport() != current_viewport) {
continue;
}

Expand Down Expand Up @@ -4461,6 +4542,32 @@ void CanvasItemEditor::_prepare_view_menu() {
popup->set_item_disabled(popup->get_item_index(CLEAR_GUIDES), !has_guides);
}

void CanvasItemEditor::_update_override_viewport_button(Viewport *p_viewport) {
if (p_viewport) {
override_viewport_button->set_disabled(false);
if (p_viewport == current_viewport) {
override_viewport_button->set_pressed_no_signal(true);
override_viewport_button->set_tooltip_text(TTR("Editor Viewport Override\nEditor viewport is overridden. Press to disable override."));
} else {
override_viewport_button->set_pressed_no_signal(false);
override_viewport_button->set_meta(SNAME("viewport"), p_viewport);
override_viewport_button->set_tooltip_text(TTR("Editor Viewport Override\nMakes editor use selected SubViewport instead of the main viewport, allowing to edit nodes inside it."));
}

} else {
if (_is_viewport_overridden()) {
override_viewport_button->set_disabled(false);
override_viewport_button->set_pressed_no_signal(true);
override_viewport_button->set_tooltip_text(TTR("Editor Viewport Override\nEditor viewport is overridden. Press to disable override."));
} else {
override_viewport_button->set_disabled(true);
override_viewport_button->set_pressed_no_signal(false);
override_viewport_button->set_tooltip_text(TTR("Editor Viewport Override\nNo SubViewport node selected. Select one to allow overriding editor viewport."));
}
override_viewport_button->set_meta(SNAME("viewport"), Variant());
}
}

void CanvasItemEditor::_popup_callback(int p_op) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
last_option = MenuOption(p_op);
Expand Down Expand Up @@ -4598,7 +4705,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
if (!ci || !ci->is_inside_tree()) {
continue;
}
if (ci->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
if (ci->get_viewport() != current_viewport) {
continue;
}

Expand All @@ -4620,7 +4727,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
if (!ci || !ci->is_inside_tree()) {
continue;
}
if (ci->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
if (ci->get_viewport() != current_viewport) {
continue;
}

Expand All @@ -4642,7 +4749,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
if (!ci || !ci->is_inside_tree()) {
continue;
}
if (ci->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
if (ci->get_viewport() != current_viewport) {
continue;
}

Expand All @@ -4664,7 +4771,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
if (!ci || !ci->is_inside_tree()) {
continue;
}
if (ci->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
if (ci->get_viewport() != current_viewport) {
continue;
}

Expand Down Expand Up @@ -4705,7 +4812,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
continue;
}

if (ci->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
if (ci->get_viewport() != current_viewport) {
continue;
}

Expand Down Expand Up @@ -4751,7 +4858,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
continue;
}

if (ci->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
if (ci->get_viewport() != current_viewport) {
continue;
}

Expand Down Expand Up @@ -5170,6 +5277,8 @@ void CanvasItemEditor::clear() {
snap_rotation_step = EditorSettings::get_singleton()->get_project_metadata("2d_editor", "snap_rotation_step", Math::deg_to_rad(15.0));
snap_rotation_offset = EditorSettings::get_singleton()->get_project_metadata("2d_editor", "snap_rotation_offset", 0.0);
snap_scale_step = EditorSettings::get_singleton()->get_project_metadata("2d_editor", "snap_scale_step", 0.1);

edit_viewport(nullptr);
}

void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) {
Expand Down Expand Up @@ -5249,7 +5358,7 @@ void CanvasItemEditor::focus_selection() {
}

void CanvasItemEditor::center_at(const Point2 &p_pos) {
Vector2 offset = viewport->get_size() / 2 - EditorNode::get_singleton()->get_scene_root()->get_global_canvas_transform().xform(p_pos);
Vector2 offset = viewport->get_size() / 2 - current_viewport->get_global_canvas_transform().xform(p_pos);
view_offset -= (offset / zoom).round();
update_viewport();
}
Expand Down Expand Up @@ -5303,11 +5412,19 @@ CanvasItemEditor::CanvasItemEditor() {
viewport_scrollable->set_h_size_flags(Control::SIZE_EXPAND_FILL);
viewport_scrollable->connect(SceneStringName(draw), callable_mp(this, &CanvasItemEditor::_update_scrollbars));

SubViewportContainer *scene_tree = memnew(SubViewportContainer);
scene_tree = memnew(SubViewportContainer);
viewport_scrollable->add_child(scene_tree);
scene_tree->set_stretch(true);
scene_tree->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
scene_tree->add_child(EditorNode::get_singleton()->get_scene_root());
scene_tree->connect("item_rect_changed", callable_mp(this, &CanvasItemEditor::_update_viewport_size));

scene_view_display = memnew(SubViewport);
scene_tree->add_child(scene_view_display);

scene_view = memnew(TextureRect);
scene_view_display->add_child(scene_view);
scene_view->set_clip_contents(true);
scene_view->add_child(EditorNode::get_singleton()->get_scene_root());

controls_vb = memnew(VBoxContainer);
controls_vb->set_begin(Point2(5, 5));
Expand Down Expand Up @@ -5373,6 +5490,7 @@ CanvasItemEditor::CanvasItemEditor() {
viewport->connect(SceneStringName(draw), callable_mp(this, &CanvasItemEditor::_draw_viewport));
viewport->connect(SceneStringName(gui_input), callable_mp(this, &CanvasItemEditor::_gui_input_viewport));
viewport->connect(SceneStringName(focus_exited), callable_mp(panner.ptr(), &ViewPanner::release_pan_key));
_set_viewport_override(nullptr);

h_scroll = memnew(HScrollBar);
viewport->add_child(h_scroll);
Expand Down Expand Up @@ -5564,6 +5682,16 @@ CanvasItemEditor::CanvasItemEditor() {

main_menu_hbox->add_child(memnew(VSeparator));

override_viewport_button = memnew(Button);
override_viewport_button->set_theme_type_variation("FlatButton");
override_viewport_button->set_toggle_mode(true);
override_viewport_button->set_disabled(true);
main_menu_hbox->add_child(override_viewport_button);
override_viewport_button->connect(SceneStringName(toggled), callable_mp(this, &CanvasItemEditor::_button_override_viewport));
_update_override_viewport_button(nullptr);

main_menu_hbox->add_child(memnew(VSeparator));

view_menu = memnew(MenuButton);
view_menu->set_flat(false);
view_menu->set_theme_type_variation("FlatMenuButton");
Expand Down Expand Up @@ -5736,10 +5864,11 @@ CanvasItemEditor *CanvasItemEditor::singleton = nullptr;

void CanvasItemEditorPlugin::edit(Object *p_object) {
canvas_item_editor->edit(Object::cast_to<CanvasItem>(p_object));
canvas_item_editor->edit_viewport(Object::cast_to<Viewport>(p_object));
}

bool CanvasItemEditorPlugin::handles(Object *p_object) const {
return p_object->is_class("CanvasItem");
return Object::cast_to<CanvasItem>(p_object) || Object::cast_to<SubViewport>(p_object) || Object::cast_to<Window>(p_object);
}

void CanvasItemEditorPlugin::make_visible(bool p_visible) {
Expand Down
Loading

0 comments on commit 9ef9844

Please sign in to comment.