Speed up large selections in the editor

This commit is contained in:
Mike Precup 2025-08-08 11:28:47 -07:00
parent a3b42d85d2
commit 1c8e3f9037
12 changed files with 111 additions and 86 deletions

View file

@ -563,7 +563,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!profile_allow_editing) {
break;
}
if (editor_selection->get_top_selected_node_list().size() > 1) {
if (editor_selection->get_selection().size() > 1) {
if (!_validate_no_foreign()) {
break;
}
@ -1153,7 +1153,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
if (selection.size() != 1) {
accept->set_text(vformat(TTR("Saving the branch as a scene requires selecting only one node, but you have selected %d nodes."), selection.size()));
@ -1214,8 +1214,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
new_scene_from_dialog->popup_file_dialog();
} break;
case TOOL_COPY_NODE_PATH: {
List<Node *> selection = editor_selection->get_top_selected_node_list();
List<Node *>::Element *e = selection.front();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
const List<Node *>::Element *e = selection.front();
if (e) {
Node *node = e->get();
if (node) {
@ -1226,8 +1226,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
} break;
case TOOL_SHOW_IN_FILE_SYSTEM: {
List<Node *> selection = editor_selection->get_top_selected_node_list();
List<Node *>::Element *e = selection.front();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
const List<Node *>::Element *e = selection.front();
if (e) {
const Node *node = e->get();
if (node) {
@ -1236,7 +1236,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
} break;
case TOOL_OPEN_DOCUMENTATION: {
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
for (const Node *node : selection) {
String class_name;
Ref<Script> script_base = node->get_script();
@ -1272,12 +1272,12 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
if (selection.size() != 1) {
break;
}
List<Node *>::Element *e = selection.front();
const List<Node *>::Element *e = selection.front();
if (e) {
Node *node = e->get();
if (node) {
@ -1307,8 +1307,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
List<Node *> selection = editor_selection->get_top_selected_node_list();
List<Node *>::Element *e = selection.front();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
const List<Node *>::Element *e = selection.front();
if (e) {
Node *node = e->get();
if (node) {
@ -1342,8 +1342,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
List<Node *> selection = editor_selection->get_top_selected_node_list();
List<Node *>::Element *e = selection.front();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
const List<Node *>::Element *e = selection.front();
if (e) {
Node *node = e->get();
if (node) {
@ -1367,8 +1367,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
} break;
case TOOL_SCENE_OPEN: {
List<Node *> selection = editor_selection->get_top_selected_node_list();
List<Node *>::Element *e = selection.front();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
const List<Node *>::Element *e = selection.front();
if (e) {
Node *node = e->get();
if (node) {
@ -1388,8 +1388,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
List<Node *> selection = editor_selection->get_top_selected_node_list();
List<Node *>::Element *e = selection.front();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
const List<Node *>::Element *e = selection.front();
if (e) {
Node *node = e->get();
if (node) {
@ -1400,8 +1400,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
} break;
case TOOL_SCENE_OPEN_INHERITED: {
List<Node *> selection = editor_selection->get_top_selected_node_list();
List<Node *>::Element *e = selection.front();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
const List<Node *>::Element *e = selection.front();
if (e) {
Node *node = e->get();
if (node && node->get_scene_inherited_state().is_valid()) {
@ -2295,7 +2295,7 @@ void SceneTreeDock::_node_prerenamed(Node *p_node, const String &p_new_name) {
}
bool SceneTreeDock::_validate_no_foreign() {
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
for (Node *E : selection) {
if (E != edited_scene && E->get_owner() != edited_scene) {
@ -2324,7 +2324,7 @@ bool SceneTreeDock::_validate_no_foreign() {
}
bool SceneTreeDock::_validate_no_instance() {
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
for (Node *E : selection) {
if (E != edited_scene && !E->get_scene_file_path().is_empty()) {
@ -2341,7 +2341,7 @@ void SceneTreeDock::_node_reparent(NodePath p_path, bool p_keep_global_xform) {
Node *new_parent = scene_root->get_node(p_path);
ERR_FAIL_NULL(new_parent);
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
if (selection.is_empty()) {
return; // Nothing to reparent.
@ -2563,7 +2563,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
}
void SceneTreeDock::_script_created(Ref<Script> p_script) {
List<Node *> selected = editor_selection->get_top_selected_node_list();
const List<Node *> &selected = editor_selection->get_top_selected_node_list();
if (selected.is_empty()) {
return;
@ -2624,8 +2624,8 @@ void SceneTreeDock::_shader_creation_closed() {
}
void SceneTreeDock::_toggle_editable_children_from_selection() {
List<Node *> selection = editor_selection->get_top_selected_node_list();
List<Node *>::Element *e = selection.front();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
const List<Node *>::Element *e = selection.front();
if (e) {
_toggle_editable_children(e->get());
@ -2633,8 +2633,8 @@ void SceneTreeDock::_toggle_editable_children_from_selection() {
}
void SceneTreeDock::_toggle_placeholder_from_selection() {
List<Node *> selection = editor_selection->get_top_selected_node_list();
List<Node *>::Element *e = selection.front();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
const List<Node *>::Element *e = selection.front();
if (e) {
Node *node = e->get();
@ -3023,7 +3023,7 @@ void SceneTreeDock::_create() {
_do_create(parent);
} else if (current_option == TOOL_REPLACE) {
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
ERR_FAIL_COND(selection.is_empty());
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
@ -3042,7 +3042,7 @@ void SceneTreeDock::_create() {
ur->commit_action(false);
} else if (current_option == TOOL_REPARENT_TO_NEW_NODE) {
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
ERR_FAIL_COND(selection.is_empty());
// Find top level node in selection
@ -3056,7 +3056,7 @@ void SceneTreeDock::_create() {
bool center_parent = EDITOR_GET("docks/scene_tree/center_node_on_reparent");
Vector<Node *> top_level_nodes;
for (List<Node *>::Element *E = selection.front()->next(); E; E = E->next()) {
for (const List<Node *>::Element *E = selection.front()->next(); E; E = E->next()) {
Node *n = E->get();
ERR_FAIL_NULL(n);
@ -3363,12 +3363,12 @@ void SceneTreeDock::set_edited_scene(Node *p_scene) {
edited_scene = p_scene;
}
static bool _is_same_selection(const Vector<Node *> &p_first, const List<Node *> &p_second) {
static bool _is_same_selection(const Vector<Node *> &p_first, const HashMap<Node *, Object *> &p_second) {
if (p_first.size() != p_second.size()) {
return false;
}
for (Node *node : p_second) {
if (!p_first.has(node)) {
for (Node *node : p_first) {
if (!p_second.has(node)) {
return false;
}
}
@ -3384,7 +3384,7 @@ void SceneTreeDock::clear_previous_node_selection() {
void SceneTreeDock::set_selection(const Vector<Node *> &p_nodes) {
// If the nodes selected are the same independently of order then return early.
if (_is_same_selection(p_nodes, editor_selection->get_full_selected_node_list())) {
if (_is_same_selection(p_nodes, editor_selection->get_selection())) {
return;
}
editor_selection->clear();
@ -3398,7 +3398,7 @@ void SceneTreeDock::set_selected(Node *p_node, bool p_emit_selected) {
}
void SceneTreeDock::_new_scene_from(const String &p_file) {
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
if (selection.size() != 1) {
accept->set_text(TTR("This operation requires a single selected node."));
@ -3576,7 +3576,7 @@ void SceneTreeDock::_normalize_drop(Node *&to_node, int &to_pos, int p_type) {
}
Array SceneTreeDock::_get_selection_array() {
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
TypedArray<Node> array;
array.resize(selection.size());
@ -3725,7 +3725,7 @@ void SceneTreeDock::_nodes_dragged(const Array &p_nodes, NodePath p_to, int p_ty
return;
}
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
if (selection.is_empty()) {
return; //nothing to reparent
@ -3788,7 +3788,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
ERR_FAIL_COND(!EditorNode::get_singleton()->get_edited_scene());
menu->clear(false);
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
List<Node *> full_selection = editor_selection->get_full_selected_node_list(); // Above method only returns nodes with common parent.
if (selection.is_empty()) {
@ -4004,7 +4004,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
Vector<String> p_paths;
Node *root = EditorNode::get_singleton()->get_edited_scene();
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
for (const List<Node *>::Element *E = selection.front(); E; E = E->next()) {
String node_path = String(root->get_path().rel_path_to(E->get()->get_path()));
p_paths.push_back(node_path);
}
@ -4141,7 +4141,7 @@ void SceneTreeDock::attach_script_to_selected(bool p_extend) {
return;
}
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
if (selection.is_empty()) {
return;
}
@ -4271,7 +4271,7 @@ List<Node *> SceneTreeDock::paste_nodes(bool p_paste_as_sibling) {
Node *paste_parent = edited_scene;
Node *paste_sibling = nullptr;
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
if (selection.size() > 0) {
paste_parent = selection.back()->get();
}

View file

@ -1296,7 +1296,7 @@ void EditorSelection::_update_node_list() {
top_selected_node_list.push_back(E.key);
}
node_list_changed = true;
node_list_changed = false;
}
void EditorSelection::update() {

View file

@ -2881,8 +2881,13 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update
}
if (!multi_nodes.is_empty()) {
// Pick the top-most node.
multi_nodes.sort_custom<Node::Comparator>();
selected_node = multi_nodes[0];
Node::Comparator comparator;
for (Node *node : multi_nodes) {
if (comparator(node, selected_node)) {
selected_node = node;
}
}
}
}
}

View file

@ -148,18 +148,20 @@ void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const {
F.name = F.name.replace_first("metadata/", "Metadata/"); // Trick to not get actual metadata edited from MultiNodeEdit.
}
if (!usage.has(F.name)) {
PLData *usage_data = usage.getptr(F.name);
if (!usage_data) {
PLData pld;
pld.uses = 0;
pld.info = F;
pld.info.name = F.name;
usage[F.name] = pld;
data_list.push_back(usage.getptr(F.name));
HashMap<String, MultiNodeEdit::PLData>::Iterator I = usage.insert(F.name, pld);
usage_data = &I->value;
data_list.push_back(usage_data);
}
// Make sure only properties with the same exact PropertyInfo data will appear.
if (usage[F.name].info == F) {
usage[F.name].uses++;
if (usage_data->info == F) {
usage_data->uses++;
}
}

View file

@ -74,8 +74,12 @@ public:
if (get_node_count() != p_other->get_node_count()) {
return false;
}
for (int i = 0; i < get_node_count(); i++) {
if (!nodes.has(p_other->get_node(i))) {
HashSet<NodePath> nodes_in_selection;
for (const NodePath &node : p_other->nodes) {
nodes_in_selection.insert(node);
}
for (const NodePath &node : nodes) {
if (!nodes_in_selection.has(node)) {
return false;
}
}

View file

@ -230,36 +230,38 @@ void Particles2DEditorPlugin::_set_show_gizmos(Node *p_node, bool p_show) {
}
void Particles2DEditorPlugin::_selection_changed() {
List<Node *> current_selection = EditorNode::get_singleton()->get_editor_selection()->get_top_selected_node_list();
const List<Node *> &current_selection = EditorNode::get_singleton()->get_editor_selection()->get_top_selected_node_list();
if (selected_particles.is_empty() && current_selection.is_empty()) {
return;
}
// Turn gizmos off for nodes that are no longer selected.
for (List<Node *>::Element *E = selected_particles.front(); E;) {
Node *node = E->get();
List<Node *>::Element *N = E->next();
if (current_selection.find(node) == nullptr) {
_set_show_gizmos(node, false);
selected_particles.erase(E);
// Turn gizmos on for nodes that are newly selected.
HashSet<const Node *> nodes_in_current_selection;
for (Node *node : current_selection) {
nodes_in_current_selection.insert(node);
if (!selected_particles.has(node)) {
_set_show_gizmos(node, true);
selected_particles.insert(node);
}
E = N;
}
// Turn gizmos on for nodes that are newly selected.
for (Node *node : current_selection) {
if (selected_particles.find(node) == nullptr) {
_set_show_gizmos(node, true);
selected_particles.push_back(node);
// Turn gizmos off for nodes that are no longer selected.
LocalVector<Node *> to_erase;
for (Node *node : selected_particles) {
if (!nodes_in_current_selection.has(node)) {
_set_show_gizmos(node, false);
to_erase.push_back(node);
}
}
for (Node *node : to_erase) {
selected_particles.erase(node);
}
}
void Particles2DEditorPlugin::_node_removed(Node *p_node) {
List<Node *>::Element *E = selected_particles.find(p_node);
if (E) {
_set_show_gizmos(E->get(), false);
selected_particles.erase(E);
if (selected_particles.erase(p_node)) {
_set_show_gizmos(p_node, false);
}
}

View file

@ -42,7 +42,7 @@ protected:
MENU_LOAD_EMISSION_MASK = 100,
};
List<Node *> selected_particles;
HashSet<Node *> selected_particles;
enum EmissionMode {
EMISSION_MODE_SOLID,

View file

@ -5137,7 +5137,7 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_
selected_files = d["files"];
}
List<Node *> selected_nodes = EditorNode::get_singleton()->get_editor_selection()->get_top_selected_node_list();
const List<Node *> &selected_nodes = EditorNode::get_singleton()->get_editor_selection()->get_top_selected_node_list();
Node *root_node = EditorNode::get_singleton()->get_edited_scene();
if (selected_nodes.size() > 0) {
Node *selected_node = selected_nodes.front()->get();

View file

@ -832,8 +832,12 @@ List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool p_retrieve_lo
if (p_remove_canvas_item_if_parent_in_selection) {
List<CanvasItem *> filtered_selection;
HashSet<const Node *> nodes_in_selection;
for (CanvasItem *E : selection) {
if (!selection.find(E->get_parent())) {
nodes_in_selection.insert(E);
}
for (CanvasItem *E : selection) {
if (!nodes_in_selection.has(E->get_parent())) {
filtered_selection.push_back(E);
}
}
@ -2617,7 +2621,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
_find_canvas_items_in_rect(Rect2(bsfrom, bsto - bsfrom), scene, &selitems);
if (selitems.size() == 1 && editor_selection->get_top_selected_node_list().is_empty()) {
if (selitems.size() == 1 && editor_selection->get_selection().is_empty()) {
EditorNode::get_singleton()->push_item(selitems.front()->get());
}
for (CanvasItem *E : selitems) {
@ -2835,7 +2839,7 @@ void CanvasItemEditor::_update_lock_and_group_button() {
bool all_locked = true;
bool all_group = true;
bool has_canvas_item = false;
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
if (selection.is_empty()) {
all_locked = false;
all_group = false;
@ -4672,7 +4676,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
case LOCK_SELECTED: {
undo_redo->create_action(TTR("Lock Selected"));
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
for (Node *E : selection) {
CanvasItem *ci = Object::cast_to<CanvasItem>(E);
if (!ci || !ci->is_inside_tree()) {
@ -4691,7 +4695,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
case UNLOCK_SELECTED: {
undo_redo->create_action(TTR("Unlock Selected"));
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
for (Node *E : selection) {
CanvasItem *ci = Object::cast_to<CanvasItem>(E);
if (!ci || !ci->is_inside_tree()) {
@ -4710,7 +4714,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
case GROUP_SELECTED: {
undo_redo->create_action(TTR("Group Selected"));
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
for (Node *E : selection) {
CanvasItem *ci = Object::cast_to<CanvasItem>(E);
if (!ci || !ci->is_inside_tree()) {
@ -4729,7 +4733,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
case UNGROUP_SELECTED: {
undo_redo->create_action(TTR("Ungroup Selected"));
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
for (Node *E : selection) {
CanvasItem *ci = Object::cast_to<CanvasItem>(E);
if (!ci || !ci->is_inside_tree()) {
@ -6353,7 +6357,7 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p
return;
}
List<Node *> selected_nodes = EditorNode::get_singleton()->get_editor_selection()->get_top_selected_node_list();
const List<Node *> &selected_nodes = EditorNode::get_singleton()->get_editor_selection()->get_top_selected_node_list();
Node *root_node = EditorNode::get_singleton()->get_edited_scene();
if (selected_nodes.size() > 0) {
Node *selected_node = selected_nodes.front()->get();

View file

@ -770,7 +770,7 @@ SizeFlagPresetPicker::SizeFlagPresetPicker(bool p_vertical) {
void ControlEditorToolbar::_anchors_preset_selected(int p_preset) {
LayoutPreset preset = (LayoutPreset)p_preset;
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Anchors, Offsets, Grow Direction"));
@ -791,7 +791,7 @@ void ControlEditorToolbar::_anchors_preset_selected(int p_preset) {
}
void ControlEditorToolbar::_anchors_to_current_ratio() {
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Anchors, Offsets (Keep Ratio)"));
@ -842,7 +842,7 @@ void ControlEditorToolbar::_anchor_mode_toggled(bool p_status) {
}
void ControlEditorToolbar::_container_flags_selected(int p_flags, bool p_vertical) {
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (p_vertical) {
@ -869,7 +869,7 @@ void ControlEditorToolbar::_container_flags_selected(int p_flags, bool p_vertica
}
void ControlEditorToolbar::_expand_flag_toggled(bool p_expand, bool p_vertical) {
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (p_vertical) {
@ -1003,7 +1003,7 @@ void ControlEditorToolbar::_selection_changed() {
int nb_valid_controls = 0;
int nb_anchors_mode = 0;
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
for (Node *E : selection) {
Control *control = Object::cast_to<Control>(E);
if (!control) {
@ -1053,7 +1053,7 @@ void ControlEditorToolbar::_selection_changed() {
int nb_h_expand = 0;
int nb_v_expand = 0;
List<Node *> selection = editor_selection->get_top_selected_node_list();
const List<Node *> &selection = editor_selection->get_top_selected_node_list();
for (Node *E : selection) {
Control *control = Object::cast_to<Control>(E);
if (!control) {

View file

@ -1312,11 +1312,17 @@ void SceneTreeEditor::_cell_multi_selected(Object *p_object, int p_cell, bool p_
}
// Emitted "selected" in _selected_changed() when select single node, so select multiple node emit "changed".
if (editor_selection->get_selected_nodes().size() > 1) {
emit_signal(SNAME("node_changed"));
if (editor_selection->get_selection().size() > 1 && !pending_selection_update) {
pending_selection_update = true;
callable_mp(this, &SceneTreeEditor::_process_selection_update).call_deferred();
}
}
void SceneTreeEditor::_process_selection_update() {
pending_selection_update = false;
emit_signal(SNAME("node_changed"));
}
void SceneTreeEditor::_tree_scroll_to_item(ObjectID p_item_id) {
ERR_FAIL_NULL(tree);
TreeItem *item = ObjectDB::get_instance<TreeItem>(p_item_id);

View file

@ -184,6 +184,7 @@ class SceneTreeEditor : public Control {
bool display_foreign = false;
bool tree_dirty = true;
bool pending_test_update = false;
bool pending_selection_update = false;
Timer *update_node_tooltip_delay = nullptr;
static void _bind_methods();
@ -191,6 +192,7 @@ class SceneTreeEditor : public Control {
void _cell_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button);
void _toggle_visible(Node *p_node);
void _cell_multi_selected(Object *p_object, int p_cell, bool p_selected);
void _process_selection_update();
void _update_selection(TreeItem *item);
void _node_script_changed(Node *p_node);
void _node_visibility_changed(Node *p_node);