From f9e03459e8fc54aad8f6fd19d38facff10fa4929 Mon Sep 17 00:00:00 2001 From: Bitlytic Date: Thu, 16 Nov 2023 20:58:23 -0500 Subject: [PATCH] Add an option to center children around the new parent when reparenting --- doc/classes/EditorSettings.xml | 3 ++ editor/editor_settings.cpp | 1 + editor/scene_tree_dock.cpp | 55 ++++++++++++++++++++++++++++++++++ editor/scene_tree_dock.h | 1 + 4 files changed, 60 insertions(+) diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index b0949ec377b9..32123d59bfae 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -220,6 +220,9 @@ If [code]true[/code], the scene tree dock will automatically unfold nodes when a node that has folded parents is selected. + + If [code]true[/code], new node created when reparenting node(s) will be positioned at the average position of the selected node(s). + If [code]true[/code], the Create dialog (Create New Node/Create New Resource) will start with all its sections expanded. Otherwise, sections will be collapsed until the user starts searching (which will automatically expand sections as needed). diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 67006196eea9..b0977d7413d4 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -538,6 +538,7 @@ void EditorSettings::_load_defaults(Ref p_extra_config) { // SceneTree _initial_set("docks/scene_tree/start_create_dialog_fully_expanded", false); _initial_set("docks/scene_tree/auto_expand_to_selected", true); + _initial_set("docks/scene_tree/center_node_on_reparent", false); // FileSystem EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "docks/filesystem/thumbnail_size", 64, "32,128,16") diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 413281ad081d..ea3d00a437cc 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1059,6 +1059,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { case TOOL_AUTO_EXPAND: { scene_tree->set_auto_expand_selected(!EDITOR_GET("docks/scene_tree/auto_expand_to_selected"), true); } break; + case TOOL_CENTER_PARENT: { + EditorSettings::get_singleton()->set("docks/scene_tree/center_node_on_reparent", !EDITOR_GET("docks/scene_tree/center_node_on_reparent")); + } break; case TOOL_SCENE_EDITABLE_CHILDREN: { if (!profile_allow_editing) { break; @@ -2687,6 +2690,9 @@ void SceneTreeDock::_create() { int smaller_path_to_top = first->get_path_to(scene_root).get_name_count(); Node *top_node = first; + bool center_parent = EDITOR_GET("docks/scene_tree/center_node_on_reparent"); + Vector top_level_nodes; + for (List::Element *E = selection.front()->next(); E; E = E->next()) { Node *n = E->get(); ERR_FAIL_NULL(n); @@ -2698,10 +2704,17 @@ void SceneTreeDock::_create() { top_node = n; smaller_path_to_top = path_length; only_one_top_node = true; + if (center_parent) { + top_level_nodes.clear(); + top_level_nodes.append(n); + } } else if (smaller_path_to_top == path_length) { if (only_one_top_node && top_node->get_parent() != n->get_parent()) { only_one_top_node = false; } + if (center_parent) { + top_level_nodes.append(n); + } } } } @@ -2722,6 +2735,44 @@ void SceneTreeDock::_create() { // This works because editor_selection was cleared and populated with last created node in _do_create() Node *last_created = editor_selection->get_selected_node_list().front()->get(); + + if (center_parent) { + // Find parent type and only average positions of relevant nodes. + Node3D *parent_node_3d = Object::cast_to(last_created); + if (parent_node_3d) { + Vector3 position; + uint32_t node_count = 0; + for (const Node *node : nodes) { + const Node3D *node_3d = Object::cast_to(node); + if (node_3d) { + position += node_3d->get_global_position(); + node_count++; + } + } + + if (node_count > 0) { + parent_node_3d->set_global_position(position / node_count); + } + } + + Node2D *parent_node_2d = Object::cast_to(last_created); + if (parent_node_2d) { + Vector2 position; + uint32_t node_count = 0; + for (const Node *node : nodes) { + const Node2D *node_2d = Object::cast_to(node); + if (node_2d) { + position += node_2d->get_global_position(); + node_count++; + } + } + + if (node_count > 0) { + parent_node_2d->set_global_position(position / (real_t)node_count); + } + } + } + _do_reparent(last_created, -1, nodes, true); } @@ -3446,6 +3497,10 @@ void SceneTreeDock::_update_tree_menu() { tree_menu->add_check_item(TTR("Auto Expand to Selected"), TOOL_AUTO_EXPAND); tree_menu->set_item_checked(tree_menu->get_item_index(TOOL_AUTO_EXPAND), EDITOR_GET("docks/scene_tree/auto_expand_to_selected")); + tree_menu->add_check_item(TTR("Center Node on Reparent"), TOOL_CENTER_PARENT); + tree_menu->set_item_checked(tree_menu->get_item_index(TOOL_CENTER_PARENT), EDITOR_GET("docks/scene_tree/center_node_on_reparent")); + tree_menu->set_item_tooltip(tree_menu->get_item_index(TOOL_CENTER_PARENT), TTR("If enabled, Reparent to New Node will create the new node in the center of the selected nodes, if possible.")); + PopupMenu *resource_list = memnew(PopupMenu); resource_list->set_name("AllResources"); resource_list->connect("about_to_popup", callable_mp(this, &SceneTreeDock::_list_all_subresources).bind(resource_list)); diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index 8b95cc02dd8f..a6d2eab2e202 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -94,6 +94,7 @@ class SceneTreeDock : public VBoxContainer { TOOL_CREATE_3D_SCENE, TOOL_CREATE_USER_INTERFACE, TOOL_CREATE_FAVORITE, + TOOL_CENTER_PARENT, };