Kaynağa Gözat

Improve TreeItem API and allow to move nodes

trollodel 4 yıl önce
ebeveyn
işleme
bca0d36fe6

+ 1 - 1
doc/classes/Tree.xml

@@ -30,7 +30,7 @@
 		}
 		}
 		[/csharp]
 		[/csharp]
 		[/codeblocks]
 		[/codeblocks]
-		To iterate over all the [TreeItem] objects in a [Tree] object, use [method TreeItem.get_next] and [method TreeItem.get_children] after getting the root through [method get_root]. You can use [method Object.free] on a [TreeItem] to remove it from the [Tree].
+		To iterate over all the [TreeItem] objects in a [Tree] object, use [method TreeItem.get_next] and [method TreeItem.get_first_child] after getting the root through [method get_root]. You can use [method Object.free] on a [TreeItem] to remove it from the [Tree].
 	</description>
 	</description>
 	<tutorials>
 	<tutorials>
 	</tutorials>
 	</tutorials>

+ 60 - 6
doc/classes/TreeItem.xml

@@ -63,6 +63,16 @@
 				Removes all OpenType features.
 				Removes all OpenType features.
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="create_child">
+			<return type="TreeItem">
+			</return>
+			<argument index="0" name="idx" type="int" default="-1">
+			</argument>
+			<description>
+				Creates an item and adds it as a child.
+				The new item will be inserted as position [code]idx[/code] (the default value [code]-1[/code] means the last position), or it will be the last child if [code]idx[/code] is higher than the child count.
+			</description>
+		</method>
 		<method name="deselect">
 		<method name="deselect">
 			<return type="void">
 			<return type="void">
 			</return>
 			</return>
@@ -123,11 +133,28 @@
 				Returns the column's cell mode.
 				Returns the column's cell mode.
 			</description>
 			</description>
 		</method>
 		</method>
-		<method name="get_children">
+		<method name="get_child">
 			<return type="TreeItem">
 			<return type="TreeItem">
 			</return>
 			</return>
+			<argument index="0" name="idx" type="int">
+			</argument>
+			<description>
+				Returns a child item by its index (see [method get_child_count]). This method is often used for iterating all children of an item.
+				Negative indices access the children from the last one.
+			</description>
+		</method>
+		<method name="get_child_count">
+			<return type="int">
+			</return>
 			<description>
 			<description>
-				Returns the TreeItem's first child item or a null object if there is none.
+				Returns the number of child items.
+			</description>
+		</method>
+		<method name="get_children">
+			<return type="Array">
+			</return>
+			<description>
+				Returns an array of references to the item's children.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="get_custom_bg_color" qualifiers="const">
 		<method name="get_custom_bg_color" qualifiers="const">
@@ -157,6 +184,13 @@
 				Returns [code]true[/code] if [code]expand_right[/code] is set.
 				Returns [code]true[/code] if [code]expand_right[/code] is set.
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="get_first_child">
+			<return type="TreeItem">
+			</return>
+			<description>
+				Returns the TreeItem's first child.
+			</description>
+		</method>
 		<method name="get_icon" qualifiers="const">
 		<method name="get_icon" qualifiers="const">
 			<return type="Texture2D">
 			<return type="Texture2D">
 			</return>
 			</return>
@@ -193,6 +227,13 @@
 				Returns the icon [Texture2D] region as [Rect2].
 				Returns the icon [Texture2D] region as [Rect2].
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="get_index">
+			<return type="int">
+			</return>
+			<description>
+				Returns the node's order in the tree. For example, if called on the first child item the position is [code]0[/code].
+			</description>
+		</method>
 		<method name="get_language" qualifiers="const">
 		<method name="get_language" qualifiers="const">
 			<return type="String">
 			<return type="String">
 			</return>
 			</return>
@@ -342,6 +383,13 @@
 				Returns the given column's tooltip.
 				Returns the given column's tooltip.
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="get_tree">
+			<return type="Tree">
+			</return>
+			<description>
+				Returns the [Tree] that owns this TreeItem.
+			</description>
+		</method>
 		<method name="is_button_disabled" qualifiers="const">
 		<method name="is_button_disabled" qualifiers="const">
 			<return type="bool">
 			<return type="bool">
 			</return>
 			</return>
@@ -397,18 +445,24 @@
 				Returns [code]true[/code] if column [code]column[/code] is selected.
 				Returns [code]true[/code] if column [code]column[/code] is selected.
 			</description>
 			</description>
 		</method>
 		</method>
-		<method name="move_to_bottom">
+		<method name="move_after">
 			<return type="void">
 			<return type="void">
 			</return>
 			</return>
+			<argument index="0" name="item" type="Object">
+			</argument>
 			<description>
 			<description>
-				Moves this TreeItem to the bottom in the [Tree] hierarchy.
+				Moves this TreeItem right after the given [code]item[/code].
+				[b]Note:[/b] You can't move to the root or move the root.
 			</description>
 			</description>
 		</method>
 		</method>
-		<method name="move_to_top">
+		<method name="move_before">
 			<return type="void">
 			<return type="void">
 			</return>
 			</return>
+			<argument index="0" name="item" type="Object">
+			</argument>
 			<description>
 			<description>
-				Moves this TreeItem to the top in the [Tree] hierarchy.
+				Moves this TreeItem right before the given [code]item[/code].
+				[b]Note:[/b] You can't move to the root or move the root.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="remove_child">
 		<method name="remove_child">

+ 2 - 2
editor/action_map_editor.cpp

