diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp index e89912d5bc68..98fce1a4c320 100644 --- a/editor/gui/scene_tree_editor.cpp +++ b/editor/gui/scene_tree_editor.cpp @@ -217,7 +217,7 @@ void SceneTreeEditor::_toggle_visible(Node *p_node) { } } -void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { +void SceneTreeEditor::_update_nodes(Node *p_node, TreeItem *p_parent) { if (!p_node) { return; } @@ -238,34 +238,124 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { part_of_subscene = p_node != get_scene_node() && get_scene_node()->get_scene_inherited_state().is_valid() && get_scene_node()->get_scene_inherited_state()->find_node_by_path(get_scene_node()->get_path_to(p_node)) >= 0; } - TreeItem *item = tree->create_item(p_parent); + TreeItem *item; + int node_index = p_node->get_index(false); + HashMap::Iterator I = node_cache.find(p_node); - item->set_text(0, p_node->get_name()); - item->set_text_overrun_behavior(0, TextServer::OVERRUN_NO_TRIMMING); - if (can_rename && !part_of_subscene) { - item->set_editable(0, true); + if (I) { + item = I->value.item; + if (marked.has(p_node)) { + if (!I->value.marked) { + I->value.marked = true; + I->value.dirty = true; + } + } else { + if (I->value.marked) { + I->value.marked = false; + I->value.dirty = true; + } + } + } else { + // We don't set the node_index cache here. As undo/redo might've just recreated this. + item = tree->create_item(p_parent); + CachedNode cached_node; + cached_node.item = item; + I = node_cache.insert(p_node, cached_node); + } + + // Do a quick check to see if we are where we expect to be. + // We can't only do this when we're dirty as moving one node will necessarily move our siblings. + if (p_parent && I->value.index != node_index) { + if (node_index < p_parent->get_child_count()) { + TreeItem *new_neigbor = p_parent->get_child(node_index); + + if (new_neigbor != item) { + if (node_index == p_parent->get_child_count()) { + item->move_after(new_neigbor); + } else { + item->move_before(new_neigbor); + } + } + } + + I->value.index = node_index; } + // Selection might have changed. item->set_selectable(0, true); + _set_item_custom_color(item, Color(0, 0, 0, 0)); + item->clear_custom_color(0); + + if (I->value.dirty) { + I->value.dirty = false; + _update_node(p_node, item, part_of_subscene); + } else { + // A parent might have moved/renamed. + item->set_metadata(0, p_node->get_path()); + } + + for (int i = 0; i < p_node->get_child_count(); i++) { + _update_nodes(p_node->get_child(i), item); + } + + if (valid_types.size()) { + bool valid = false; + for (const StringName &E : valid_types) { + if (p_node->is_class(E) || + EditorNode::get_singleton()->is_object_of_custom_type(p_node, E)) { + valid = true; + break; + } else { + Ref