Browse Source

Merge pull request #21833 from StraToN/wrap-in-new-node

Adds contextual item in scene tree dock to wrap selection in a new node
Rémi Verschelde 6 years ago
parent
commit
e12f3a9bfd
3 changed files with 184 additions and 46 deletions
  1. 83 0
      editor/icons/icon_reparent_to_new_node.svg
  2. 99 46
      editor/scene_tree_dock.cpp
  3. 2 0
      editor/scene_tree_dock.h

+ 83 - 0
editor/icons/icon_reparent_to_new_node.svg

@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="16"
+   height="16"
+   version="1.1"
+   viewBox="0 0 16 16"
+   id="svg8"
+   sodipodi:docname="icon_reparent_to_new_node.svg"
+   inkscape:version="0.92.1 r15371">
+  <metadata
+     id="metadata14">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs12" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1023"
+     id="namedview10"
+     showgrid="false"
+     inkscape:zoom="29.5"
+     inkscape:cx="2.2588225"
+     inkscape:cy="3.6882199"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="g6" />
+  <g
+     transform="translate(0 -1036.4)"
+     id="g6">
+    <path
+       transform="translate(0,1036.4)"
+       d="m 1.4915254,13 c 0,1.104569 0.8954305,2 2,2 0.7139771,-5.54e-4 1.3735116,-0.381677 1.7305,-1 H 11.2715 c 0.356631,0.617705 1.015238,0.998733 1.7285,1 1.104569,0 2,-0.895431 2,-2 0,-1.104569 -0.895431,-2 -2,-2 -0.713977,5.54e-4 -1.373512,0.381677 -1.7305,1 H 5.2200254 c -0.1747809,-0.30301 -0.8483719,-1 -1.7285,-1 -0.9027301,0 -2,0.891221 -2,2 z"
+       id="path2"
+       inkscape:connector-curvature="0"
+       style="fill:#e0e0e0"
+       sodipodi:nodetypes="cccccsccccc" />
+    <path
+       d="m 10.421845,1038.2814 -2.7947264,2.096 2.7947264,2.0961 v -1.3974 c 2.716918,0 2.180792,1.4469 2.180792,3.9265 V 1046.4 H 14 v -1.3974 c 0,-3.863 0.13086,-5.3239 -3.578155,-5.3239 z"
+       id="path4"
+       inkscape:connector-curvature="0"
+       style="fill:#84ffb1;stroke-width:0.69868171"
+       sodipodi:nodetypes="cccccccccc" />
+    <g
+       transform="translate(-8.5,-8)"
+       id="g6-7">
+      <path
+         style="fill:#84ffb1"
+         inkscape:connector-curvature="0"
+         transform="translate(0,1036.4)"
+         d="m 11,9 v 2 H 9 v 2 h 2 v 2 h 2 v -2 h 2 V 11 H 13 V 9 Z"
+         id="path4-5" />
+    </g>
+    <path
+       d="m 4.5,1047.7968 v -3.1171 H 2.4999995 v 3.1171 z"
+       id="path2-3"
+       inkscape:connector-curvature="0"
+       style="fill:#e0e0e0;stroke-width:0.7178387"
+       sodipodi:nodetypes="ccccc" />
+  </g>
+</svg>

+ 99 - 46
editor/scene_tree_dock.cpp

@@ -338,7 +338,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
 				tree->edit_selected();
 				tree->edit_selected();
 			}
 			}
 		} break;
 		} break;