@@ -122,9 +122,9 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event) {
 
 
 		// Update selected item in input list for keys, joybuttons and joyaxis only (since the mouse cannot be "listened" for).
 		// Update selected item in input list for keys, joybuttons and joyaxis only (since the mouse cannot be "listened" for).
 		if (k.is_valid() || joyb.is_valid() || joym.is_valid()) {
 		if (k.is_valid() || joyb.is_valid() || joym.is_valid()) {
-			TreeItem *category = input_list_tree->get_root()->get_children();
+			TreeItem *category = input_list_tree->get_root()->get_first_child();
 			while (category) {
 			while (category) {
-				TreeItem *input_item = category->get_children();
+				TreeItem *input_item = category->get_first_child();
 
 
 				// has_type this should be always true, unless the tree structure has been misconfigured.
 				// has_type this should be always true, unless the tree structure has been misconfigured.
 				bool has_type = input_item->get_parent()->has_meta("__type");
 				bool has_type = input_item->get_parent()->has_meta("__type");

+ 4 - 4
editor/animation_track_editor.cpp

@@ -5216,7 +5216,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
 			track_clipboard.clear();
 			track_clipboard.clear();
 			TreeItem *root = track_copy_select->get_root();
 			TreeItem *root = track_copy_select->get_root();
 			if (root) {
 			if (root) {
-				TreeItem *it = root->get_children();
+				TreeItem *it = root->get_first_child();
 				while (it) {
 				while (it) {
 					Dictionary md = it->get_metadata(0);
 					Dictionary md = it->get_metadata(0);
 					int idx = md["track_idx"];
 					int idx = md["track_idx"];
@@ -5602,7 +5602,7 @@ void AnimationTrackEditor::_show_imported_anim_warning() {
 }
 }
 
 
 void AnimationTrackEditor::_select_all_tracks_for_copy() {
 void AnimationTrackEditor::_select_all_tracks_for_copy() {
-	TreeItem *track = track_copy_select->get_root()->get_children();
+	TreeItem *track = track_copy_select->get_root()->get_first_child();
 	if (!track) {
 	if (!track) {
 		return;
 		return;
 	}
 	}
@@ -5616,7 +5616,7 @@ void AnimationTrackEditor::_select_all_tracks_for_copy() {
 		track = track->get_next();
 		track = track->get_next();
 	}
 	}
 
 
-	track = track_copy_select->get_root()->get_children();
+	track = track_copy_select->get_root()->get_first_child();
 	while (track) {
 	while (track) {
 		track->set_checked(0, !all_selected);
 		track->set_checked(0, !all_selected);
 		track = track->get_next();
 		track = track->get_next();
@@ -5681,7 +5681,7 @@ void AnimationTrackEditor::_pick_track_select_recursive(TreeItem *p_item, const
 		p_select_candidates.push_back(node);
 		p_select_candidates.push_back(node);
 	}
 	}
 
 
-	TreeItem *c = p_item->get_children();
+	TreeItem *c = p_item->get_first_child();
 
 
 	while (c) {
 	while (c) {
 		_pick_track_select_recursive(c, p_filter, p_select_candidates);
 		_pick_track_select_recursive(c, p_filter, p_select_candidates);

+ 1 - 1
editor/connections_dialog.cpp

@@ -655,7 +655,7 @@ void ConnectionsDock::_disconnect_all() {
 		return;
 		return;
 	}
 	}
 
 
-	TreeItem *child = item->get_children();
+	TreeItem *child = item->get_first_child();
 	String signalName = item->get_metadata(0).operator Dictionary()["name"];
 	String signalName = item->get_metadata(0).operator Dictionary()["name"];
 	undo_redo->create_action(vformat(TTR("Disconnect all from signal: '%s'"), signalName));
 	undo_redo->create_action(vformat(TTR("Disconnect all from signal: '%s'"), signalName));
 
 

+ 6 - 6
editor/debugger/script_editor_debugger.cpp

@@ -220,7 +220,7 @@ void ScriptEditorDebugger::_file_selected(const String &p_file) {
 			file->store_csv_line(headers);
 			file->store_csv_line(headers);
 
 
 			if (vmem_tree->get_root()) {
 			if (vmem_tree->get_root()) {
-				TreeItem *ti = vmem_tree->get_root()->get_children();
+				TreeItem *ti = vmem_tree->get_root()->get_first_child();
 				while (ti) {
 				while (ti) {
 					Vector<String> values;
 					Vector<String> values;
 					values.resize(vmem_tree->get_columns());
 					values.resize(vmem_tree->get_columns());
@@ -1319,7 +1319,7 @@ bool ScriptEditorDebugger::is_skip_breakpoints() {
 void ScriptEditorDebugger::_error_activated() {
 void ScriptEditorDebugger::_error_activated() {
 	TreeItem *selected = error_tree->get_selected();
 	TreeItem *selected = error_tree->get_selected();
 
 
-	TreeItem *ci = selected->get_children();
+	TreeItem *ci = selected->get_first_child();
 	if (ci) {
 	if (ci) {
 		selected->set_collapsed(!selected->is_collapsed());
 		selected->set_collapsed(!selected->is_collapsed());
 	}
 	}
@@ -1341,7 +1341,7 @@ void ScriptEditorDebugger::_expand_errors_list() {
 		return;
 		return;
 	}
 	}
 
 
-	TreeItem *item = root->get_children();
+	TreeItem *item = root->get_first_child();
 	while (item) {
 	while (item) {
 		item->set_collapsed(false);
 		item->set_collapsed(false);
 		item = item->get_next();
 		item = item->get_next();
@@ -1354,7 +1354,7 @@ void ScriptEditorDebugger::_collapse_errors_list() {
 		return;
 		return;
 	}
 	}
 
 
-	TreeItem *item = root->get_children();
+	TreeItem *item = root->get_first_child();
 	while (item) {
 	while (item) {
 		item->set_collapsed(true);
 		item->set_collapsed(true);
 		item = item->get_next();
 		item = item->get_next();
@@ -1403,7 +1403,7 @@ void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) {
 			int rpad_len = text.length();
 			int rpad_len = text.length();
 
 
 			text = type + text + ti->get_text(1) + "\n";
 			text = type + text + ti->get_text(1) + "\n";
-			TreeItem *ci = ti->get_children();
+			TreeItem *ci = ti->get_first_child();
 			while (ci) {
 			while (ci) {
 				text += "  " + ci->get_text(0).rpad(rpad_len) + ci->get_text(1) + "\n";
 				text += "  " + ci->get_text(0).rpad(rpad_len) + ci->get_text(1) + "\n";
 				ci = ci->get_next();
 				ci = ci->get_next();
@@ -1419,7 +1419,7 @@ void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) {
 			}
 			}
 
 
 			// We only need the first child here (C++ source stack trace).
 			// We only need the first child here (C++ source stack trace).
-			TreeItem *ci = ti->get_children();
+			TreeItem *ci = ti->get_first_child();
 			// Parse back the `file:line @ method()` string.
 			// Parse back the `file:line @ method()` string.
 			const Vector<String> file_line_number = ci->get_text(1).split("@")[0].strip_edges().split(":");
 			const Vector<String> file_line_number = ci->get_text(1).split("@")[0].strip_edges().split(":");
 			ERR_FAIL_COND_MSG(file_line_number.size() < 2, "Incorrect C++ source stack trace file:line format (please report).");
 			ERR_FAIL_COND_MSG(file_line_number.size() < 2, "Incorrect C++ source stack trace file:line format (please report).");

+ 2 - 2
editor/dependency_editor.cpp

@@ -725,8 +725,8 @@ void OrphanResourcesDialog::_find_to_delete(TreeItem *p_item, List<String> &path
 			paths.push_back(p_item->get_metadata(0));
 			paths.push_back(p_item->get_metadata(0));
 		}
 		}
 
 
-		if (p_item->get_children()) {
-			_find_to_delete(p_item->get_children(), paths);
+		if (p_item->get_first_child()) {
+			_find_to_delete(p_item->get_first_child(), paths);
 		}
 		}
 
 
 		p_item = p_item->get_next();
 		p_item = p_item->get_next();

+ 3 - 3
editor/editor_asset_installer.cpp

@@ -45,8 +45,8 @@ void EditorAssetInstaller::_update_subitems(TreeItem *p_item, bool p_check, bool
 		p_item->set_checked(0, false);
 		p_item->set_checked(0, false);
 	}
 	}
 
 
-	if (p_item->get_children()) {
-		_update_subitems(p_item->get_children(), p_check);
+	if (p_item->get_first_child()) {
+		_update_subitems(p_item->get_first_child(), p_check);
 	}
 	}
 
 
 	if (!p_first && p_item->get_next()) {
 	if (!p_first && p_item->get_next()) {
@@ -60,7 +60,7 @@ void EditorAssetInstaller::_uncheck_parent(TreeItem *p_item) {
 	}
 	}
 
 
 	bool any_checked = false;
 	bool any_checked = false;
-	TreeItem *item = p_item->get_children();
+	TreeItem *item = p_item->get_first_child();
 	while (item) {
 	while (item) {
 		if (item->is_checked(0)) {
 		if (item->is_checked(0)) {
 			any_checked = true;
 			any_checked = true;

+ 3 - 3
editor/editor_sectioned_inspector.cpp

@@ -135,7 +135,7 @@ void SectionedInspector::_section_selected() {
 	}
 	}
 
 
 	selected_category = sections->get_selected()->get_metadata(0);
 	selected_category = sections->get_selected()->get_metadata(0);
-	filter->set_section(selected_category, sections->get_selected()->get_children() == nullptr);
+	filter->set_section(selected_category, sections->get_selected()->get_first_child() == nullptr);
 	inspector->set_property_prefix(selected_category + "/");
 	inspector->set_property_prefix(selected_category + "/");
 }
 }
 
 
@@ -187,8 +187,8 @@ void SectionedInspector::edit(Object *p_object) {
 
 
 		TreeItem *first_item = sections->get_root();
 		TreeItem *first_item = sections->get_root();
 		if (first_item) {
 		if (first_item) {
-			while (first_item->get_children()) {
-				first_item = first_item->get_children();
+			while (first_item->get_first_child()) {
+				first_item = first_item->get_first_child();
 			}
 			}
 
 
 			first_item->select(0);
 			first_item->select(0);

+ 13 - 13
editor/filesystem_dock.cpp

@@ -180,12 +180,12 @@ Vector<String> FileSystemDock::_compute_uncollapsed_paths() {
 	Vector<String> uncollapsed_paths;
 	Vector<String> uncollapsed_paths;
 	TreeItem *root = tree->get_root();
 	TreeItem *root = tree->get_root();
 	if (root) {
 	if (root) {
-		TreeItem *favorites_item = root->get_children();
+		TreeItem *favorites_item = root->get_first_child();
 		if (!favorites_item->is_collapsed()) {
 		if (!favorites_item->is_collapsed()) {
 			uncollapsed_paths.push_back(favorites_item->get_metadata(0));
 			uncollapsed_paths.push_back(favorites_item->get_metadata(0));
 		}
 		}
 
 
-		TreeItem *resTree = root->get_children()->get_next();
+		TreeItem *resTree = root->get_first_child()->get_next();
 		if (resTree) {
 		if (resTree) {
 			Vector<TreeItem *> needs_check;
 			Vector<TreeItem *> needs_check;
 			needs_check.push_back(resTree);
 			needs_check.push_back(resTree);
@@ -193,7 +193,7 @@ Vector<String> FileSystemDock::_compute_uncollapsed_paths() {
 			while (needs_check.size()) {
 			while (needs_check.size()) {
 				if (!needs_check[0]->is_collapsed()) {
 				if (!needs_check[0]->is_collapsed()) {
 					uncollapsed_paths.push_back(needs_check[0]->get_metadata(0));
 					uncollapsed_paths.push_back(needs_check[0]->get_metadata(0));
-					TreeItem *child = needs_check[0]->get_children();
+					TreeItem *child = needs_check[0]->get_first_child();
 					while (child) {
 					while (child) {
 						needs_check.push_back(child);
 						needs_check.push_back(child);
 						child = child->get_next();
 						child = child->get_next();
@@ -464,7 +464,7 @@ void FileSystemDock::_tree_multi_selected(Object *p_item, int p_column, bool p_s
 		return;
 		return;
 	}
 	}
 
 
-	TreeItem *favorites_item = tree->get_root()->get_children();
+	TreeItem *favorites_item = tree->get_root()->get_first_child();
 	if (selected->get_parent() == favorites_item && !String(selected->get_metadata(0)).ends_with("/")) {
 	if (selected->get_parent() == favorites_item && !String(selected->get_metadata(0)).ends_with("/")) {
 		// Go to the favorites if we click in the favorites and the path has changed.
 		// Go to the favorites if we click in the favorites and the path has changed.
 		path = "Favorites";
 		path = "Favorites";
@@ -1644,7 +1644,7 @@ Vector<String> FileSystemDock::_tree_get_selected(bool remove_self_inclusion) {
 	// Build a list of selected items with the active one at the first position.
 	// Build a list of selected items with the active one at the first position.
 	Vector<String> selected_strings;
 	Vector<String> selected_strings;
 
 
-	TreeItem *favorites_item = tree->get_root()->get_children();
+	TreeItem *favorites_item = tree->get_root()->get_first_child();
 	TreeItem *active_selected = tree->get_selected();
 	TreeItem *active_selected = tree->get_selected();
 	if (active_selected && active_selected != favorites_item) {
 	if (active_selected && active_selected != favorites_item) {
 		selected_strings.push_back(active_selected->get_metadata(0));
 		selected_strings.push_back(active_selected->get_metadata(0));
@@ -1700,7 +1700,7 @@ void FileSystemDock::_tree_rmb_option(int p_option) {
 				while (needs_check.size()) {
 				while (needs_check.size()) {
 					needs_check[0]->set_collapsed(is_collapsed);
 					needs_check[0]->set_collapsed(is_collapsed);
 
 
-					TreeItem *child = needs_check[0]->get_children();
+					TreeItem *child = needs_check[0]->get_first_child();
 					while (child) {
 					while (child) {
 						needs_check.push_back(child);
 						needs_check.push_back(child);
 						child = child->get_next();
 						child = child->get_next();
@@ -2062,13 +2062,13 @@ Variant FileSystemDock::get_drag_data_fw(const Point2 &p_point, Control *p_from)
 		// Check if the first selected is in favorite.
 		// Check if the first selected is in favorite.
 		TreeItem *selected = tree->get_next_selected(tree->get_root());
 		TreeItem *selected = tree->get_next_selected(tree->get_root());
 		while (selected) {
 		while (selected) {
-			TreeItem *favorites_item = tree->get_root()->get_children();
+			TreeItem *favorites_item = tree->get_root()->get_first_child();
 			if (selected == favorites_item) {
 			if (selected == favorites_item) {
 				// The "Favorites" item is not draggable.
 				// The "Favorites" item is not draggable.
 				return Variant();
 				return Variant();
 			}
 			}
 
 
-			bool is_favorite = selected->get_parent() != nullptr && tree->get_root()->get_children() == selected->get_parent();
+			bool is_favorite = selected->get_parent() != nullptr && tree->get_root()->get_first_child() == selected->get_parent();
 			all_favorites &= is_favorite;
 			all_favorites &= is_favorite;
 			all_not_favorites &= !is_favorite;
 			all_not_favorites &= !is_favorite;
 			selected = tree->get_next_selected(selected);
 			selected = tree->get_next_selected(selected);
@@ -2114,7 +2114,7 @@ bool FileSystemDock::can_drop_data_fw(const Point2 &p_point, const Variant &p_da
 		}
 		}
 
 
 		int drop_section = tree->get_drop_section_at_position(p_point);
 		int drop_section = tree->get_drop_section_at_position(p_point);
-		TreeItem *favorites_item = tree->get_root()->get_children();
+		TreeItem *favorites_item = tree->get_root()->get_first_child();
 
 
 		TreeItem *resources_item = favorites_item->get_next();
 		TreeItem *resources_item = favorites_item->get_next();
 
 
@@ -2190,7 +2190,7 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
 
 
 		int drop_position;
 		int drop_position;
 		Vector<String> files = drag_data["files"];
 		Vector<String> files = drag_data["files"];
-		TreeItem *favorites_item = tree->get_root()->get_children();
+		TreeItem *favorites_item = tree->get_root()->get_first_child();
 		TreeItem *resources_item = favorites_item->get_next();
 		TreeItem *resources_item = favorites_item->get_next();
 
 
 		if (ti == favorites_item) {
 		if (ti == favorites_item) {
@@ -2328,10 +2328,10 @@ void FileSystemDock::_get_drag_target_folder(String &target, bool &target_favori
 		int section = tree->get_drop_section_at_position(p_point);
 		int section = tree->get_drop_section_at_position(p_point);
 		if (ti) {
 		if (ti) {
 			// Check the favorites first.
 			// Check the favorites first.
-			if (ti == tree->get_root()->get_children() && section >= 0) {
+			if (ti == tree->get_root()->get_first_child() && section >= 0) {
 				target_favorites = true;
 				target_favorites = true;
 				return;
 				return;
-			} else if (ti->get_parent() == tree->get_root()->get_children()) {
+			} else if (ti->get_parent() == tree->get_root()->get_first_child()) {
 				target_favorites = true;
 				target_favorites = true;
 				return;
 				return;
 			} else {
 			} else {
@@ -2347,7 +2347,7 @@ void FileSystemDock::_get_drag_target_folder(String &target, bool &target_favori
 						return;
 						return;
 					}
 					}
 				} else {
 				} else {
-					if (ti->get_parent() != tree->get_root()->get_children()) {
+					if (ti->get_parent() != tree->get_root()->get_first_child()) {
 						// Not in the favorite section.
 						// Not in the favorite section.
 						if (fpath != "res://") {
 						if (fpath != "res://") {
 							// We drop between two files
 							// We drop between two files

+ 1 - 1
editor/find_in_files.cpp

@@ -838,7 +838,7 @@ void FindInFilesPanel::_on_replace_all_clicked() {
 		String fpath = file_item->get_metadata(0);
 		String fpath = file_item->get_metadata(0);
 
 
 		Vector<Result> locations;
 		Vector<Result> locations;
-		for (TreeItem *item = file_item->get_children(); item; item = item->get_next()) {
+		for (TreeItem *item = file_item->get_first_child(); item; item = item->get_next()) {
 			if (!item->is_checked(0)) {
 			if (!item->is_checked(0)) {
 				continue;
 				continue;
 			}
 			}

+ 4 - 4
editor/groups_editor.cpp

@@ -52,7 +52,7 @@ void GroupDialog::_group_selected() {
 	selected_group = groups->get_selected()->get_text(0);
 	selected_group = groups->get_selected()->get_text(0);
 	_load_nodes(scene_tree->get_edited_scene_root());
 	_load_nodes(scene_tree->get_edited_scene_root());
 
 
-	group_empty->set_visible(!remove_node_root->get_children());
+	group_empty->set_visible(!remove_node_root->get_first_child());
 }
 }
 
 
 void GroupDialog::_load_nodes(Node *p_current) {
 void GroupDialog::_load_nodes(Node *p_current) {
@@ -217,7 +217,7 @@ void GroupDialog::_group_renamed() {
 	}
 	}
 
 
 	const String name = renamed_group->get_text(0).strip_edges();
 	const String name = renamed_group->get_text(0).strip_edges();
-	for (TreeItem *E = groups_root->get_children(); E; E = E->get_next()) {
+	for (TreeItem *E = groups_root->get_first_child(); E; E = E->get_next()) {
 		if (E != renamed_group && E->get_text(0) == name) {
 		if (E != renamed_group && E->get_text(0) == name) {
 			renamed_group->set_text(0, selected_group);
 			renamed_group->set_text(0, selected_group);
 			error->set_text(TTR("Group name already exists."));
 			error->set_text(TTR("Group name already exists."));
@@ -274,7 +274,7 @@ void GroupDialog::_rename_group_item(const String &p_old_name, const String &p_n
 
 
 	selected_group = p_new_name;
 	selected_group = p_new_name;
 
 
-	for (TreeItem *E = groups_root->get_children(); E; E = E->get_next()) {
+	for (TreeItem *E = groups_root->get_first_child(); E; E = E->get_next()) {
 		if (E->get_text(0) == p_old_name) {
 		if (E->get_text(0) == p_old_name) {
 			E->set_text(0, p_new_name);
 			E->set_text(0, p_new_name);
 			return;
 			return;
@@ -351,7 +351,7 @@ void GroupDialog::_delete_group_item(const String &p_name) {
 		selected_group = "";
 		selected_group = "";
 	}
 	}
 
 
-	for (TreeItem *E = groups_root->get_children(); E; E = E->get_next()) {
+	for (TreeItem *E = groups_root->get_first_child(); E; E = E->get_next()) {
 		if (E->get_text(0) == p_name) {
 		if (E->get_text(0) == p_name) {
 			groups_root->remove_child(E);
 			groups_root->remove_child(E);
 			return;
 			return;

+ 2 - 2
editor/plugins/script_editor_plugin.cpp

@@ -339,13 +339,13 @@ void ScriptEditorQuickOpen::_update_search() {
 		if ((search_box->get_text() == "" || file.findn(search_box->get_text()) != -1)) {
 		if ((search_box->get_text() == "" || file.findn(search_box->get_text()) != -1)) {
 			TreeItem *ti = search_options->create_item(root);
 			TreeItem *ti = search_options->create_item(root);
 			ti->set_text(0, file);
 			ti->set_text(0, file);
-			if (root->get_children() == ti) {
+			if (root->get_first_child() == ti) {
 				ti->select(0);
 				ti->select(0);
 			}
 			}
 		}
 		}
 	}
 	}
 
 
-	get_ok_button()->set_disabled(root->get_children() == nullptr);
+	get_ok_button()->set_disabled(root->get_first_child() == nullptr);
 }
 }
 
 
 void ScriptEditorQuickOpen::_confirmed() {
 void ScriptEditorQuickOpen::_confirmed() {

+ 4 - 4
editor/plugins/theme_editor_plugin.cpp

@@ -321,7 +321,7 @@ void ThemeItemImportTree::_toggle_type_items(bool p_collapse) {
 		return;
 		return;
 	}
 	}
 
 
-	TreeItem *type_node = root->get_children();
+	TreeItem *type_node = root->get_first_child();
 	while (type_node) {
 	while (type_node) {
 		type_node->set_collapsed(p_collapse);
 		type_node->set_collapsed(p_collapse);
 		type_node = type_node->get_next();
 		type_node = type_node->get_next();
@@ -491,7 +491,7 @@ void ThemeItemImportTree::_tree_item_edited() {
 }
 }
 
 
 void ThemeItemImportTree::_select_all_subitems(TreeItem *p_root_item, bool p_select_with_data) {
 void ThemeItemImportTree::_select_all_subitems(TreeItem *p_root_item, bool p_select_with_data) {
-	TreeItem *child_item = p_root_item->get_children();
+	TreeItem *child_item = p_root_item->get_first_child();
 	while (child_item) {
 	while (child_item) {
 		child_item->set_checked(IMPORT_ITEM, true);
 		child_item->set_checked(IMPORT_ITEM, true);
 		if (p_select_with_data) {
 		if (p_select_with_data) {
@@ -505,7 +505,7 @@ void ThemeItemImportTree::_select_all_subitems(TreeItem *p_root_item, bool p_sel
 }
 }
 
 
 void ThemeItemImportTree::_deselect_all_subitems(TreeItem *p_root_item, bool p_deselect_completely) {
 void ThemeItemImportTree::_deselect_all_subitems(TreeItem *p_root_item, bool p_deselect_completely) {
-	TreeItem *child_item = p_root_item->get_children();
+	TreeItem *child_item = p_root_item->get_first_child();
 	while (child_item) {
 	while (child_item) {
 		child_item->set_checked(IMPORT_ITEM_DATA, false);
 		child_item->set_checked(IMPORT_ITEM_DATA, false);
 		if (p_deselect_completely) {
 		if (p_deselect_completely) {
@@ -527,7 +527,7 @@ void ThemeItemImportTree::_update_parent_items(TreeItem *p_root_item) {
 	bool any_checked = false;
 	bool any_checked = false;
 	bool any_checked_with_data = false;
 	bool any_checked_with_data = false;
 
 
-	TreeItem *child_item = parent_item->get_children();
+	TreeItem *child_item = parent_item->get_first_child();
 	while (child_item) {
 	while (child_item) {
 		if (child_item->is_checked(IMPORT_ITEM)) {
 		if (child_item->is_checked(IMPORT_ITEM)) {
 			any_checked = true;
 			any_checked = true;

+ 1 - 1
editor/plugins/tiles/tile_map_editor.cpp

@@ -2587,7 +2587,7 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
 							}
 							}
 
 
 							if (need_tree_item_switch) {
 							if (need_tree_item_switch) {
-								for (tree_item = terrains_tree->get_root()->get_children(); tree_item; tree_item = tree_item->get_next_visible()) {
+								for (tree_item = terrains_tree->get_root()->get_first_child(); tree_item; tree_item = tree_item->get_next_visible()) {
 									Dictionary metadata_dict = tree_item->get_metadata(0);
 									Dictionary metadata_dict = tree_item->get_metadata(0);
 									if (metadata_dict.has("terrain_set") && metadata_dict.has("terrain_id")) {
 									if (metadata_dict.has("terrain_set") && metadata_dict.has("terrain_id")) {
 										int terrain_set = metadata_dict["terrain_set"];
 										int terrain_set = metadata_dict["terrain_set"];

+ 2 - 2
editor/plugins/version_control_editor_plugin.cpp

@@ -180,7 +180,7 @@ void VersionControlEditorPlugin::_stage_selected() {
 	staged_files_count = 0;
 	staged_files_count = 0;
 	TreeItem *root = stage_files->get_root();
 	TreeItem *root = stage_files->get_root();
 	if (root) {
 	if (root) {
-		TreeItem *file_entry = root->get_children();
+		TreeItem *file_entry = root->get_first_child();
 		while (file_entry) {
 		while (file_entry) {
 			if (file_entry->is_checked(0)) {
 			if (file_entry->is_checked(0)) {
 				EditorVCSInterface::get_singleton()->stage_file(file_entry->get_metadata(0));
 				EditorVCSInterface::get_singleton()->stage_file(file_entry->get_metadata(0));
@@ -207,7 +207,7 @@ void VersionControlEditorPlugin::_stage_all() {
 	staged_files_count = 0;
 	staged_files_count = 0;
 	TreeItem *root = stage_files->get_root();
 	TreeItem *root = stage_files->get_root();
 	if (root) {
 	if (root) {
-		TreeItem *file_entry = root->get_children();
+		TreeItem *file_entry = root->get_first_child();
 		while (file_entry) {
 		while (file_entry) {
 			EditorVCSInterface::get_singleton()->stage_file(file_entry->get_metadata(0));
 			EditorVCSInterface::get_singleton()->stage_file(file_entry->get_metadata(0));
 			file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color("success_color", "Editor"));
 			file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color("success_color", "Editor"));

+ 5 - 5
editor/plugins/visual_shader_editor_plugin.cpp

@@ -2762,10 +2762,10 @@ void VisualShaderEditor::_notification(int p_what) {
 
 
 		// collapse tree by default
 		// collapse tree by default
 
 
-		TreeItem *category = members->get_root()->get_children();
+		TreeItem *category = members->get_root()->get_first_child();
 		while (category) {
 		while (category) {
 			category->set_collapsed(true);
 			category->set_collapsed(true);
-			TreeItem *sub_category = category->get_children();
+			TreeItem *sub_category = category->get_first_child();
 			while (sub_category) {
 			while (sub_category) {
 				sub_category->set_collapsed(true);
 				sub_category->set_collapsed(true);
 				sub_category = sub_category->get_next();
 				sub_category = sub_category->get_next();
@@ -3210,14 +3210,14 @@ void VisualShaderEditor::_member_cancel() {
 }
 }
 
 
 void VisualShaderEditor::_tools_menu_option(int p_idx) {
 void VisualShaderEditor::_tools_menu_option(int p_idx) {
-	TreeItem *category = members->get_root()->get_children();
+	TreeItem *category = members->get_root()->get_first_child();
 
 
 	switch (p_idx) {
 	switch (p_idx) {
 		case EXPAND_ALL:
 		case EXPAND_ALL:
 
 
 			while (category) {
 			while (category) {
 				category->set_collapsed(false);
 				category->set_collapsed(false);
-				TreeItem *sub_category = category->get_children();
+				TreeItem *sub_category = category->get_first_child();
 				while (sub_category) {
 				while (sub_category) {
 					sub_category->set_collapsed(false);
 					sub_category->set_collapsed(false);
 					sub_category = sub_category->get_next();
 					sub_category = sub_category->get_next();
@@ -3231,7 +3231,7 @@ void VisualShaderEditor::_tools_menu_option(int p_idx) {
 
 
 			while (category) {
 			while (category) {
 				category->set_collapsed(true);
 				category->set_collapsed(true);
-				TreeItem *sub_category = category->get_children();
+				TreeItem *sub_category = category->get_first_child();
 				while (sub_category) {
 				while (sub_category) {
 					sub_category->set_collapsed(true);
 					sub_category->set_collapsed(true);
 					sub_category = sub_category->get_next();
 					sub_category = sub_category->get_next();

+ 2 - 2
editor/project_export.cpp

@@ -795,7 +795,7 @@ void ProjectExportDialog::_tree_changed() {
 }
 }
 
 
 void ProjectExportDialog::_check_dir_recursive(TreeItem *p_dir, bool p_checked) {
 void ProjectExportDialog::_check_dir_recursive(TreeItem *p_dir, bool p_checked) {
-	for (TreeItem *child = p_dir->get_children(); child; child = child->get_next()) {
+	for (TreeItem *child = p_dir->get_first_child(); child; child = child->get_next()) {
 		String path = child->get_metadata(0);
 		String path = child->get_metadata(0);
 
 
 		child->set_checked(0, p_checked);
 		child->set_checked(0, p_checked);
@@ -818,7 +818,7 @@ void ProjectExportDialog::_refresh_parent_checks(TreeItem *p_item) {
 	}
 	}
 
 
 	bool checked = true;
 	bool checked = true;
-	for (TreeItem *child = parent->get_children(); child; child = child->get_next()) {
+	for (TreeItem *child = parent->get_first_child(); child; child = child->get_next()) {
 		checked = checked && child->is_checked(0);
 		checked = checked && child->is_checked(0);
 		if (!checked) {
 		if (!checked) {
 			break;
 			break;

+ 6 - 6
editor/property_selector.cpp

@@ -52,7 +52,7 @@ void PropertySelector::_sbox_input(const Ref<InputEvent> &p_ie) {
 				search_box->accept_event();
 				search_box->accept_event();
 
 
 				TreeItem *root = search_options->get_root();
 				TreeItem *root = search_options->get_root();
-				if (!root->get_children()) {
+				if (!root->get_first_child()) {
 					break;
 					break;
 				}
 				}
 
 
@@ -150,7 +150,7 @@ void PropertySelector::_update_search() {
 
 
 		for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
 		for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
 			if (E->get().usage == PROPERTY_USAGE_CATEGORY) {
 			if (E->get().usage == PROPERTY_USAGE_CATEGORY) {
-				if (category && category->get_children() == nullptr) {
+				if (category && category->get_first_child() == nullptr) {
 					memdelete(category); //old category was unused
 					memdelete(category); //old category was unused
 				}
 				}
 				category = search_options->create_item(root);
 				category = search_options->create_item(root);
@@ -192,7 +192,7 @@ void PropertySelector::_update_search() {
 			item->set_selectable(0, true);
 			item->set_selectable(0, true);
 		}
 		}
 
 
-		if (category && category->get_children() == nullptr) {
+		if (category && category->get_first_child() == nullptr) {
 			memdelete(category); //old category was unused
 			memdelete(category); //old category was unused
 		}
 		}
 	} else {
 	} else {
@@ -225,7 +225,7 @@ void PropertySelector::_update_search() {
 
 
 		for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
 		for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
 			if (E->get().name.begins_with("*")) {
 			if (E->get().name.begins_with("*")) {
-				if (category && category->get_children() == nullptr) {
+				if (category && category->get_first_child() == nullptr) {
 					memdelete(category); //old category was unused
 					memdelete(category); //old category was unused
 				}
 				}
 				category = search_options->create_item(root);
 				category = search_options->create_item(root);
@@ -316,12 +316,12 @@ void PropertySelector::_update_search() {
 			}
 			}
 		}
 		}
 
 
-		if (category && category->get_children() == nullptr) {
+		if (category && category->get_first_child() == nullptr) {
 			memdelete(category); //old category was unused
 			memdelete(category); //old category was unused
 		}
 		}
 	}
 	}
 
 
-	get_ok_button()->set_disabled(root->get_children() == nullptr);
+	get_ok_button()->set_disabled(root->get_first_child() == nullptr);
 }
 }
 
 
 void PropertySelector::_confirmed() {
 void PropertySelector::_confirmed() {

+ 2 - 2
editor/quick_open.cpp

@@ -102,7 +102,7 @@ void EditorQuickOpen::_update_search() {
 			ti->set_icon(0, *icons.lookup_ptr(entries[i].path.get_extension()));
 			ti->set_icon(0, *icons.lookup_ptr(entries[i].path.get_extension()));
 		}
 		}
 
 
-		TreeItem *to_select = root->get_children();
+		TreeItem *to_select = root->get_first_child();
 		to_select->select(0);
 		to_select->select(0);
 		to_select->set_as_cursor(0);
 		to_select->set_as_cursor(0);
 		search_options->scroll_to_item(to_select);
 		search_options->scroll_to_item(to_select);
@@ -170,7 +170,7 @@ void EditorQuickOpen::_sbox_input(const Ref<InputEvent> &p_ie) {
 
 
 				if (allow_multi_select) {
 				if (allow_multi_select) {
 					TreeItem *root = search_options->get_root();
 					TreeItem *root = search_options->get_root();
-					if (!root->get_children()) {
+					if (!root->get_first_child()) {
 						break;
 						break;
 					}
 					}
 
 

+ 2 - 2
editor/scene_tree_dock.cpp

@@ -1833,7 +1833,7 @@ bool SceneTreeDock::_is_collapsed_recursive(TreeItem *p_item) const {
 		TreeItem *item = needs_check.back()->get();
 		TreeItem *item = needs_check.back()->get();
 		needs_check.pop_back();
 		needs_check.pop_back();
 
 
-		TreeItem *child = item->get_children();
+		TreeItem *child = item->get_first_child();
 		is_branch_collapsed = item->is_collapsed() && child;
 		is_branch_collapsed = item->is_collapsed() && child;
 
 
 		if (is_branch_collapsed) {
 		if (is_branch_collapsed) {
@@ -1857,7 +1857,7 @@ void SceneTreeDock::_set_collapsed_recursive(TreeItem *p_item, bool p_collapsed)
 
 
 		item->set_collapsed(p_collapsed);
 		item->set_collapsed(p_collapsed);
 
 
-		TreeItem *child = item->get_children();
+		TreeItem *child = item->get_first_child();
 		while (child) {
 		while (child) {
 			to_collapse.push_back(child);
 			to_collapse.push_back(child);
 			child = child->get_next();
 			child = child->get_next();

+ 2 - 2
editor/scene_tree_editor.cpp

@@ -699,7 +699,7 @@ TreeItem *SceneTreeEditor::_find(TreeItem *p_node, const NodePath &p_path) {
 		return p_node;
 		return p_node;
 	}
 	}
 
 
-	TreeItem *children = p_node->get_children();
+	TreeItem *children = p_node->get_first_child();
 	while (children) {
 	while (children) {
 		TreeItem *n = _find(children, p_path);
 		TreeItem *n = _find(children, p_path);
 		if (n) {
 		if (n) {
@@ -883,7 +883,7 @@ void SceneTreeEditor::_update_selection(TreeItem *item) {
 		item->deselect(0);
 		item->deselect(0);
 	}
 	}
 
 
-	TreeItem *c = item->get_children();
+	TreeItem *c = item->get_first_child();
 
 
 	while (c) {
 	while (c) {
 		_update_selection(c);
 		_update_selection(c);

+ 3 - 3
editor/settings_config_dialog.cpp

@@ -235,8 +235,8 @@ void EditorSettingsDialog::_update_shortcuts() {
 	// Before clearing the tree, take note of which categories are collapsed so that this state can be maintained when the tree is repopulated.
 	// Before clearing the tree, take note of which categories are collapsed so that this state can be maintained when the tree is repopulated.
 	Map<String, bool> collapsed;
 	Map<String, bool> collapsed;
 
 
-	if (shortcuts->get_root() && shortcuts->get_root()->get_children()) {
-		for (TreeItem *item = shortcuts->get_root()->get_children(); item; item = item->get_next()) {
+	if (shortcuts->get_root() && shortcuts->get_root()->get_first_child()) {
+		for (TreeItem *item = shortcuts->get_root()->get_first_child(); item; item = item->get_next()) {
 			collapsed[item->get_text(0)] = item->is_collapsed();
 			collapsed[item->get_text(0)] = item->is_collapsed();
 		}
 		}
 	}
 	}
@@ -380,7 +380,7 @@ void EditorSettingsDialog::_update_shortcuts() {
 	// remove sections with no shortcuts
 	// remove sections with no shortcuts
 	for (Map<String, TreeItem *>::Element *E = sections.front(); E; E = E->next()) {
 	for (Map<String, TreeItem *>::Element *E = sections.front(); E; E = E->next()) {
 		TreeItem *section = E->get();
 		TreeItem *section = E->get();
-		if (section->get_children() == nullptr) {
+		if (section->get_first_child() == nullptr) {
 			root->remove_child(section);
 			root->remove_child(section);
 		}
 		}
 	}
 	}

+ 18 - 18
modules/visual_script/visual_script_editor.cpp

@@ -1168,7 +1168,7 @@ void VisualScriptEditor::_member_selected() {
 
 
 	selected = ti->get_metadata(0);
 	selected = ti->get_metadata(0);
 
 
-	if (ti->get_parent() == members->get_root()->get_children()) {
+	if (ti->get_parent() == members->get_root()->get_first_child()) {
 #ifdef OSX_ENABLED
 #ifdef OSX_ENABLED
 		bool held_ctrl = Input::get_singleton()->is_key_pressed(KEY_META);
 		bool held_ctrl = Input::get_singleton()->is_key_pressed(KEY_META);
 #else
 #else
@@ -1214,7 +1214,7 @@ void VisualScriptEditor::_member_edited() {
 
 
 	TreeItem *root = members->get_root();
 	TreeItem *root = members->get_root();
 
 
-	if (ti->get_parent() == root->get_children()) {
+	if (ti->get_parent() == root->get_first_child()) {
 		selected = new_name;
 		selected = new_name;
 
 
 		int node_id = script->get_function_node_id(name);
 		int node_id = script->get_function_node_id(name);
@@ -1255,7 +1255,7 @@ void VisualScriptEditor::_member_edited() {
 		return; // Or crash because it will become invalid.
 		return; // Or crash because it will become invalid.
 	}
 	}
 
 
-	if (ti->get_parent() == root->get_children()->get_next()) {
+	if (ti->get_parent() == root->get_first_child()->get_next()) {
 		selected = new_name;
 		selected = new_name;
 		undo_redo->create_action(TTR("Rename Variable"));
 		undo_redo->create_action(TTR("Rename Variable"));
 		undo_redo->add_do_method(script.ptr(), "rename_variable", name, new_name);
 		undo_redo->add_do_method(script.ptr(), "rename_variable", name, new_name);
@@ -1271,7 +1271,7 @@ void VisualScriptEditor::_member_edited() {
 		return; // Or crash because it will become invalid.
 		return; // Or crash because it will become invalid.
 	}
 	}
 
 
-	if (ti->get_parent() == root->get_children()->get_next()->get_next()) {
+	if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) {
 		selected = new_name;
 		selected = new_name;
 		undo_redo->create_action(TTR("Rename Signal"));
 		undo_redo->create_action(TTR("Rename Signal"));
 		undo_redo->add_do_method(script.ptr(), "rename_custom_signal", name, new_name);
 		undo_redo->add_do_method(script.ptr(), "rename_custom_signal", name, new_name);
@@ -1405,7 +1405,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
 
 
 	if (ti->get_parent() == root) {
 	if (ti->get_parent() == root) {
 		//main buttons
 		//main buttons
-		if (ti == root->get_children()) {
+		if (ti == root->get_first_child()) {
 			// Add function, this one uses menu.
 			// Add function, this one uses menu.
 
 
 			if (p_button == 1) {
 			if (p_button == 1) {
@@ -1442,7 +1442,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
 			return; // Or crash because it will become invalid.
 			return; // Or crash because it will become invalid.
 		}
 		}
 
 
-		if (ti == root->get_children()->get_next()) {
+		if (ti == root->get_first_child()->get_next()) {
 			// Add variable.
 			// Add variable.
 			String name = _validate_name("new_variable");
 			String name = _validate_name("new_variable");
 			selected = name;
 			selected = name;
@@ -1458,7 +1458,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
 			return; // Or crash because it will become invalid.
 			return; // Or crash because it will become invalid.
 		}
 		}
 
 
-		if (ti == root->get_children()->get_next()->get_next()) {
+		if (ti == root->get_first_child()->get_next()->get_next()) {
 			// Add variable.
 			// Add variable.
 			String name = _validate_name("new_signal");
 			String name = _validate_name("new_signal");
 			selected = name;
 			selected = name;
@@ -1473,7 +1473,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
 			undo_redo->commit_action();
 			undo_redo->commit_action();
 			return; // Or crash because it will become invalid.
 			return; // Or crash because it will become invalid.
 		}
 		}
-	} else if (ti->get_parent() == root->get_children()) {
+	} else if (ti->get_parent() == root->get_first_child()) {
 		selected = ti->get_text(0);
 		selected = ti->get_text(0);
 		function_name_edit->set_position(Input::get_singleton()->get_mouse_position() - Vector2(60, -10));
 		function_name_edit->set_position(Input::get_singleton()->get_mouse_position() - Vector2(60, -10));
 		function_name_edit->popup();
 		function_name_edit->popup();
@@ -1841,13 +1841,13 @@ void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) {
 			TreeItem *ti = members->get_selected();
 			TreeItem *ti = members->get_selected();
 			if (ti) {
 			if (ti) {
 				TreeItem *root = members->get_root();
 				TreeItem *root = members->get_root();
-				if (ti->get_parent() == root->get_children()) {
+				if (ti->get_parent() == root->get_first_child()) {
 					member_type = MEMBER_FUNCTION;
 					member_type = MEMBER_FUNCTION;
 				}
 				}
-				if (ti->get_parent() == root->get_children()->get_next()) {
+				if (ti->get_parent() == root->get_first_child()->get_next()) {
 					member_type = MEMBER_VARIABLE;
 					member_type = MEMBER_VARIABLE;
 				}
 				}
-				if (ti->get_parent() == root->get_children()->get_next()->get_next()) {
+				if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) {
 					member_type = MEMBER_SIGNAL;
 					member_type = MEMBER_SIGNAL;
 				}
 				}
 				member_name = ti->get_text(0);
 				member_name = ti->get_text(0);
@@ -1864,7 +1864,7 @@ void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) {
 	Ref<InputEventMouseButton> btn = p_event;
 	Ref<InputEventMouseButton> btn = p_event;
 	if (btn.is_valid() && btn->is_double_click()) {
 	if (btn.is_valid() && btn->is_double_click()) {
 		TreeItem *ti = members->get_selected();
 		TreeItem *ti = members->get_selected();
-		if (ti && ti->get_parent() == members->get_root()->get_children()) { // to check if it's a function
+		if (ti && ti->get_parent() == members->get_root()->get_first_child()) { // to check if it's a function
 			_center_on_node(script->get_function_node_id(ti->get_metadata(0)));
 			_center_on_node(script->get_function_node_id(ti->get_metadata(0)));
 		}
 		}
 	}
 	}
@@ -1946,13 +1946,13 @@ Variant VisualScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_f
 		Dictionary dd;
 		Dictionary dd;
 		TreeItem *root = members->get_root();
 		TreeItem *root = members->get_root();
 
 
-		if (it->get_parent() == root->get_children()) {
+		if (it->get_parent() == root->get_first_child()) {
 			dd["type"] = "visual_script_function_drag";
 			dd["type"] = "visual_script_function_drag";
 			dd["function"] = type;
 			dd["function"] = type;
-		} else if (it->get_parent() == root->get_children()->get_next()) {
+		} else if (it->get_parent() == root->get_first_child()->get_next()) {
 			dd["type"] = "visual_script_variable_drag";
 			dd["type"] = "visual_script_variable_drag";
 			dd["variable"] = type;
 			dd["variable"] = type;
-		} else if (it->get_parent() == root->get_children()->get_next()->get_next()) {
+		} else if (it->get_parent() == root->get_first_child()->get_next()->get_next()) {
 			dd["type"] = "visual_script_signal_drag";
 			dd["type"] = "visual_script_signal_drag";
 			dd["signal"] = type;
 			dd["signal"] = type;
 
 
@@ -4115,7 +4115,7 @@ void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) {
 
 
 	Ref<Texture2D> edit_icon = Control::get_theme_icon("Edit", "EditorIcons");
 	Ref<Texture2D> edit_icon = Control::get_theme_icon("Edit", "EditorIcons");
 
 
-	if (ti->get_parent() == root->get_children()) {
+	if (ti->get_parent() == root->get_first_child()) {
 		member_type = MEMBER_FUNCTION;
 		member_type = MEMBER_FUNCTION;
 		member_name = ti->get_text(0);
 		member_name = ti->get_text(0);
 		member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);
 		member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);
@@ -4125,7 +4125,7 @@ void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) {
 		return;
 		return;
 	}
 	}
 
 
-	if (ti->get_parent() == root->get_children()->get_next()) {
+	if (ti->get_parent() == root->get_first_child()->get_next()) {
 		member_type = MEMBER_VARIABLE;
 		member_type = MEMBER_VARIABLE;
 		member_name = ti->get_text(0);
 		member_name = ti->get_text(0);
 		member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);
 		member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);
@@ -4135,7 +4135,7 @@ void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) {
 		return;
 		return;
 	}
 	}
 
 
-	if (ti->get_parent() == root->get_children()->get_next()->get_next()) {
+	if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) {
 		member_type = MEMBER_SIGNAL;
 		member_type = MEMBER_SIGNAL;
 		member_name = ti->get_text(0);
 		member_name = ti->get_text(0);
 		member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);
 		member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);

+ 3 - 3
modules/visual_script/visual_script_property_selector.cpp

@@ -59,7 +59,7 @@ void VisualScriptPropertySelector::_sbox_input(const Ref<InputEvent> &p_ie) {
 				search_box->accept_event();
 				search_box->accept_event();
 
 
 				TreeItem *root = search_options->get_root();
 				TreeItem *root = search_options->get_root();
-				if (!root->get_children()) {
+				if (!root->get_first_child()) {
 					break;
 					break;
 				}
 				}
 
 
@@ -265,7 +265,7 @@ void VisualScriptPropertySelector::_update_search() {
 			item->set_metadata(2, connecting);
 			item->set_metadata(2, connecting);
 		}
 		}
 
 
-		if (category && category->get_children() == nullptr) {
+		if (category && category->get_first_child() == nullptr) {
 			memdelete(category); //old category was unused
 			memdelete(category); //old category was unused
 		}
 		}
 	}
 	}
@@ -310,7 +310,7 @@ void VisualScriptPropertySelector::_update_search() {
 		found = true;
 		found = true;
 	}
 	}
 
 
-	get_ok_button()->set_disabled(root->get_children() == nullptr);
+	get_ok_button()->set_disabled(root->get_first_child() == nullptr);
 }
 }
 
 
 void VisualScriptPropertySelector::create_visualscript_item(const String &name, TreeItem *const root, const String &search_input, const String &text) {
 void VisualScriptPropertySelector::create_visualscript_item(const String &name, TreeItem *const root, const String &search_input, const String &text) {

+ 2 - 2
scene/gui/file_dialog.cpp

@@ -589,8 +589,8 @@ void FileDialog::update_file_list() {
 		files.pop_front();
 		files.pop_front();
 	}
 	}
 
 
-	if (tree->get_root() && tree->get_root()->get_children() && tree->get_selected() == nullptr) {
-		tree->get_root()->get_children()->select(0);
+	if (tree->get_root() && tree->get_root()->get_first_child() && tree->get_selected() == nullptr) {
+		tree->get_root()->get_first_child()->select(0);
 	}
 	}
 }
 }
 
 

+ 294 - 163
scene/gui/tree.cpp

@@ -47,36 +47,6 @@
 
 
 #include <limits.h>
 #include <limits.h>
 
 
-void TreeItem::move_to_top() {
-	if (!parent || parent->children == this) {
-		return; //already on top
-	}
-	TreeItem *prev = get_prev();
-	prev->next = next;
-	next = parent->children;
-	parent->children = this;
-}
-
-void TreeItem::move_to_bottom() {
-	if (!parent || !next) {
-		return;
-	}
-
-	TreeItem *prev = get_prev();
-	TreeItem *last = next;
-	while (last->next) {
-		last = last->next;
-	}
-
-	if (prev) {
-		prev->next = next;
-	} else {
-		parent->children = next;
-	}
-	last->next = this;
-	next = nullptr;
-}
-
 Size2 TreeItem::Cell::get_icon_size() const {
 Size2 TreeItem::Cell::get_icon_size() const {
 	if (icon.is_null()) {
 	if (icon.is_null()) {
 		return Size2();
 		return Size2();
@@ -118,6 +88,54 @@ void TreeItem::_cell_deselected(int p_cell) {
 	tree->item_deselected(p_cell, this);
 	tree->item_deselected(p_cell, this);
 }
 }
 
 
+void TreeItem::_change_tree(Tree *p_tree) {
+	if (p_tree == tree) {
+		return;
+	}
+
+	TreeItem *c = first_child;
+	while (c) {
+		c->_change_tree(p_tree);
+		c = c->next;
+	}
+
+	if (tree && tree->root == this) {
+		tree->root = nullptr;
+	}
+
+	if (tree && tree->popup_edited_item == this) {
+		tree->popup_edited_item = nullptr;
+		tree->pressing_for_editor = false;
+	}
+
+	if (tree && tree->cache.hover_item == this) {
+		tree->cache.hover_item = nullptr;
+	}
+
+	if (tree && tree->selected_item == this) {
+		tree->selected_item = nullptr;
+	}
+
+	if (tree && tree->drop_mode_over == this) {
+		tree->drop_mode_over = nullptr;
+	}
+
+	if (tree && tree->single_select_defer == this) {
+		tree->single_select_defer = nullptr;
+	}
+
+	if (tree && tree->edited_item == this) {
+		tree->edited_item = nullptr;
+		tree->pressing_for_editor = false;
+	}
+
+	tree = p_tree;
+
+	if (tree) {
+		cells.resize(tree->columns.size());
+	}
+}
+
 /* cell mode */
 /* cell mode */
 void TreeItem::set_cell_mode(int p_column, TreeCellMode p_mode) {
 void TreeItem::set_cell_mode(int p_column, TreeCellMode p_mode) {
 	ERR_FAIL_INDEX(p_column, cells.size());
 	ERR_FAIL_INDEX(p_column, cells.size());
@@ -427,20 +445,74 @@ int TreeItem::get_custom_minimum_height() const {
 	return custom_min_height;
 	return custom_min_height;
 }
 }
 
 
+/* Item manipulation */
+
+TreeItem *TreeItem::create_child(int p_idx) {
+	TreeItem *ti = memnew(TreeItem(tree));
+	if (tree) {
+		ti->cells.resize(tree->columns.size());
+	}
+
+	TreeItem *l_prev = nullptr;
+	TreeItem *c = first_child;
+	int idx = 0;
+
+	while (c) {
+		if (idx++ == p_idx) {
+			c->prev = ti;
+			ti->next = c;
+			break;
+		}
+		l_prev = c;
+		c = c->next;
+	}
+
+	if (l_prev) {
+		l_prev->next = ti;
+		ti->prev = l_prev;
+		if (!children_cache.is_empty()) {
+			if (ti->next) {
+				children_cache.insert(p_idx, ti);
+			} else {
+				children_cache.append(ti);
+			}
+		}
+	} else {
+		first_child = ti;
+		if (!children_cache.is_empty()) {
+			children_cache.insert(0, ti);
+		}
+	}
+
+	ti->parent = this;
+
+	return ti;
+}
+
+Tree *TreeItem::get_tree() {
+	return tree;
+}
+
 TreeItem *TreeItem::get_next() {
 TreeItem *TreeItem::get_next() {
 	return next;
 	return next;
 }
 }
 
 
 TreeItem *TreeItem::get_prev() {
 TreeItem *TreeItem::get_prev() {
-	if (!parent || parent->children == this) {
-		return nullptr;
+	if (prev) {
+		return prev;
 	}
 	}
 
 
-	TreeItem *prev = parent->children;
-	while (prev && prev->next != this) {
-		prev = prev->next;
+	if (!parent || parent->first_child == this) {
+		return nullptr;
+	}
+	// This is an edge case
+	TreeItem *l_prev = parent->first_child;
+	while (l_prev && l_prev->next != this) {
+		l_prev = l_prev->next;
 	}
 	}
 
 
+	prev = l_prev;
+
 	return prev;
 	return prev;
 }
 }
 
 
@@ -448,8 +520,8 @@ TreeItem *TreeItem::get_parent() {
 	return parent;
 	return parent;
 }
 }
 
 
-TreeItem *TreeItem::get_children() {
-	return children;
+TreeItem *TreeItem::get_first_child() {
+	return first_child;
 }
 }
 
 
 TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
 TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
@@ -475,10 +547,10 @@ TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
 		}
 		}
 	} else {
 	} else {
 		current = prev;
 		current = prev;
-		while (!current->collapsed && current->children) {
+		while (!current->collapsed && current->first_child) {
 			//go to the very end
 			//go to the very end
 
 
-			current = current->children;
+			current = current->first_child;
 			while (current->next) {
 			while (current->next) {
 				current = current->next;
 				current = current->next;
 			}
 			}
@@ -491,8 +563,8 @@ TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
 TreeItem *TreeItem::get_next_visible(bool p_wrap) {
 TreeItem *TreeItem::get_next_visible(bool p_wrap) {
 	TreeItem *current = this;
 	TreeItem *current = this;
 
 
-	if (!current->collapsed && current->children) {
-		current = current->children;
+	if (!current->collapsed && current->first_child) {
+		current = current->first_child;
 
 
 	} else if (current->next) {
 	} else if (current->next) {
 		current = current->next;
 		current = current->next;
@@ -515,24 +587,136 @@ TreeItem *TreeItem::get_next_visible(bool p_wrap) {
 	return current;
 	return current;
 }
 }
 
 
-void TreeItem::remove_child(TreeItem *p_item) {
+TreeItem *TreeItem::get_child(int p_idx) {
+	_create_children_cache();
+	ERR_FAIL_INDEX_V(p_idx, children_cache.size(), nullptr);
+	return children_cache.get(p_idx);
+}
+
+int TreeItem::get_child_count() {
+	_create_children_cache();
+	return children_cache.size();
+}
+
+Array TreeItem::get_children() {
+	int size = get_child_count();
+	Array arr;
+	arr.resize(size);
+	for (int i = 0; i < size; i++) {
+		arr[i] = children_cache[i];
+	}
+
+	return arr;
+}
+
+int TreeItem::get_index() {
+	int idx = 0;
+	TreeItem *c = this;
+
+	while (c) {
+		c = c->get_prev();
+		idx++;
+	}
+	return idx - 1;
+}
+
+void TreeItem::move_before(TreeItem *p_item) {
 	ERR_FAIL_NULL(p_item);
 	ERR_FAIL_NULL(p_item);
-	TreeItem **c = &children;
+	ERR_FAIL_COND(is_root);
+	ERR_FAIL_COND(!p_item->parent);
 
 
-	while (*c) {
-		if ((*c) == p_item) {
-			TreeItem *aux = *c;
+	if (p_item == this) {
+		return;
+	}
 
 
-			*c = (*c)->next;
+	TreeItem *p = p_item->parent;
+	while (p) {
+		ERR_FAIL_COND_MSG(p == this, "Can't move to a descendant");
+		p = p->parent;
+	}
 
 
-			aux->parent = nullptr;
-			return;
-		}
+	Tree *old_tree = tree;
+	_unlink_from_tree();
+	_change_tree(p_item->tree);
+
+	parent = p_item->parent;
+
+	TreeItem *item_prev = p_item->get_prev();
+	if (item_prev) {
+		item_prev->next = this;
+		parent->children_cache.clear();
+	} else {
+		parent->first_child = this;
+		parent->children_cache.insert(0, this);
+	}
+
+	prev = item_prev;
+	next = p_item;
+	p_item->prev = this;
+
+	if (old_tree && old_tree != tree) {
+		old_tree->update();
+	}
+
+	if (tree) {
+		tree->update();
+	}
+}
+
+void TreeItem::move_after(TreeItem *p_item) {
+	ERR_FAIL_NULL(p_item);
+	ERR_FAIL_COND(is_root);
+	ERR_FAIL_COND(!p_item->parent);
+
+	if (p_item == this) {
+		return;
+	}
 
 
-		c = &(*c)->next;
+	TreeItem *p = p_item->parent;
+	while (p) {
+		ERR_FAIL_COND_MSG(p == this, "Can't move to a descendant");
+		p = p->parent;
 	}
 	}
 
 
-	ERR_FAIL();
+	Tree *old_tree = tree;
+	_unlink_from_tree();
+	_change_tree(p_item->tree);
+
+	if (p_item->next) {
+		p_item->next->prev = this;
+	}
+	parent = p_item->parent;
+	prev = p_item;
+	next = p_item->next;
+	p_item->next = this;
+
+	if (next) {
+		parent->children_cache.clear();
+	} else {
+		parent->children_cache.append(this);
+	}
+
+	if (old_tree && old_tree != tree) {
+		old_tree->update();
+	}
+
+	if (tree) {
+		tree->update();
+	}
+}
+
+void TreeItem::remove_child(TreeItem *p_item) {
+	ERR_FAIL_NULL(p_item);
+	ERR_FAIL_COND(p_item->parent != this);
+
+	p_item->_unlink_from_tree();
+	p_item->prev = nullptr;
+	p_item->next = nullptr;
+	p_item->parent = nullptr;
+
+	if (tree) {
+		tree->update();
+	}
 }
 }
 
 
 void TreeItem::set_selectable(int p_column, bool p_selectable) {
 void TreeItem::set_selectable(int p_column, bool p_selectable) {
@@ -785,7 +969,7 @@ void recursive_call_aux(TreeItem *p_item, const StringName &p_method, const Vari
 		return;
 		return;
 	}
 	}
 	p_item->call(p_method, p_args, p_argcount, r_error);
 	p_item->call(p_method, p_args, p_argcount, r_error);
-	TreeItem *c = p_item->get_children();
+	TreeItem *c = p_item->get_first_child();
 	while (c) {
 	while (c) {
 		recursive_call_aux(c, p_method, p_args, p_argcount, r_error);
 		recursive_call_aux(c, p_method, p_args, p_argcount, r_error);
 		c = c->get_next();
 		c = c->get_next();
@@ -855,16 +1039,6 @@ void TreeItem::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_custom_minimum_height", "height"), &TreeItem::set_custom_minimum_height);
 	ClassDB::bind_method(D_METHOD("set_custom_minimum_height", "height"), &TreeItem::set_custom_minimum_height);
 	ClassDB::bind_method(D_METHOD("get_custom_minimum_height"), &TreeItem::get_custom_minimum_height);
 	ClassDB::bind_method(D_METHOD("get_custom_minimum_height"), &TreeItem::get_custom_minimum_height);
 
 
-	ClassDB::bind_method(D_METHOD("get_next"), &TreeItem::get_next);
-	ClassDB::bind_method(D_METHOD("get_prev"), &TreeItem::get_prev);
-	ClassDB::bind_method(D_METHOD("get_parent"), &TreeItem::get_parent);
-	ClassDB::bind_method(D_METHOD("get_children"), &TreeItem::get_children);
-
-	ClassDB::bind_method(D_METHOD("get_next_visible", "wrap"), &TreeItem::get_next_visible, DEFVAL(false));
-	ClassDB::bind_method(D_METHOD("get_prev_visible", "wrap"), &TreeItem::get_prev_visible, DEFVAL(false));
-
-	ClassDB::bind_method(D_METHOD("remove_child", "child"), &TreeItem::_remove_child);
-
 	ClassDB::bind_method(D_METHOD("set_selectable", "column", "selectable"), &TreeItem::set_selectable);
 	ClassDB::bind_method(D_METHOD("set_selectable", "column", "selectable"), &TreeItem::set_selectable);
 	ClassDB::bind_method(D_METHOD("is_selectable", "column"), &TreeItem::is_selectable);
 	ClassDB::bind_method(D_METHOD("is_selectable", "column"), &TreeItem::is_selectable);
 
 
@@ -895,19 +1069,38 @@ void TreeItem::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_button_disabled", "column", "button_idx", "disabled"), &TreeItem::set_button_disabled);
 	ClassDB::bind_method(D_METHOD("set_button_disabled", "column", "button_idx", "disabled"), &TreeItem::set_button_disabled);
 	ClassDB::bind_method(D_METHOD("is_button_disabled", "column", "button_idx"), &TreeItem::is_button_disabled);
 	ClassDB::bind_method(D_METHOD("is_button_disabled", "column", "button_idx"), &TreeItem::is_button_disabled);
 
 
-	ClassDB::bind_method(D_METHOD("set_expand_right", "column", "enable"), &TreeItem::set_expand_right);
-	ClassDB::bind_method(D_METHOD("get_expand_right", "column"), &TreeItem::get_expand_right);
-
 	ClassDB::bind_method(D_METHOD("set_tooltip", "column", "tooltip"), &TreeItem::set_tooltip);
 	ClassDB::bind_method(D_METHOD("set_tooltip", "column", "tooltip"), &TreeItem::set_tooltip);
 	ClassDB::bind_method(D_METHOD("get_tooltip", "column"), &TreeItem::get_tooltip);
 	ClassDB::bind_method(D_METHOD("get_tooltip", "column"), &TreeItem::get_tooltip);
 	ClassDB::bind_method(D_METHOD("set_text_align", "column", "text_align"), &TreeItem::set_text_align);
 	ClassDB::bind_method(D_METHOD("set_text_align", "column", "text_align"), &TreeItem::set_text_align);
 	ClassDB::bind_method(D_METHOD("get_text_align", "column"), &TreeItem::get_text_align);
 	ClassDB::bind_method(D_METHOD("get_text_align", "column"), &TreeItem::get_text_align);
-	ClassDB::bind_method(D_METHOD("move_to_top"), &TreeItem::move_to_top);
-	ClassDB::bind_method(D_METHOD("move_to_bottom"), &TreeItem::move_to_bottom);
+
+	ClassDB::bind_method(D_METHOD("set_expand_right", "column", "enable"), &TreeItem::set_expand_right);
+	ClassDB::bind_method(D_METHOD("get_expand_right", "column"), &TreeItem::get_expand_right);
 
 
 	ClassDB::bind_method(D_METHOD("set_disable_folding", "disable"), &TreeItem::set_disable_folding);
 	ClassDB::bind_method(D_METHOD("set_disable_folding", "disable"), &TreeItem::set_disable_folding);
 	ClassDB::bind_method(D_METHOD("is_folding_disabled"), &TreeItem::is_folding_disabled);
 	ClassDB::bind_method(D_METHOD("is_folding_disabled"), &TreeItem::is_folding_disabled);
 
 
+	ClassDB::bind_method(D_METHOD("create_child", "idx"), &TreeItem::create_child, DEFVAL(-1));
+	ClassDB::bind_method(D_METHOD("get_tree"), &TreeItem::get_tree);
+
+	ClassDB::bind_method(D_METHOD("get_next"), &TreeItem::get_next);
+	ClassDB::bind_method(D_METHOD("get_prev"), &TreeItem::get_prev);
+	ClassDB::bind_method(D_METHOD("get_parent"), &TreeItem::get_parent);
+	ClassDB::bind_method(D_METHOD("get_first_child"), &TreeItem::get_first_child);
+
+	ClassDB::bind_method(D_METHOD("get_next_visible", "wrap"), &TreeItem::get_next_visible, DEFVAL(false));
+	ClassDB::bind_method(D_METHOD("get_prev_visible", "wrap"), &TreeItem::get_prev_visible, DEFVAL(false));
+
+	ClassDB::bind_method(D_METHOD("get_child", "idx"), &TreeItem::get_child);
+	ClassDB::bind_method(D_METHOD("get_child_count"), &TreeItem::get_child_count);
+	ClassDB::bind_method(D_METHOD("get_children"), &TreeItem::get_children);
+	ClassDB::bind_method(D_METHOD("get_index"), &TreeItem::get_index);
+
+	ClassDB::bind_method(D_METHOD("move_before", "item"), &TreeItem::_move_before);
+	ClassDB::bind_method(D_METHOD("move_after", "item"), &TreeItem::_move_after);
+
+	ClassDB::bind_method(D_METHOD("remove_child", "child"), &TreeItem::_remove_child);
+
 	{
 	{
 		MethodInfo mi;
 		MethodInfo mi;
 		mi.name = "call_recursive";
 		mi.name = "call_recursive";
@@ -932,7 +1125,7 @@ void TreeItem::_bind_methods() {
 }
 }
 
 
 void TreeItem::clear_children() {
 void TreeItem::clear_children() {
-	TreeItem *c = children;
+	TreeItem *c = first_child;
 	while (c) {
 	while (c) {
 		TreeItem *aux = c;
 		TreeItem *aux = c;
 		c = c->get_next();
 		c = c->get_next();
@@ -940,56 +1133,18 @@ void TreeItem::clear_children() {
 		memdelete(aux);
 		memdelete(aux);
 	}
 	}
 
 
-	children = nullptr;
+	first_child = nullptr;
 };
 };
 
 
 TreeItem::TreeItem(Tree *p_tree) {
 TreeItem::TreeItem(Tree *p_tree) {
 	tree = p_tree;
 	tree = p_tree;
-	collapsed = false;
-	disable_folding = false;
-	custom_min_height = 0;
-
-	parent = nullptr; // parent item
-	next = nullptr; // next in list
-	children = nullptr; //child items
 }
 }
 
 
 TreeItem::~TreeItem() {
 TreeItem::~TreeItem() {
+	_unlink_from_tree();
+	prev = nullptr;
 	clear_children();
 	clear_children();
-
-	if (parent) {
-		parent->remove_child(this);
-	}
-
-	if (tree && tree->root == this) {
-		tree->root = nullptr;
-	}
-
-	if (tree && tree->popup_edited_item == this) {
-		tree->popup_edited_item = nullptr;
-		tree->pressing_for_editor = false;
-	}
-
-	if (tree && tree->cache.hover_item == this) {
-		tree->cache.hover_item = nullptr;
-	}
-
-	if (tree && tree->selected_item == this) {
-		tree->selected_item = nullptr;
-	}
-
-	if (tree && tree->drop_mode_over == this) {
-		tree->drop_mode_over = nullptr;
-	}
-
-	if (tree && tree->single_select_defer == this) {
-		tree->single_select_defer = nullptr;
-	}
-
-	if (tree && tree->edited_item == this) {
-		tree->edited_item = nullptr;
-		tree->pressing_for_editor = false;
-	}
+	_change_tree(nullptr);
 }
 }
 
 
 /**********************************************/
 /**********************************************/
@@ -1116,7 +1271,7 @@ int Tree::get_item_height(TreeItem *p_item) const {
 
 
 	if (!p_item->collapsed) { /* if not collapsed, check the children */
 	if (!p_item->collapsed) { /* if not collapsed, check the children */
 
 
-		TreeItem *c = p_item->children;
+		TreeItem *c = p_item->first_child;
 
 
 		while (c) {
 		while (c) {
 			height += get_item_height(c);
 			height += get_item_height(c);
@@ -1263,7 +1418,7 @@ void Tree::update_item_cache(TreeItem *p_item) {
 		update_item_cell(p_item, i);
 		update_item_cell(p_item, i);
 	}
 	}
 
 
-	TreeItem *c = p_item->children;
+	TreeItem *c = p_item->first_child;
 	while (c) {
 	while (c) {
 		update_item_cache(c);
 		update_item_cache(c);
 		c = c->next;
 		c = c->next;
@@ -1430,7 +1585,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
 
 
 			if (drop_mode_flags && drop_mode_over == p_item) {
 			if (drop_mode_flags && drop_mode_over == p_item) {
 				Rect2 r = cell_rect;
 				Rect2 r = cell_rect;
-				bool has_parent = p_item->get_children() != nullptr;
+				bool has_parent = p_item->get_first_child() != nullptr;
 				if (rtl) {
 				if (rtl) {
 					r.position.x = get_size().width - r.position.x - r.size.x;
 					r.position.x = get_size().width - r.position.x - r.size.x;
 				}
 				}
@@ -1626,7 +1781,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
 			}
 			}
 		}
 		}
 
 
-		if (!p_item->disable_folding && !hide_folding && p_item->children) { //has children, draw the guide box
+		if (!p_item->disable_folding && !hide_folding && p_item->first_child) { //has children, draw the guide box
 
 
 			Ref<Texture2D> arrow;
 			Ref<Texture2D> arrow;
 
 
@@ -1656,7 +1811,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
 
 
 	if (!p_item->collapsed) { /* if not collapsed, check the children */
 	if (!p_item->collapsed) { /* if not collapsed, check the children */
 
 
-		TreeItem *c = p_item->children;
+		TreeItem *c = p_item->first_child;
 
 
 		int prev_ofs = children_pos.y - cache.offset.y + p_draw_ofs.y;
 		int prev_ofs = children_pos.y - cache.offset.y + p_draw_ofs.y;
 
 
@@ -1666,7 +1821,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
 				int parent_ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin);
 				int parent_ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin);
 				Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs;
 				Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs;
 
 
-				if (c->get_children() != nullptr) {
+				if (c->get_first_child() != nullptr) {
 					root_pos -= Point2i(cache.arrow->get_width(), 0);
 					root_pos -= Point2i(cache.arrow->get_width(), 0);
 				}
 				}
 
 
@@ -1723,8 +1878,8 @@ int Tree::_count_selected_items(TreeItem *p_from) const {
 		}
 		}
 	}
 	}
 
 
-	if (p_from->get_children()) {
-		count += _count_selected_items(p_from->get_children());
+	if (p_from->get_first_child()) {
+		count += _count_selected_items(p_from->get_first_child());
 	}
 	}
 
 
 	if (p_from->get_next()) {
 	if (p_from->get_next()) {
@@ -1812,7 +1967,7 @@ void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_c
 		*r_in_range = false;
 		*r_in_range = false;
 	}
 	}
 
 
-	TreeItem *c = p_current->children;
+	TreeItem *c = p_current->first_child;
 
 
 	while (c) {
 	while (c) {
 		select_single_item(p_selected, c, p_col, p_prev, r_in_range, p_current->is_collapsed() || p_force_deselect);
 		select_single_item(p_selected, c, p_col, p_prev, r_in_range, p_current->is_collapsed() || p_force_deselect);
@@ -1839,7 +1994,6 @@ void Tree::_range_click_timeout() {
 		click_handled = false;
 		click_handled = false;
 		Ref<InputEventMouseButton> mb;
 		Ref<InputEventMouseButton> mb;
 		mb.instance();
 		mb.instance();
-		;
 
 
 		propagate_mouse_activated = false; // done from outside, so signal handler can't clear the tree in the middle of emit (which is a common case)
 		propagate_mouse_activated = false; // done from outside, so signal handler can't clear the tree in the middle of emit (which is a common case)
 		blocked++;
 		blocked++;
@@ -1879,7 +2033,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
 		}
 		}
 
 
 		if (!p_item->disable_folding && !hide_folding && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + cache.item_margin))) {
 		if (!p_item->disable_folding && !hide_folding && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + cache.item_margin))) {
-			if (p_item->children) {
+			if (p_item->first_child) {
 				p_item->set_collapsed(!p_item->is_collapsed());
 				p_item->set_collapsed(!p_item->is_collapsed());
 			}
 			}
 
 
@@ -1926,7 +2080,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
 			x -= cache.hseparation;
 			x -= cache.hseparation;
 		}
 		}
 
 
-		if (!p_item->disable_folding && !hide_folding && !p_item->cells[col].editable && !p_item->cells[col].selectable && p_item->get_children()) {
+		if (!p_item->disable_folding && !hide_folding && !p_item->cells[col].editable && !p_item->cells[col].selectable && p_item->get_first_child()) {
 			p_item->set_collapsed(!p_item->is_collapsed());
 			p_item->set_collapsed(!p_item->is_collapsed());
 			return -1; //collapse/uncollapse because nothing can be done with item
 			return -1; //collapse/uncollapse because nothing can be done with item
 		}
 		}
@@ -2164,7 +2318,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
 
 
 		if (!p_item->collapsed) { /* if not collapsed, check the children */
 		if (!p_item->collapsed) { /* if not collapsed, check the children */
 
 
-			TreeItem *c = p_item->children;
+			TreeItem *c = p_item->first_child;
 
 
 			while (c) {
 			while (c) {
 				int child_h = propagate_mouse_event(new_pos, x_ofs, y_ofs, p_double_click, c, p_button, p_mod);
 				int child_h = propagate_mouse_event(new_pos, x_ofs, y_ofs, p_double_click, c, p_button, p_mod);
@@ -2270,7 +2424,7 @@ void Tree::popup_select(int p_option) {
 
 
 void Tree::_go_left() {
 void Tree::_go_left() {
 	if (selected_col == 0) {
 	if (selected_col == 0) {
-		if (selected_item->get_children() != nullptr && !selected_item->is_collapsed()) {
+		if (selected_item->get_first_child() != nullptr && !selected_item->is_collapsed()) {
 			selected_item->set_collapsed(true);
 			selected_item->set_collapsed(true);
 		} else {
 		} else {
 			if (columns.size() == 1) { // goto parent with one column
 			if (columns.size() == 1) { // goto parent with one column
@@ -2298,7 +2452,7 @@ void Tree::_go_left() {
 
 
 void Tree::_go_right() {
 void Tree::_go_right() {
 	if (selected_col == (columns.size() - 1)) {
 	if (selected_col == (columns.size() - 1)) {
-		if (selected_item->get_children() != nullptr && selected_item->is_collapsed()) {
+		if (selected_item->get_first_child() != nullptr && selected_item->is_collapsed()) {
 			selected_item->set_collapsed(false);
 			selected_item->set_collapsed(false);
 		} else if (selected_item->get_next_visible()) {
 		} else if (selected_item->get_next_visible()) {
 			selected_col = 0;
 			selected_col = 0;
@@ -2417,7 +2571,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
 		}
 		}
 		if (k.is_valid() && k->is_alt_pressed()) {
 		if (k.is_valid() && k->is_alt_pressed()) {
 			selected_item->set_collapsed(false);
 			selected_item->set_collapsed(false);
-			TreeItem *next = selected_item->get_children();
+			TreeItem *next = selected_item->get_first_child();
 			while (next && next != selected_item->next) {
 			while (next && next != selected_item->next) {
 				next->set_collapsed(false);
 				next->set_collapsed(false);
 				next = next->get_next_visible();
 				next = next->get_next_visible();
@@ -2436,7 +2590,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
 
 
 		if (k.is_valid() && k->is_alt_pressed()) {
 		if (k.is_valid() && k->is_alt_pressed()) {
 			selected_item->set_collapsed(true);
 			selected_item->set_collapsed(true);
-			TreeItem *next = selected_item->get_children();
+			TreeItem *next = selected_item->get_first_child();
 			while (next && next != selected_item->next) {
 			while (next && next != selected_item->next) {
 				next->set_collapsed(true);
 				next->set_collapsed(true);
 				next = next->get_next_visible();
 				next = next->get_next_visible();
@@ -2834,7 +2988,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
 						break;
 						break;
 					}
 					}
 				}
 				}
-				if (!root || (!root->get_children() && hide_root)) {
+				if (!root || (!root->get_first_child() && hide_root)) {
 					if (b->get_button_index() == MOUSE_BUTTON_RIGHT && allow_rmb_select) {
 					if (b->get_button_index() == MOUSE_BUTTON_RIGHT && allow_rmb_select) {
 						emit_signal("empty_tree_rmb_selected", get_local_mouse_position());
 						emit_signal("empty_tree_rmb_selected", get_local_mouse_position());
 					}
 					}
@@ -3269,38 +3423,15 @@ TreeItem *Tree::create_item(TreeItem *p_parent, int p_idx) {
 	TreeItem *ti = nullptr;
 	TreeItem *ti = nullptr;
 
 
 	if (p_parent) {
 	if (p_parent) {
-		// Append or insert a new item to the given parent.
-		ti = memnew(TreeItem(this));
-		ERR_FAIL_COND_V(!ti, nullptr);
-		ti->cells.resize(columns.size());
-
-		TreeItem *prev = nullptr;
-		TreeItem *c = p_parent->children;
-		int idx = 0;
-
-		while (c) {
-			if (idx++ == p_idx) {
-				ti->next = c;
-				break;
-			}
-			prev = c;
-			c = c->next;
-		}
-
-		if (prev) {
-			prev->next = ti;
-		} else {
-			p_parent->children = ti;
-		}
-		ti->parent = p_parent;
-
+		ERR_FAIL_COND_V_MSG(p_parent->tree != this, nullptr, "A different tree owns the given parent");
+		ti = p_parent->create_child(p_idx);
 	} else {
 	} else {
 		if (!root) {
 		if (!root) {
 			// No root exists, make the given item the new root.
 			// No root exists, make the given item the new root.
 			ti = memnew(TreeItem(this));
 			ti = memnew(TreeItem(this));
 			ERR_FAIL_COND_V(!ti, nullptr);
 			ERR_FAIL_COND_V(!ti, nullptr);
 			ti->cells.resize(columns.size());
 			ti->cells.resize(columns.size());
-
+			ti->is_root = true;
 			root = ti;
 			root = ti;
 		} else {
 		} else {
 			// Root exists, append or insert to root.
 			// Root exists, append or insert to root.
@@ -3321,8 +3452,8 @@ TreeItem *Tree::get_last_item() {
 	while (last) {
 	while (last) {
 		if (last->next) {
 		if (last->next) {
 			last = last->next;
 			last = last->next;
-		} else if (last->children) {
-			last = last->children;
+		} else if (last->first_child) {
+			last = last->first_child;
 		} else {
 		} else {
 			break;
 			break;
 		}
 		}
@@ -3491,8 +3622,8 @@ TreeItem *Tree::get_next_selected(TreeItem *p_item) {
 		if (!p_item) {
 		if (!p_item) {
 			p_item = root;
 			p_item = root;
 		} else {
 		} else {
-			if (p_item->children) {
-				p_item = p_item->children;
+			if (p_item->first_child) {
+				p_item = p_item->first_child;
 
 
 			} else if (p_item->next) {
 			} else if (p_item->next) {
 				p_item = p_item->next;
 				p_item = p_item->next;
@@ -3561,7 +3692,7 @@ int Tree::get_column_width(int p_column) const {
 void Tree::propagate_set_columns(TreeItem *p_item) {
 void Tree::propagate_set_columns(TreeItem *p_item) {
 	p_item->cells.resize(columns.size());
 	p_item->cells.resize(columns.size());
 
 
-	TreeItem *c = p_item->get_children();
+	TreeItem *c = p_item->get_first_child();
 	while (c) {
 	while (c) {
 		propagate_set_columns(c);
 		propagate_set_columns(c);
 		c = c->next;
 		c = c->next;
@@ -3611,8 +3742,8 @@ int Tree::get_item_offset(TreeItem *p_item) const {
 			ofs += cache.vseparation;
 			ofs += cache.vseparation;
 		}
 		}
 
 
-		if (it->children && !it->collapsed) {
-			it = it->children;
+		if (it->first_child && !it->collapsed) {
+			it = it->first_child;
 
 
 		} else if (it->next) {
 		} else if (it->next) {
 			it = it->next;
 			it = it->next;
@@ -3935,7 +4066,7 @@ TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_
 		return nullptr; // do not try children, it's collapsed
 		return nullptr; // do not try children, it's collapsed
 	}
 	}
 
 
-	TreeItem *n = p_item->get_children();
+	TreeItem *n = p_item->get_first_child();
 	while (n) {
 	while (n) {
 		int ch;
 		int ch;
 		TreeItem *r = _find_item_at_pos(n, pos, r_column, ch, section);
 		TreeItem *r = _find_item_at_pos(n, pos, r_column, ch, section);

+ 76 - 23
scene/gui/tree.h

@@ -122,14 +122,18 @@ private:
 
 
 	Vector<Cell> cells;
 	Vector<Cell> cells;
 
 
-	bool collapsed; // won't show children
-	bool disable_folding;
-	int custom_min_height;
+	bool collapsed = false; // won't show children
+	bool disable_folding = false;
+	int custom_min_height = 0;
 
 
-	TreeItem *parent; // parent item
-	TreeItem *next; // next in list
-	TreeItem *children; //child items
-	Tree *tree; //tree (for reference)
+	TreeItem *parent = nullptr; // parent item
+	TreeItem *prev = nullptr; // previous in list
+	TreeItem *next = nullptr; // next in list
+	TreeItem *first_child = nullptr;
+
+	Vector<TreeItem *> children_cache;
+	bool is_root = false; // for tree root
+	Tree *tree; // tree (for reference)
 
 
 	TreeItem(Tree *p_tree);
 	TreeItem(Tree *p_tree);
 
 
@@ -138,9 +142,40 @@ private:
 	void _cell_selected(int p_cell);
 	void _cell_selected(int p_cell);
 	void _cell_deselected(int p_cell);
 	void _cell_deselected(int p_cell);
 
 
+	void _change_tree(Tree *p_tree);
+
+	_FORCE_INLINE_ void _create_children_cache() {
+		if (children_cache.is_empty()) {
+			TreeItem *c = first_child;
+			while (c) {
+				children_cache.append(c);
+				c = c->next;
+			}
+		}
+	}
+
+	_FORCE_INLINE_ void _unlink_from_tree() {
+		TreeItem *p = get_prev();
+		if (p) {
+			p->next = next;
+		}
+		if (next) {
+			next->prev = p;
+		}
+		if (parent) {
+			if (!parent->children_cache.is_empty()) {
+				parent->children_cache.remove(get_index());
+			}
+			if (parent->first_child == this) {
+				parent->first_child = next;
+			}
+		}
+	}
+
 protected:
 protected:
 	static void _bind_methods();
 	static void _bind_methods();
-	//bind helpers
+
+	// Bind helpers
 	Dictionary _get_range_config(int p_column) {
 	Dictionary _get_range_config(int p_column) {
 		Dictionary d;
 		Dictionary d;
 		double min = 0.0, max = 0.0, step = 0.0;
 		double min = 0.0, max = 0.0, step = 0.0;
@@ -156,6 +191,13 @@ protected:
 		remove_child(Object::cast_to<TreeItem>(p_child));
 		remove_child(Object::cast_to<TreeItem>(p_child));
 	}
 	}
 
 
+	void _move_before(Object *p_item) {
+		move_before(Object::cast_to<TreeItem>(p_item));
+	}
+	void _move_after(Object *p_item) {
+		move_after(Object::cast_to<TreeItem>(p_item));
+	}
+
 	Variant _call_recursive_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
 	Variant _call_recursive_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
 
 
 public:
 public:
@@ -234,16 +276,6 @@ public:
 	void set_custom_minimum_height(int p_height);
 	void set_custom_minimum_height(int p_height);
 	int get_custom_minimum_height() const;
 	int get_custom_minimum_height() const;
 
 
-	TreeItem *get_prev();
-	TreeItem *get_next();
-	TreeItem *get_parent();
-	TreeItem *get_children();
-
-	TreeItem *get_prev_visible(bool p_wrap = false);
-	TreeItem *get_next_visible(bool p_wrap = false);
-
-	void remove_child(TreeItem *p_item);
-
 	void set_selectable(int p_column, bool p_selectable);
 	void set_selectable(int p_column, bool p_selectable);
 	bool is_selectable(int p_column) const;
 	bool is_selectable(int p_column) const;
 
 
@@ -269,22 +301,43 @@ public:
 	void set_tooltip(int p_column, const String &p_tooltip);
 	void set_tooltip(int p_column, const String &p_tooltip);
 	String get_tooltip(int p_column) const;
 	String get_tooltip(int p_column) const;
 
 
-	void clear_children();
-
 	void set_text_align(int p_column, TextAlign p_align);
 	void set_text_align(int p_column, TextAlign p_align);
 	TextAlign get_text_align(int p_column) const;
 	TextAlign get_text_align(int p_column) const;
 
 
 	void set_expand_right(int p_column, bool p_enable);
 	void set_expand_right(int p_column, bool p_enable);
 	bool get_expand_right(int p_column) const;
 	bool get_expand_right(int p_column) const;
 
 
-	void move_to_top();
-	void move_to_bottom();
-
 	void set_disable_folding(bool p_disable);
 	void set_disable_folding(bool p_disable);
 	bool is_folding_disabled() const;
 	bool is_folding_disabled() const;
 
 
+	/* Item manipulation */
+
+	TreeItem *create_child(int p_idx = -1);
+
+	Tree *get_tree();
+
+	TreeItem *get_prev();
+	TreeItem *get_next();
+	TreeItem *get_parent();
+	TreeItem *get_first_child();
+
+	TreeItem *get_prev_visible(bool p_wrap = false);
+	TreeItem *get_next_visible(bool p_wrap = false);
+
+	TreeItem *get_child(int p_idx);
+	int get_child_count();
+	Array get_children();
+	int get_index();
+
+	void move_before(TreeItem *p_item);
+	void move_after(TreeItem *p_item);
+
+	void remove_child(TreeItem *p_item);
+
 	void call_recursive(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
 	void call_recursive(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
 
 
+	void clear_children();
+
 	~TreeItem();
 	~TreeItem();
 };
 };