1
0
mirror of https://github.com/godotengine/godot.git synced 2026-01-06 19:41:11 +00:00

Use ObjectID to store nodes in the editor selection.

This commit is contained in:
Pāvels Nadtočajevs
2025-10-20 08:56:07 +03:00
parent 79603b2f28
commit 338cfba60a
8 changed files with 127 additions and 85 deletions

View File

@@ -1073,8 +1073,11 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
Ref<MultiNodeEdit> mne = memnew(MultiNodeEdit);
for (const KeyValue<Node *, Object *> &E : editor_selection->get_selection()) {
mne->add_node(root->get_path_to(E.key));
for (const KeyValue<ObjectID, Object *> &E : editor_selection->get_selection()) {
Node *node = ObjectDB::get_instance<Node>(E.key);
if (node) {
mne->add_node(root->get_path_to(node));
}
}
_push_item(mne.ptr());
@@ -2930,7 +2933,10 @@ void SceneTreeDock::_selection_changed() {
//automatically turn on multi-edit
_tool_selected(TOOL_MULTI_EDIT);
} else if (selection_size == 1) {
_handle_select(editor_selection->get_selection().begin()->key);
Node *node = ObjectDB::get_instance<Node>(editor_selection->get_selection().begin()->key);
if (node) {
_handle_select(node);
}
} else if (selection_size == 0) {
_push_item(nullptr);
}
@@ -2940,10 +2946,12 @@ void SceneTreeDock::_selection_changed() {
// Track script changes in newly selected nodes.
node_previous_selection.reserve(editor_selection->get_selection().size());
for (const KeyValue<Node *, Object *> &E : editor_selection->get_selection()) {
Node *node = E.key;
node_previous_selection.push_back(node->get_instance_id());
node->connect(CoreStringName(script_changed), callable_mp(this, &SceneTreeDock::_queue_update_script_button));
for (const KeyValue<ObjectID, Object *> &E : editor_selection->get_selection()) {
Node *node = ObjectDB::get_instance<Node>(E.key);
if (node) {
node_previous_selection.push_back(E.key);
node->connect(CoreStringName(script_changed), callable_mp(this, &SceneTreeDock::_queue_update_script_button));
}
}
_queue_update_script_button();
}
@@ -3369,12 +3377,12 @@ void SceneTreeDock::set_edited_scene(Node *p_scene) {
edited_scene = p_scene;
}
static bool _is_same_selection(const Vector<Node *> &p_first, const HashMap<Node *, Object *> &p_second) {
static bool _is_same_selection(const Vector<Node *> &p_first, const HashMap<ObjectID, Object *> &p_second) {
if (p_first.size() != p_second.size()) {
return false;
}
for (Node *node : p_first) {
if (!p_second.has(node)) {
if (!p_second.has(node->get_instance_id())) {
return false;
}
}

View File

@@ -1214,15 +1214,15 @@ EditorData::~EditorData() {
///////////////////////////////////////////////////////////////////////////////
void EditorSelection::_node_removed(Node *p_node) {
if (!selection.has(p_node)) {
ERR_FAIL_NULL(p_node);
ObjectID nid = p_node->get_instance_id();
if (!selection.has(nid)) {
return;
}
Object *meta = selection[p_node];
if (meta) {
memdelete(meta);
}
selection.erase(p_node);
Object *meta = selection[nid];
memdelete_notnull(meta);
selection.erase(nid);
changed = true;
node_list_changed = true;
}
@@ -1230,7 +1230,8 @@ void EditorSelection::_node_removed(Node *p_node) {
void EditorSelection::add_node(Node *p_node) {
ERR_FAIL_NULL(p_node);
ERR_FAIL_COND(!p_node->is_inside_tree());
if (selection.has(p_node)) {
ObjectID nid = p_node->get_instance_id();
if (selection.has(nid)) {
return;
}
@@ -1243,30 +1244,32 @@ void EditorSelection::add_node(Node *p_node) {
break;
}
}
selection[p_node] = meta;
selection[nid] = meta;
p_node->connect(SceneStringName(tree_exiting), callable_mp(this, &EditorSelection::_node_removed).bind(p_node), CONNECT_ONE_SHOT);
}
void EditorSelection::remove_node(Node *p_node) {
ERR_FAIL_NULL(p_node);
if (!selection.has(p_node)) {
ObjectID nid = p_node->get_instance_id();
if (!selection.has(nid)) {
return;
}
changed = true;
node_list_changed = true;
Object *meta = selection[p_node];
if (meta) {
memdelete(meta);
}
selection.erase(p_node);
Object *meta = selection[nid];
memdelete_notnull(meta);
selection.erase(nid);
p_node->disconnect(SceneStringName(tree_exiting), callable_mp(this, &EditorSelection::_node_removed));
}
bool EditorSelection::is_selected(Node *p_node) const {
return selection.has(p_node);
if (!p_node) {
return false;
}
return selection.has(p_node->get_instance_id());
}
void EditorSelection::_bind_methods() {
@@ -1295,12 +1298,15 @@ void EditorSelection::_update_node_list() {
// If the selection does not have the parent of the selected node, then add the node to the node list.
// However, if the parent is already selected, then adding this node is redundant as
// it is included with the parent, so skip it.
for (const KeyValue<Node *, Object *> &E : selection) {
Node *parent = E.key;
for (const KeyValue<ObjectID, Object *> &E : selection) {
Node *parent = ObjectDB::get_instance<Node>(E.key);
if (!parent) {
continue;
}
parent = parent->get_parent();
bool skip = false;
while (parent) {
if (selection.has(parent)) {
if (selection.has(parent->get_instance_id())) {
skip = true;
break;
}
@@ -1337,8 +1343,11 @@ void EditorSelection::_emit_change() {
TypedArray<Node> EditorSelection::get_top_selected_nodes() {
TypedArray<Node> ret;
for (const Node *E : top_selected_node_list) {
ret.push_back(E);
for (const ObjectID &nid : top_selected_node_list) {
Node *node = ObjectDB::get_instance<Node>(nid);
if (node) {
ret.push_back(node);
}
}
return ret;
@@ -1347,26 +1356,39 @@ TypedArray<Node> EditorSelection::get_top_selected_nodes() {
TypedArray<Node> EditorSelection::get_selected_nodes() {
TypedArray<Node> ret;
for (const KeyValue<Node *, Object *> &E : selection) {
ret.push_back(E.key);
for (const KeyValue<ObjectID, Object *> &E : selection) {
Node *node = ObjectDB::get_instance<Node>(E.key);
if (node) {
ret.push_back(node);
}
}
return ret;
}
const List<Node *> &EditorSelection::get_top_selected_node_list() {
List<Node *> EditorSelection::get_top_selected_node_list() {
if (changed) {
update();
} else {
_update_node_list();
}
return top_selected_node_list;
List<Node *> node_list;
for (const ObjectID &nid : top_selected_node_list) {
Node *node = ObjectDB::get_instance<Node>(nid);
if (node) {
node_list.push_back(node);
}
}
return node_list;
}
List<Node *> EditorSelection::get_full_selected_node_list() {
List<Node *> node_list;
for (const KeyValue<Node *, Object *> &E : selection) {
node_list.push_back(E.key);
for (const KeyValue<ObjectID, Object *> &E : selection) {
Node *node = ObjectDB::get_instance<Node>(E.key);
if (node) {
node_list.push_back(node);
}
}
return node_list;
@@ -1374,7 +1396,10 @@ List<Node *> EditorSelection::get_full_selected_node_list() {
void EditorSelection::clear() {
while (!selection.is_empty()) {
remove_node(selection.begin()->key);
Node *node = ObjectDB::get_instance<Node>(selection.begin()->key);
if (node) {
remove_node(node);
}
}
changed = true;

View File

@@ -31,6 +31,7 @@
#pragma once
#include "core/templates/list.h"
#include "scene/main/node.h"
#include "scene/resources/texture.h"
class ConfigFile;
@@ -274,7 +275,7 @@ class EditorSelection : public Object {
// Contains the selected nodes and corresponding metadata.
// Metadata objects come from calling _get_editor_data on the editor_plugins, passing the selected node.
HashMap<Node *, Object *> selection;
HashMap<ObjectID, Object *> selection;
// Tracks whether the selection change signal has been emitted.
// Prevents multiple signals being called in one frame.
@@ -287,7 +288,7 @@ class EditorSelection : public Object {
// Editor plugins which are related to selection.
List<Object *> editor_plugins;
List<Node *> top_selected_node_list;
LocalVector<ObjectID> top_selected_node_list;
void _update_node_list();
void _emit_change();
@@ -302,10 +303,14 @@ public:
template <typename T>
T *get_node_editor_data(Node *p_node) {
if (!selection.has(p_node)) {
if (!p_node) {
return nullptr;
}
return Object::cast_to<T>(selection[p_node]);
ObjectID nid = p_node->get_instance_id();
if (!selection.has(nid)) {
return nullptr;
}
return Object::cast_to<T>(selection[nid]);
}
// Adds an editor plugin which can provide metadata for selected nodes.
@@ -316,7 +321,7 @@ public:
// Returns only the top level selected nodes.
// That is, if the selection includes some node and a child of that node, only the parent is returned.
const List<Node *> &get_top_selected_node_list();
List<Node *> get_top_selected_node_list();
// Same as get_top_selected_node_list but returns a copy in a TypedArray for binding to scripts.
TypedArray<Node> get_top_selected_nodes();
// Returns all the selected nodes (list version of "get_selected_nodes").
@@ -324,7 +329,7 @@ public:
// Same as get_full_selected_node_list but returns a copy in a TypedArray for binding to scripts.
TypedArray<Node> get_selected_nodes();
// Returns the map of selected objects and their metadata.
HashMap<Node *, Object *> &get_selection() { return selection; }
HashMap<ObjectID, Object *> &get_selection() { return selection; }
~EditorSelection();
};

View File

@@ -341,12 +341,13 @@ void Particles2DEditorPlugin::_selection_changed() {
}
// Turn gizmos on for nodes that are newly selected.
HashSet<const Node *> nodes_in_current_selection;
HashSet<ObjectID> nodes_in_current_selection;
for (Node *node : current_selection) {
nodes_in_current_selection.insert(node);
if (!selected_particles.has(node)) {
ObjectID nid = node->get_instance_id();
nodes_in_current_selection.insert(nid);
if (!selected_particles.has(nid)) {
_set_show_gizmos(node, true);
selected_particles.insert(node);
selected_particles.insert(nid);
}
}
@@ -358,21 +359,24 @@ void Particles2DEditorPlugin::_selection_changed() {
direction_img_path_line_edit->set_text("");
// 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);
LocalVector<ObjectID> to_erase;
for (const ObjectID &nid : selected_particles) {
if (!nodes_in_current_selection.has(nid)) {
Node *node = ObjectDB::get_instance<Node>(nid);
if (node) {
_set_show_gizmos(node, false);
}
to_erase.push_back(nid);
}
}
for (Node *node : to_erase) {
selected_particles.erase(node);
for (const ObjectID &nid : to_erase) {
selected_particles.erase(nid);
}
}
void Particles2DEditorPlugin::_node_removed(Node *p_node) {
if (selected_particles.erase(p_node)) {
if (p_node && selected_particles.erase(p_node->get_instance_id())) {
_set_show_gizmos(p_node, false);
}
}

View File

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

View File

@@ -673,12 +673,12 @@ Transform3D Node3DEditorViewport::to_camera_transform(const Cursor &p_cursor) co
}
int Node3DEditorViewport::get_selected_count() const {
const HashMap<Node *, Object *> &selection = editor_selection->get_selection();
const HashMap<ObjectID, Object *> &selection = editor_selection->get_selection();
int count = 0;
for (const KeyValue<Node *, Object *> &E : selection) {
Node3D *sp = Object::cast_to<Node3D>(E.key);
for (const KeyValue<ObjectID, Object *> &E : selection) {
Node3D *sp = ObjectDB::get_instance<Node3D>(E.key);
if (!sp) {
continue;
}
@@ -3341,13 +3341,13 @@ void Node3DEditorViewport::_notification(int p_what) {
_update_camera(delta);
}
const HashMap<Node *, Object *> &selection = editor_selection->get_selection();
const HashMap<ObjectID, Object *> &selection = editor_selection->get_selection();
bool changed = false;
bool exist = false;
for (const KeyValue<Node *, Object *> &E : selection) {
Node3D *sp = Object::cast_to<Node3D>(E.key);
for (const KeyValue<ObjectID, Object *> &E : selection) {
Node3D *sp = ObjectDB::get_instance<Node3D>(E.key);
if (!sp) {
continue;
}
@@ -8489,10 +8489,10 @@ void Node3DEditor::update_grid() {
void Node3DEditor::_selection_changed() {
_refresh_menu_icons();
const HashMap<Node *, Object *> &selection = editor_selection->get_selection();
const HashMap<ObjectID, Object *> &selection = editor_selection->get_selection();
for (const KeyValue<Node *, Object *> &E : selection) {
Node3D *sp = Object::cast_to<Node3D>(E.key);
for (const KeyValue<ObjectID, Object *> &E : selection) {
Node3D *sp = ObjectDB::get_instance<Node3D>(E.key);
if (!sp) {
continue;
}

View File

@@ -824,8 +824,8 @@ bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_po
List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool p_retrieve_locked, bool p_remove_canvas_item_if_parent_in_selection, bool *r_has_locked_items) const {
List<CanvasItem *> selection;
for (const KeyValue<Node *, Object *> &E : editor_selection->get_selection()) {
CanvasItem *ci = Object::cast_to<CanvasItem>(E.key);
for (const KeyValue<ObjectID, Object *> &E : editor_selection->get_selection()) {
CanvasItem *ci = ObjectDB::get_instance<CanvasItem>(E.key);
if (ci) {
if (ci->is_visible_in_tree() && (p_retrieve_locked || !_is_node_locked(ci))) {
Viewport *vp = ci->get_viewport();
@@ -4667,7 +4667,7 @@ void CanvasItemEditor::_button_tool_select(int p_index) {
}
void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation, bool p_scale, bool p_on_existing) {
const HashMap<Node *, Object *> &selection = editor_selection->get_selection();
const HashMap<ObjectID, Object *> &selection = editor_selection->get_selection();
AnimationTrackEditor *te = AnimationPlayerEditor::get_singleton()->get_track_editor();
ERR_FAIL_COND_MSG(te->get_current_animation().is_null(), "Cannot insert animation key. No animation selected.");
@@ -4678,8 +4678,8 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation,
return;
}
te->make_insert_queue();
for (const KeyValue<Node *, Object *> &E : selection) {
CanvasItem *ci = Object::cast_to<CanvasItem>(E.key);
for (const KeyValue<ObjectID, Object *> &E : selection) {
CanvasItem *ci = ObjectDB::get_instance<CanvasItem>(E.key);
if (!ci || !ci->is_visible_in_tree()) {
continue;
}
@@ -4981,10 +4981,10 @@ void CanvasItemEditor::_popup_callback(int p_op) {
case ANIM_COPY_POSE: {
pose_clipboard.clear();
const HashMap<Node *, Object *> &selection = editor_selection->get_selection();
const HashMap<ObjectID, Object *> &selection = editor_selection->get_selection();
for (const KeyValue<Node *, Object *> &E : selection) {
CanvasItem *ci = Object::cast_to<CanvasItem>(E.key);
for (const KeyValue<ObjectID, Object *> &E : selection) {
CanvasItem *ci = ObjectDB::get_instance<CanvasItem>(E.key);
if (!ci || !ci->is_visible_in_tree()) {
continue;
}
@@ -5023,10 +5023,10 @@ void CanvasItemEditor::_popup_callback(int p_op) {
} break;
case ANIM_CLEAR_POSE: {
HashMap<Node *, Object *> &selection = editor_selection->get_selection();
HashMap<ObjectID, Object *> &selection = editor_selection->get_selection();
for (const KeyValue<Node *, Object *> &E : selection) {
CanvasItem *ci = Object::cast_to<CanvasItem>(E.key);
for (const KeyValue<ObjectID, Object *> &E : selection) {
CanvasItem *ci = ObjectDB::get_instance<CanvasItem>(E.key);
if (!ci || !ci->is_visible_in_tree()) {
continue;
}
@@ -5089,7 +5089,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
} break;
case SKELETON_MAKE_BONES: {
HashMap<Node *, Object *> &selection = editor_selection->get_selection();
HashMap<ObjectID, Object *> &selection = editor_selection->get_selection();
Node *editor_root = get_tree()->get_edited_scene_root();
if (!editor_root || selection.is_empty()) {
@@ -5097,8 +5097,8 @@ void CanvasItemEditor::_popup_callback(int p_op) {
}
undo_redo->create_action(TTR("Create Custom Bone2D(s) from Node(s)"));
for (const KeyValue<Node *, Object *> &E : selection) {
Node2D *n2d = Object::cast_to<Node2D>(E.key);
for (const KeyValue<ObjectID, Object *> &E : selection) {
Node2D *n2d = ObjectDB::get_instance<Node2D>(E.key);
if (!n2d) {
continue;
}
@@ -5144,9 +5144,9 @@ void CanvasItemEditor::_focus_selection(int p_op) {
Rect2 rect;
int count = 0;
const HashMap<Node *, Object *> &selection = editor_selection->get_selection();
for (const KeyValue<Node *, Object *> &E : selection) {
CanvasItem *ci = Object::cast_to<CanvasItem>(E.key);
const HashMap<ObjectID, Object *> &selection = editor_selection->get_selection();
for (const KeyValue<ObjectID, Object *> &E : selection) {
CanvasItem *ci = ObjectDB::get_instance<CanvasItem>(E.key);
if (!ci) {
continue;
}

View File

@@ -926,8 +926,8 @@ bool ControlEditorToolbar::_is_node_locked(const Node *p_node) {
List<Control *> ControlEditorToolbar::_get_edited_controls() {
List<Control *> selection;
for (const KeyValue<Node *, Object *> &E : editor_selection->get_selection()) {
Control *control = Object::cast_to<Control>(E.key);
for (const KeyValue<ObjectID, Object *> &E : editor_selection->get_selection()) {
Control *control = ObjectDB::get_instance<Control>(E.key);
if (control && control->is_visible_in_tree() && control->get_viewport() == EditorNode::get_singleton()->get_scene_root() && !_is_node_locked(control)) {
selection.push_back(control);
}
@@ -958,8 +958,8 @@ void ControlEditorToolbar::_selection_changed() {
SIZE_EXPAND,
};
for (const KeyValue<Node *, Object *> &E : editor_selection->get_selection()) {
Control *control = Object::cast_to<Control>(E.key);
for (const KeyValue<ObjectID, Object *> &E : editor_selection->get_selection()) {
Control *control = ObjectDB::get_instance<Control>(E.key);
if (!control) {
continue;
}