-		case TOOL_NEW: {
+		case TOOL_NEW:
+		case TOOL_REPARENT_TO_NEW_NODE: {
 
 
 			if (!profile_allow_editing) {
 			if (!profile_allow_editing) {
 				break;
 				break;
@@ -1909,6 +1910,54 @@ Node *SceneTreeDock::_get_selection_group_tail(Node *p_node, List<Node *> p_list
 	return tail;
 	return tail;
 }
 }
 
 
+void SceneTreeDock::_do_create(Node *p_parent) {
+	Object *c = create_dialog->instance_selected();
+
+	ERR_FAIL_COND(!c);
+	Node *child = Object::cast_to<Node>(c);
+	ERR_FAIL_COND(!child);
+
+	editor_data->get_undo_redo().create_action(TTR("Create Node"));
+
+	if (edited_scene) {
+
+		editor_data->get_undo_redo().add_do_method(p_parent, "add_child", child);
+		editor_data->get_undo_redo().add_do_method(child, "set_owner", edited_scene);
+		editor_data->get_undo_redo().add_do_method(editor_selection, "clear");
+		editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", child);
+		editor_data->get_undo_redo().add_do_reference(child);
+		editor_data->get_undo_redo().add_undo_method(p_parent, "remove_child", child);
+
+		String new_name = p_parent->validate_child_name(child);
+		ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
+		editor_data->get_undo_redo().add_do_method(sed, "live_debug_create_node", edited_scene->get_path_to(p_parent), child->get_class(), new_name);
+		editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).plus_file(new_name)));
+
+	} else {
+
+		editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", child);
+		editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree");
+		editor_data->get_undo_redo().add_do_reference(child);
+		editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)NULL);
+	}
+
+	editor_data->get_undo_redo().commit_action();
+	editor->push_item(c);
+	editor_selection->clear();
+	editor_selection->add_node(child);
+	if (Object::cast_to<Control>(c)) {
+		//make editor more comfortable, so some controls don't appear super shrunk
+		Control *ct = Object::cast_to<Control>(c);
+
+		Size2 ms = ct->get_minimum_size();
+		if (ms.width < 4)
+			ms.width = 40;
+		if (ms.height < 4)
+			ms.height = 40;
+		ct->set_size(ms);
+	}
+}
+
 void SceneTreeDock::_create() {
 void SceneTreeDock::_create() {
 
 
 	if (current_option == TOOL_NEW) {
 	if (current_option == TOOL_NEW) {
@@ -1927,51 +1976,7 @@ void SceneTreeDock::_create() {
 			ERR_FAIL_COND(!parent);
 			ERR_FAIL_COND(!parent);
 		}
 		}
 
 
-		Object *c = create_dialog->instance_selected();
-
-		ERR_FAIL_COND(!c);
-		Node *child = Object::cast_to<Node>(c);
-		ERR_FAIL_COND(!child);
-
-		editor_data->get_undo_redo().create_action(TTR("Create Node"));
-
-		if (edited_scene) {
-
-			editor_data->get_undo_redo().add_do_method(parent, "add_child", child);
-			editor_data->get_undo_redo().add_do_method(child, "set_owner", edited_scene);
-			editor_data->get_undo_redo().add_do_method(editor_selection, "clear");
-			editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", child);
-			editor_data->get_undo_redo().add_do_reference(child);
-			editor_data->get_undo_redo().add_undo_method(parent, "remove_child", child);
-
-			String new_name = parent->validate_child_name(child);
-			ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
-			editor_data->get_undo_redo().add_do_method(sed, "live_debug_create_node", edited_scene->get_path_to(parent), child->get_class(), new_name);
-			editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(new_name)));
-
-		} else {
-
-			editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", child);
-			editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree");
-			editor_data->get_undo_redo().add_do_reference(child);
-			editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)NULL);
-		}
-
-		editor_data->get_undo_redo().commit_action();
-		editor->push_item(c);
-		editor_selection->clear();
-		editor_selection->add_node(child);
-		if (Object::cast_to<Control>(c)) {
-			//make editor more comfortable, so some controls don't appear super shrunk
-			Control *ct = Object::cast_to<Control>(c);
-
-			Size2 ms = ct->get_minimum_size();
-			if (ms.width < 4)
-				ms.width = 40;
-			if (ms.height < 4)
-				ms.height = 40;
-			ct->set_size(ms);
-		}
+		_do_create(parent);
 
 
 	} else if (current_option == TOOL_REPLACE) {
 	} else if (current_option == TOOL_REPLACE) {
 		List<Node *> selection = editor_selection->get_selected_node_list();
 		List<Node *> selection = editor_selection->get_selected_node_list();
@@ -1988,6 +1993,52 @@ void SceneTreeDock::_create() {
 
 
 			replace_node(n, newnode);
 			replace_node(n, newnode);
 		}
 		}
+	} else if (current_option == TOOL_REPARENT_TO_NEW_NODE) {
+		List<Node *> selection = editor_selection->get_selected_node_list();
+		ERR_FAIL_COND(selection.size() <= 0);
+
+		// Find top level node in selection
+		bool only_one_top_node = true;
+
+		Node *first = selection.front()->get();
+		ERR_FAIL_COND(!first);
+		int smaller_path_to_top = first->get_path_to(scene_root).get_name_count();
+		Node *top_node = first;
+
+		for (List<Node *>::Element *E = selection.front()->next(); E; E = E->next()) {
+			Node *n = E->get();
+			ERR_FAIL_COND(!n);
+
+			int path_length = n->get_path_to(scene_root).get_name_count();
+
+			if (top_node != n) {
+				if (smaller_path_to_top > path_length) {
+					top_node = n;
+					smaller_path_to_top = path_length;
+					only_one_top_node = true;
+				} 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;
+				}
+			}
+		}
+
+		Node *parent = NULL;
+		if (only_one_top_node)
+			parent = top_node->get_parent();
+		else
+			parent = top_node->get_parent()->get_parent();
+
+		_do_create(parent);
+
+		Vector<Node *> nodes;
+		for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+			nodes.push_back(E->get());
+		}
+
+		// 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();
+		_do_reparent(last_created, -1, nodes, true);
 	}
 	}
 
 
 	scene_tree->get_scene_tree()->call_deferred("grab_focus");
 	scene_tree->get_scene_tree()->call_deferred("grab_focus");
@@ -2377,6 +2428,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
 			menu->add_icon_shortcut(get_icon("MoveDown", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/move_down"), TOOL_MOVE_DOWN);
 			menu->add_icon_shortcut(get_icon("MoveDown", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/move_down"), TOOL_MOVE_DOWN);
 			menu->add_icon_shortcut(get_icon("Duplicate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/duplicate"), TOOL_DUPLICATE);
 			menu->add_icon_shortcut(get_icon("Duplicate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/duplicate"), TOOL_DUPLICATE);
 			menu->add_icon_shortcut(get_icon("Reparent", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/reparent"), TOOL_REPARENT);
 			menu->add_icon_shortcut(get_icon("Reparent", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/reparent"), TOOL_REPARENT);
+			menu->add_icon_shortcut(get_icon("ReparentToNewNode", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/reparent_to_new_node"), TOOL_REPARENT_TO_NEW_NODE);
 			menu->add_icon_shortcut(get_icon("NewRoot", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/make_root"), TOOL_MAKE_ROOT);
 			menu->add_icon_shortcut(get_icon("NewRoot", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/make_root"), TOOL_MAKE_ROOT);
 		}
 		}
 	}
 	}
@@ -2673,6 +2725,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
 	ED_SHORTCUT("scene_tree/move_down", TTR("Move Down"), KEY_MASK_CMD | KEY_DOWN);
 	ED_SHORTCUT("scene_tree/move_down", TTR("Move Down"), KEY_MASK_CMD | KEY_DOWN);
 	ED_SHORTCUT("scene_tree/duplicate", TTR("Duplicate"), KEY_MASK_CMD | KEY_D);
 	ED_SHORTCUT("scene_tree/duplicate", TTR("Duplicate"), KEY_MASK_CMD | KEY_D);
 	ED_SHORTCUT("scene_tree/reparent", TTR("Reparent"));
 	ED_SHORTCUT("scene_tree/reparent", TTR("Reparent"));
+	ED_SHORTCUT("scene_tree/reparent_to_new_node", TTR("Reparent to New Node"));
 	ED_SHORTCUT("scene_tree/make_root", TTR("Make Scene Root"));
 	ED_SHORTCUT("scene_tree/make_root", TTR("Make Scene Root"));
 	ED_SHORTCUT("scene_tree/merge_from_scene", TTR("Merge From Scene"));
 	ED_SHORTCUT("scene_tree/merge_from_scene", TTR("Merge From Scene"));
 	ED_SHORTCUT("scene_tree/save_branch_as_scene", TTR("Save Branch as Scene"));
 	ED_SHORTCUT("scene_tree/save_branch_as_scene", TTR("Save Branch as Scene"));

+ 2 - 0
editor/scene_tree_dock.h

@@ -70,6 +70,7 @@ class SceneTreeDock : public VBoxContainer {
 		TOOL_MOVE_DOWN,
 		TOOL_MOVE_DOWN,
 		TOOL_DUPLICATE,
 		TOOL_DUPLICATE,
 		TOOL_REPARENT,
 		TOOL_REPARENT,
+		TOOL_REPARENT_TO_NEW_NODE,
 		TOOL_MAKE_ROOT,
 		TOOL_MAKE_ROOT,
 		TOOL_NEW_SCENE_FROM,
 		TOOL_NEW_SCENE_FROM,
 		TOOL_MERGE_FROM_SCENE,
 		TOOL_MERGE_FROM_SCENE,
@@ -142,6 +143,7 @@ class SceneTreeDock : public VBoxContainer {
 	bool first_enter;
 	bool first_enter;
 
 
 	void _create();
 	void _create();
+	void _do_create(Node *p_parent);
 	Node *scene_root;
 	Node *scene_root;
 	Node *edited_scene;
 	Node *edited_scene;
 	EditorNode *editor;
 	EditorNode *editor;