Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/editor/docks/scene_tree_dock.cpp
20942 views
1
/**************************************************************************/
2
/* scene_tree_dock.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "scene_tree_dock.h"
32
33
#include "core/config/project_settings.h"
34
#include "core/input/input.h"
35
#include "core/io/resource_saver.h"
36
#include "core/object/class_db.h"
37
#include "core/os/keyboard.h"
38
#include "editor/animation/animation_player_editor_plugin.h"
39
#include "editor/debugger/editor_debugger_node.h"
40
#include "editor/docks/filesystem_dock.h"
41
#include "editor/docks/groups_dock.h"
42
#include "editor/docks/inspector_dock.h"
43
#include "editor/docks/signals_dock.h"
44
#include "editor/editor_main_screen.h"
45
#include "editor/editor_node.h"
46
#include "editor/editor_string_names.h"
47
#include "editor/editor_undo_redo_manager.h"
48
#include "editor/file_system/editor_file_system.h"
49
#include "editor/file_system/editor_paths.h"
50
#include "editor/gui/editor_file_dialog.h"
51
#include "editor/gui/editor_quick_open_dialog.h"
52
#include "editor/inspector/editor_context_menu_plugin.h"
53
#include "editor/inspector/multi_node_edit.h"
54
#include "editor/scene/3d/node_3d_editor_plugin.h"
55
#include "editor/scene/canvas_item_editor_plugin.h"
56
#include "editor/scene/rename_dialog.h"
57
#include "editor/scene/reparent_dialog.h"
58
#include "editor/script/script_editor_plugin.h"
59
#include "editor/settings/editor_command_palette.h"
60
#include "editor/settings/editor_feature_profile.h"
61
#include "editor/settings/editor_settings.h"
62
#include "editor/shader/shader_create_dialog.h"
63
#include "editor/themes/editor_scale.h"
64
#include "scene/2d/node_2d.h"
65
#include "scene/animation/animation_tree.h"
66
#include "scene/audio/audio_stream_player.h"
67
#include "scene/gui/box_container.h"
68
#include "scene/gui/check_box.h"
69
#include "scene/property_utils.h"
70
#include "scene/resources/packed_scene.h"
71
#include "servers/display/display_server.h"
72
73
void SceneTreeDock::_nodes_drag_begin() {
74
pending_click_select = nullptr;
75
}
76
77
void SceneTreeDock::_quick_open(const String &p_file_path) {
78
instantiate_scenes({ p_file_path }, scene_tree->get_selected());
79
}
80
81
static void _restore_treeitem_custom_color(TreeItem *p_item) {
82
if (!p_item) {
83
return;
84
}
85
Color custom_color = p_item->get_meta(SNAME("custom_color"), Color(0, 0, 0, 0));
86
if (custom_color != Color(0, 0, 0, 0)) {
87
p_item->set_custom_color(0, custom_color);
88
} else {
89
p_item->clear_custom_color(0);
90
}
91
}
92
93
void SceneTreeDock::_inspect_hovered_node() {
94
Tree *tree = scene_tree->get_scene_tree();
95
if (!tree->get_rect().has_point(tree->get_local_mouse_position())) {
96
return;
97
}
98
99
select_node_hovered_at_end_of_drag = true;
100
TreeItem *item = tree->get_item_with_metadata(node_hovered_now->get_path());
101
102
_restore_treeitem_custom_color(tree_item_inspected);
103
tree_item_inspected = item;
104
105
if (item) {
106
Color accent_color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));
107
tree_item_inspected->set_custom_color(0, accent_color);
108
}
109
110
EditorSelectionHistory *editor_history = EditorNode::get_singleton()->get_editor_selection_history();
111
editor_history->add_object(node_hovered_now->get_instance_id());
112
InspectorDock::get_inspector_singleton()->edit(node_hovered_now);
113
InspectorDock::get_inspector_singleton()->propagate_notification(NOTIFICATION_DRAG_BEGIN); // Enable inspector drag preview after it updated.
114
InspectorDock::get_singleton()->update(node_hovered_now);
115
EditorNode::get_singleton()->hide_unused_editors();
116
}
117
118
void SceneTreeDock::_handle_hover_to_inspect() {
119
Tree *tree = scene_tree->get_scene_tree();
120
TreeItem *item = tree->get_item_at_position(tree->get_local_mouse_position());
121
122
if (item) {
123
const NodePath &np = item->get_metadata(0);
124
node_hovered_now = get_node_or_null(np);
125
if (node_hovered_previously != node_hovered_now) {
126
inspect_hovered_node_delay->start();
127
}
128
node_hovered_previously = node_hovered_now;
129
} else {
130
_reset_hovering_timer();
131
}
132
}
133
134
void SceneTreeDock::_reset_hovering_timer() {
135
if (!inspect_hovered_node_delay->is_stopped()) {
136
inspect_hovered_node_delay->stop();
137
}
138
node_hovered_previously = nullptr;
139
}
140
141
void SceneTreeDock::input(const Ref<InputEvent> &p_event) {
142
ERR_FAIL_COND(p_event.is_null());
143
144
Ref<InputEventMouseButton> mb = p_event;
145
146
if (mb.is_valid() && (mb->get_button_index() == MouseButton::LEFT || mb->get_button_index() == MouseButton::RIGHT)) {
147
Tree *tree = scene_tree->get_scene_tree();
148
if (mb->is_pressed() && tree->get_rect().has_point(tree->get_local_mouse_position())) {
149
tree_clicked = true;
150
} else if (!mb->is_pressed()) {
151
tree_clicked = false;
152
}
153
154
if (!mb->is_pressed() && pending_click_select) {
155
_push_item(pending_click_select);
156
pending_click_select = nullptr;
157
}
158
}
159
160
Ref<InputEventMouseMotion> mm = p_event;
161
bool tree_hovered = false;
162
if (mm.is_valid()) {
163
Tree *tree = scene_tree->get_scene_tree();
164
tree_hovered = tree->get_rect().has_point(tree->get_local_mouse_position());
165
}
166
167
if ((tree_clicked || tree_hovered) && get_viewport()->gui_is_dragging()) {
168
_handle_hover_to_inspect();
169
}
170
}
171
172
void SceneTreeDock::shortcut_input(const Ref<InputEvent> &p_event) {
173
ERR_FAIL_COND(p_event.is_null());
174
175
Control *focus_owner = get_viewport()->gui_get_focus_owner();
176
if (focus_owner && focus_owner->is_text_field()) {
177
return;
178
}
179
180
if (!p_event->is_pressed() || p_event->is_echo()) {
181
return;
182
}
183
184
if (ED_IS_SHORTCUT("scene_tree/rename", p_event)) {
185
// Prevent renaming if a button or a range is focused
186
// to avoid conflict with Enter shortcut on macOS.
187
if (focus_owner && (Object::cast_to<BaseButton>(focus_owner) || Object::cast_to<Range>(focus_owner))) {
188
return;
189
}
190
if (!scene_tree->is_visible_in_tree()) {
191
return;
192
}
193
_tool_selected(TOOL_RENAME);
194
} else if (ED_IS_SHORTCUT("scene_tree/batch_rename", p_event)) {
195
_tool_selected(TOOL_BATCH_RENAME);
196
} else if (ED_IS_SHORTCUT("scene_tree/add_child_node", p_event)) {
197
_tool_selected(TOOL_NEW);
198
} else if (ED_IS_SHORTCUT("scene_tree/instantiate_scene", p_event)) {
199
_tool_selected(TOOL_INSTANTIATE);
200
} else if (ED_IS_SHORTCUT("scene_tree/expand_collapse_all", p_event)) {
201
_tool_selected(TOOL_EXPAND_COLLAPSE);
202
} else if (ED_IS_SHORTCUT("scene_tree/cut_node", p_event)) {
203
_tool_selected(TOOL_CUT);
204
} else if (ED_IS_SHORTCUT("scene_tree/copy_node", p_event)) {
205
_tool_selected(TOOL_COPY);
206
} else if (ED_IS_SHORTCUT("scene_tree/paste_node", p_event)) {
207
_tool_selected(TOOL_PASTE);
208
} else if (ED_IS_SHORTCUT("scene_tree/paste_node_as_sibling", p_event)) {
209
_tool_selected(TOOL_PASTE_AS_SIBLING);
210
} else if (ED_IS_SHORTCUT("scene_tree/change_node_type", p_event)) {
211
_tool_selected(TOOL_REPLACE);
212
} else if (ED_IS_SHORTCUT("scene_tree/duplicate", p_event)) {
213
_tool_selected(TOOL_DUPLICATE);
214
} else if (ED_IS_SHORTCUT("scene_tree/attach_script", p_event)) {
215
_tool_selected(TOOL_ATTACH_SCRIPT);
216
} else if (ED_IS_SHORTCUT("scene_tree/detach_script", p_event)) {
217
_tool_selected(TOOL_DETACH_SCRIPT);
218
} else if (ED_IS_SHORTCUT("scene_tree/move_up", p_event)) {
219
_tool_selected(TOOL_MOVE_UP);
220
} else if (ED_IS_SHORTCUT("scene_tree/move_down", p_event)) {
221
_tool_selected(TOOL_MOVE_DOWN);
222
} else if (ED_IS_SHORTCUT("scene_tree/reparent", p_event)) {
223
_tool_selected(TOOL_REPARENT);
224
} else if (ED_IS_SHORTCUT("scene_tree/reparent_to_new_node", p_event)) {
225
_tool_selected(TOOL_REPARENT_TO_NEW_NODE);
226
} else if (ED_IS_SHORTCUT("scene_tree/save_branch_as_scene", p_event)) {
227
_tool_selected(TOOL_NEW_SCENE_FROM);
228
} else if (ED_IS_SHORTCUT("scene_tree/delete_no_confirm", p_event)) {
229
_tool_selected(TOOL_ERASE, true);
230
} else if (ED_IS_SHORTCUT("scene_tree/copy_node_path", p_event)) {
231
_tool_selected(TOOL_COPY_NODE_PATH);
232
} else if (ED_IS_SHORTCUT("scene_tree/show_in_file_system", p_event)) {
233
_tool_selected(TOOL_SHOW_IN_FILE_SYSTEM);
234
} else if (ED_IS_SHORTCUT("scene_tree/toggle_unique_name", p_event)) {
235
_tool_selected(TOOL_TOGGLE_SCENE_UNIQUE_NAME);
236
} else if (ED_IS_SHORTCUT("scene_tree/toggle_editable_children", p_event)) {
237
_tool_selected(TOOL_SCENE_EDITABLE_CHILDREN);
238
} else if (ED_IS_SHORTCUT("scene_tree/delete", p_event)) {
239
_tool_selected(TOOL_ERASE);
240
} else {
241
Callable custom_callback = EditorContextMenuPluginManager::get_singleton()->match_custom_shortcut(EditorContextMenuPlugin::CONTEXT_SLOT_SCENE_TREE, p_event);
242
if (custom_callback.is_valid()) {
243
EditorContextMenuPluginManager::get_singleton()->invoke_callback(custom_callback, _get_selection_array());
244
} else {
245
return;
246
}
247
}
248
249
// Tool selection was successful, accept the event to stop propagation.
250
accept_event();
251
}
252
253
void SceneTreeDock::_scene_tree_gui_input(Ref<InputEvent> p_event) {
254
Ref<InputEventKey> key = p_event;
255
256
if (key.is_null() || !key->is_pressed() || key->is_echo()) {
257
return;
258
}
259
260
if (ED_IS_SHORTCUT("editor/open_search", p_event)) {
261
filter->grab_focus();
262
filter->select_all();
263
accept_event();
264
}
265
}
266
267
void SceneTreeDock::instantiate(const String &p_file) {
268
Vector<String> scenes;
269
scenes.push_back(p_file);
270
instantiate_scenes(scenes, scene_tree->get_selected());
271
}
272
273
void SceneTreeDock::instantiate_scenes(const Vector<String> &p_files, Node *p_parent) {
274
Node *parent = p_parent;
275
276
if (!parent) {
277
parent = scene_tree->get_selected();
278
}
279
280
if (!parent) {
281
parent = edited_scene;
282
}
283
284
if (!parent) {
285
if (p_files.size() == 1) {
286
accept->set_text(TTR("No parent to instantiate a child at."));
287
} else {
288
accept->set_text(TTR("No parent to instantiate the scenes at."));
289
}
290
accept->popup_centered();
291
return;
292
};
293
294
_perform_instantiate_scenes(p_files, parent, -1);
295
}
296
297
void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, Node *p_parent, int p_pos) {
298
ERR_FAIL_NULL(p_parent);
299
300
Vector<Node *> instances;
301
302
bool error = false;
303
304
for (int i = 0; i < p_files.size(); i++) {
305
Ref<PackedScene> sdata = ResourceLoader::load(p_files[i]);
306
if (sdata.is_null()) {
307
current_option = -1;
308
accept->set_text(vformat(TTR("Error loading scene from %s"), p_files[i]));
309
accept->popup_centered();
310
error = true;
311
break;
312
}
313
314
Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
315
if (!instantiated_scene) {
316
current_option = -1;
317
accept->set_text(vformat(TTR("Error instantiating scene from %s"), p_files[i]));
318
accept->popup_centered();
319
error = true;
320
break;
321
}
322
323
if (!edited_scene->get_scene_file_path().is_empty()) {
324
if (_cyclical_dependency_exists(edited_scene->get_scene_file_path(), instantiated_scene)) {
325
accept->set_text(vformat(TTR("Cannot instantiate the scene '%s' because the current scene exists within one of its nodes."), p_files[i]));
326
accept->popup_centered();
327
error = true;
328
break;
329
}
330
}
331
332
instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(p_files[i]));
333
334
instances.push_back(instantiated_scene);
335
}
336
337
if (error) {
338
for (int i = 0; i < instances.size(); i++) {
339
memdelete(instances[i]);
340
}
341
return;
342
}
343
344
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
345
undo_redo->create_action_for_history(TTRN("Instantiate Scene", "Instantiate Scenes", instances.size()), editor_data->get_current_edited_scene_history_id());
346
undo_redo->add_do_method(editor_selection, "clear");
347
348
for (int i = 0; i < instances.size(); i++) {
349
Node *instantiated_scene = instances[i];
350
351
undo_redo->add_do_method(p_parent, "add_child", instantiated_scene, true);
352
if (p_pos >= 0) {
353
undo_redo->add_do_method(p_parent, "move_child", instantiated_scene, p_pos + i);
354
}
355
undo_redo->add_do_method(instantiated_scene, "set_owner", edited_scene);
356
undo_redo->add_do_method(editor_selection, "add_node", instantiated_scene);
357
undo_redo->add_do_reference(instantiated_scene);
358
undo_redo->add_undo_method(p_parent, "remove_child", instantiated_scene);
359
360
String new_name = p_parent->validate_child_name(instantiated_scene);
361
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
362
undo_redo->add_do_method(ed, "live_debug_instantiate_node", edited_scene->get_path_to(p_parent), p_files[i], new_name);
363
undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).path_join(new_name)));
364
}
365
366
undo_redo->commit_action();
367
_push_item(instances[instances.size() - 1]);
368
for (int i = 0; i < instances.size(); i++) {
369
emit_signal(SNAME("node_created"), instances[i]);
370
}
371
}
372
373
void SceneTreeDock::_perform_create_audio_stream_players(const Vector<String> &p_files, Node *p_parent, int p_pos) {
374
ERR_FAIL_NULL(p_parent);
375
376
StringName node_type = "AudioStreamPlayer";
377
if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
378
if (Object::cast_to<Node2D>(p_parent)) {
379
node_type = "AudioStreamPlayer2D";
380
} else if (Object::cast_to<Node3D>(p_parent)) {
381
node_type = "AudioStreamPlayer3D";
382
}
383
}
384
385
Vector<Node *> nodes;
386
bool error = false;
387
388
for (const String &path : p_files) {
389
Ref<AudioStream> stream = ResourceLoader::load(path);
390
if (stream.is_null()) {
391
current_option = -1;
392
accept->set_text(vformat(TTR("Error loading audio stream from %s"), path));
393
accept->popup_centered();
394
error = true;
395
break;
396
}
397
398
Node *player = Object::cast_to<Node>(ClassDB::instantiate(node_type));
399
player->set("stream", stream);
400
401
// Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others.
402
const String &node_name = Node::adjust_name_casing(path.get_file().get_basename());
403
if (!node_name.is_empty()) {
404
player->set_name(node_name);
405
}
406
407
nodes.push_back(player);
408
}
409
410
if (error) {
411
for (Node *node : nodes) {
412
memdelete(node);
413
}
414
return;
415
}
416
417
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
418
undo_redo->create_action_for_history(TTRN("Create AudioStreamPlayer", "Create AudioStreamPlayers", nodes.size()), editor_data->get_current_edited_scene_history_id());
419
undo_redo->add_do_method(editor_selection, "clear");
420
421
for (int i = 0; i < nodes.size(); i++) {
422
Node *node = nodes[i];
423
424
undo_redo->add_do_method(p_parent, "add_child", node, true);
425
if (p_pos >= 0) {
426
undo_redo->add_do_method(p_parent, "move_child", node, p_pos + i);
427
}
428
undo_redo->add_do_method(node, "set_owner", edited_scene);
429
undo_redo->add_do_method(editor_selection, "add_node", node);
430
undo_redo->add_do_reference(node);
431
undo_redo->add_undo_method(p_parent, "remove_child", node);
432
433
String new_name = p_parent->validate_child_name(node);
434
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
435
undo_redo->add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(p_parent), node->get_class(), new_name);
436
undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).path_join(new_name)));
437
}
438
439
undo_redo->commit_action();
440
}
441
442
void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *p_base) {
443
// `move_child` + `get_index` doesn't really work for internal nodes.
444
ERR_FAIL_COND_MSG(p_base->is_internal(), "Trying to replace internal node, this is not supported.");
445
446
Ref<PackedScene> sdata = ResourceLoader::load(p_file);
447
if (sdata.is_null()) {
448
accept->set_text(vformat(TTR("Error loading scene from %s"), p_file));
449
accept->popup_centered();
450
return;
451
}
452
453
Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
454
if (!instantiated_scene) {
455
accept->set_text(vformat(TTR("Error instantiating scene from %s"), p_file));
456
accept->popup_centered();
457
return;
458
}
459
460
instantiated_scene->set_unique_name_in_owner(p_base->is_unique_name_in_owner());
461
462
Node2D *copy_2d = Object::cast_to<Node2D>(instantiated_scene);
463
Node2D *base_2d = Object::cast_to<Node2D>(p_base);
464
if (copy_2d && base_2d) {
465
copy_2d->set_position(base_2d->get_position());
466
copy_2d->set_rotation(base_2d->get_rotation());
467
copy_2d->set_scale(base_2d->get_scale());
468
}
469
470
Node3D *copy_3d = Object::cast_to<Node3D>(instantiated_scene);
471
Node3D *base_3d = Object::cast_to<Node3D>(p_base);
472
if (copy_3d && base_3d) {
473
copy_3d->set_position(base_3d->get_position());
474
copy_3d->set_rotation(base_3d->get_rotation());
475
copy_3d->set_scale(base_3d->get_scale());
476
}
477
478
// Ensure that local signals are still connected.
479
List<MethodInfo> signal_list;
480
p_base->get_signal_list(&signal_list);
481
for (const MethodInfo &meth : signal_list) {
482
List<Object::Connection> connection_list;
483
p_base->get_signal_connection_list(meth.name, &connection_list);
484
485
List<Object::Connection> other;
486
instantiated_scene->get_signal_connection_list(meth.name, &other);
487
488
for (const Object::Connection &con : connection_list) {
489
if (!(con.flags & Object::CONNECT_PERSIST)) {
490
continue;
491
}
492
// May be already connected if the connection was saved with the scene.
493
bool already_connected = false; // Can't use is_connected(), because of different targets.
494
for (const Object::Connection &otcon : other) {
495
if (otcon.signal.get_name() == con.signal.get_name() && otcon.callable.get_method() == con.callable.get_method()) {
496
already_connected = true;
497
break;
498
}
499
}
500
if (!already_connected) {
501
instantiated_scene->connect(con.signal.get_name(), con.callable, con.flags);
502
}
503
}
504
}
505
506
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
507
undo_redo->create_action(TTR("Replace with Branch Scene"));
508
509
Node *parent = p_base->get_parent();
510
int pos = p_base->get_index(false);
511
undo_redo->add_do_method(parent, "remove_child", p_base);
512
undo_redo->add_undo_method(parent, "remove_child", instantiated_scene);
513
undo_redo->add_do_method(parent, "add_child", instantiated_scene, true);
514
undo_redo->add_undo_method(parent, "add_child", p_base, true);
515
undo_redo->add_do_method(parent, "move_child", instantiated_scene, pos);
516
undo_redo->add_undo_method(parent, "move_child", p_base, pos);
517
518
List<Node *> owned;
519
p_base->get_owned_by(p_base->get_owner(), &owned);
520
Array owners;
521
for (Node *F : owned) {
522
owners.push_back(F);
523
}
524
undo_redo->add_do_method(instantiated_scene, "set_owner", edited_scene);
525
undo_redo->add_undo_method(this, "_set_owners", edited_scene, owners);
526
527
undo_redo->add_do_method(editor_selection, "clear");
528
undo_redo->add_undo_method(editor_selection, "clear");
529
undo_redo->add_do_method(editor_selection, "add_node", instantiated_scene);
530
undo_redo->add_undo_method(editor_selection, "add_node", p_base);
531
undo_redo->add_do_property(scene_tree, "set_selected", instantiated_scene);
532
undo_redo->add_undo_property(scene_tree, "set_selected", p_base);
533
534
undo_redo->add_do_reference(instantiated_scene);
535
undo_redo->add_undo_reference(p_base);
536
undo_redo->commit_action();
537
}
538
539
bool SceneTreeDock::_cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node) {
540
int childCount = p_desired_node->get_child_count();
541
542
if (_track_inherit(p_target_scene_path, p_desired_node)) {
543
return true;
544
}
545
546
for (int i = 0; i < childCount; i++) {
547
Node *child = p_desired_node->get_child(i);
548
549
if (_cyclical_dependency_exists(p_target_scene_path, child)) {
550
return true;
551
}
552
}
553
554
return false;
555
}
556
557
bool SceneTreeDock::_track_inherit(const String &p_target_scene_path, Node *p_desired_node) {
558
Node *p = p_desired_node;
559
bool result = false;
560
Vector<Node *> instances;
561
while (true) {
562
if (p->get_scene_file_path() == p_target_scene_path) {
563
result = true;
564
break;
565
}
566
Ref<SceneState> ss = p->get_scene_inherited_state();
567
if (ss.is_valid()) {
568
String path = ss->get_path();
569
Ref<PackedScene> pack_data = ResourceLoader::load(path);
570
if (pack_data.is_valid()) {
571
p = pack_data->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
572
if (!p) {
573
continue;
574
}
575
instances.push_back(p);
576
} else {
577
break;
578
}
579
} else {
580
break;
581
}
582
}
583
for (int i = 0; i < instances.size(); i++) {
584
memdelete(instances[i]);
585
}
586
return result;
587
}
588
589
void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
590
current_option = p_tool;
591
592
switch (p_tool) {
593
case TOOL_BATCH_RENAME: {
594
if (!profile_allow_editing) {
595
break;
596
}
597
if (editor_selection->get_selection().size() > 1) {
598
if (!_validate_no_foreign()) {
599
break;
600
}
601
rename_dialog->popup_centered();
602
}
603
} break;
604
case TOOL_RENAME: {
605
if (!profile_allow_editing) {
606
break;
607
}
608
Tree *tree = scene_tree->get_scene_tree();
609
if (tree->is_anything_selected()) {
610
if (!_validate_no_foreign()) {
611
break;
612
}
613
tree->grab_focus(!tree->has_focus(true));
614
tree->edit_selected();
615
}
616
} break;
617
case TOOL_REPARENT_TO_NEW_NODE:
618
if (!_validate_no_foreign()) {
619
break;
620
}
621
[[fallthrough]];
622
case TOOL_NEW: {
623
if (!profile_allow_editing) {
624
break;
625
}
626
627
if (reset_create_dialog && !p_confirm_override) {
628
create_dialog->set_base_type("Node");
629
reset_create_dialog = false;
630
}
631
632
// Prefer nodes that inherit from the current scene root.
633
Node *current_edited_scene_root = EditorNode::get_singleton()->get_edited_scene();
634
if (current_edited_scene_root) {
635
String root_class = current_edited_scene_root->get_class_name();
636
static Vector<String> preferred_types;
637
if (preferred_types.is_empty()) {
638
preferred_types.push_back("Control");
639
preferred_types.push_back("Node2D");
640
preferred_types.push_back("Node3D");
641
}
642
643
for (int i = 0; i < preferred_types.size(); i++) {
644
if (ClassDB::is_parent_class(root_class, preferred_types[i])) {
645
create_dialog->set_preferred_search_result_type(preferred_types[i]);
646
break;
647
}
648
}
649
}
650
651
create_dialog->popup_create(true);
652
if (!p_confirm_override) {
653
emit_signal(SNAME("add_node_used"));
654
}
655
} break;
656
case TOOL_INSTANTIATE: {
657
if (!profile_allow_editing) {
658
break;
659
}
660
Node *scene = edited_scene;
661
662
if (!scene) {
663
EditorNode::get_singleton()->new_inherited_scene();
664
break;
665
}
666
667
EditorNode::get_singleton()->get_quick_open_dialog()->popup_dialog({ "PackedScene" }, callable_mp(this, &SceneTreeDock::_quick_open));
668
if (!p_confirm_override) {
669
emit_signal(SNAME("add_node_used"));
670
}
671
} break;
672
case TOOL_EXPAND_COLLAPSE: {
673
Tree *tree = scene_tree->get_scene_tree();
674
TreeItem *selected_item = tree->get_selected();
675
676
if (!selected_item) {
677
selected_item = tree->get_root();
678
if (!selected_item) {
679
break;
680
}
681
}
682
683
bool collapsed = selected_item->is_any_collapsed();
684
selected_item->set_collapsed_recursive(!collapsed);
685
686
tree->ensure_cursor_is_visible();
687
688
} break;
689
case TOOL_CUT:
690
case TOOL_COPY: {
691
if (!edited_scene || (p_tool == TOOL_CUT && !_validate_no_foreign())) {
692
break;
693
}
694
695
List<Node *> selection = editor_selection->get_top_selected_node_list();
696
if (selection.is_empty()) {
697
break;
698
}
699
700
bool was_empty = false;
701
if (!node_clipboard.is_empty()) {
702
_clear_clipboard();
703
} else {
704
was_empty = true;
705
}
706
clipboard_source_scene = EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path();
707
708
selection.sort_custom<Node::Comparator>();
709
710
for (Node *node : selection) {
711
HashMap<const Node *, Node *> duplimap;
712
Node *dup = node->duplicate_from_editor(duplimap);
713
714
ERR_CONTINUE(!dup);
715
716
// Preserve ownership relations ready for pasting.
717
List<Node *> owned;
718
Node *owner = node;
719
while (owner) {
720
List<Node *> cur_owned;
721
node->get_owned_by(owner, &cur_owned);
722
owner = owner->get_owner();
723
for (Node *F : cur_owned) {
724
owned.push_back(F);
725
}
726
}
727
728
for (Node *F : owned) {
729
if (!duplimap.has(F) || F == node) {
730
continue;
731
}
732
Node *d = duplimap[F];
733
// Only use nullptr as a marker that ownership may need to be assigned when pasting.
734
// The ownership is subsequently tracked in the node_clipboard_edited_scene_owned list.
735
d->set_owner(nullptr);
736
node_clipboard_edited_scene_owned.insert(d);
737
}
738
739
node_clipboard.push_back(dup);
740
}
741
742
if (p_tool == TOOL_CUT) {
743
_delete_confirm(true);
744
}
745
746
if (was_empty) {
747
_update_create_root_dialog();
748
}
749
} break;
750
case TOOL_PASTE: {
751
paste_nodes(false);
752
} break;
753
case TOOL_PASTE_AS_SIBLING: {
754
paste_nodes(true);
755
} break;
756
case TOOL_REPLACE: {
757
if (!profile_allow_editing) {
758
break;
759
}
760
761
if (!_validate_no_foreign()) {
762
break;
763
}
764
765
if (!_validate_no_instance()) {
766
break;
767
}
768
769
if (reset_create_dialog) {
770
create_dialog->set_base_type("Node");
771
reset_create_dialog = false;
772
}
773
774
Node *selected = scene_tree->get_selected();
775
const List<Node *> &top_node_list = editor_selection->get_top_selected_node_list();
776
if (!selected && !top_node_list.is_empty()) {
777
selected = top_node_list.front()->get();
778
}
779
780
if (selected) {
781
create_dialog->popup_create(false, true, selected->get_class(), selected->get_name());
782
}
783
} break;
784
case TOOL_EXTEND_SCRIPT: {
785
attach_script_to_selected(true);
786
} break;
787
case TOOL_ATTACH_SCRIPT: {
788
attach_script_to_selected(false);
789
} break;
790
case TOOL_DETACH_SCRIPT: {
791
if (!profile_allow_script_editing) {
792
break;
793
}
794
795
Array selection = editor_selection->get_selected_nodes();
796
797
if (selection.is_empty()) {
798
return;
799
}
800
801
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
802
undo_redo->create_action(TTR("Detach Script"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
803
804
for (int i = 0; i < selection.size(); i++) {
805
Node *n = Object::cast_to<Node>(selection[i]);
806
Ref<Script> existing = n->get_script();
807
Ref<Script> empty = EditorNode::get_singleton()->get_object_custom_type_base(n);
808
if (existing != empty) {
809
undo_redo->add_do_method(n, "set_script", empty);
810
undo_redo->add_undo_method(n, "set_script", existing);
811
812
List<PropertyInfo> properties;
813
n->get_property_list(&properties);
814
for (const PropertyInfo &property : properties) {
815
if (property.usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR)) {
816
undo_redo->add_undo_property(n, property.name, n->get(property.name));
817
}
818
}
819
}
820
}
821
822
undo_redo->add_do_method(this, "_queue_update_script_button");
823
undo_redo->add_undo_method(this, "_queue_update_script_button");
824
825
undo_redo->commit_action();
826
} break;
827
case TOOL_MOVE_UP:
828
case TOOL_MOVE_DOWN: {
829
if (!profile_allow_editing) {
830
break;
831
}
832
833
if (!scene_tree->get_selected()) {
834
break;
835
}
836
837
if (scene_tree->get_selected() == edited_scene) {
838
current_option = -1;
839
accept->set_text(TTR("This operation can't be done on the tree root."));
840
accept->popup_centered();
841
break;
842
}
843
844
if (!_validate_no_foreign()) {
845
break;
846
}
847
848
bool MOVING_DOWN = (p_tool == TOOL_MOVE_DOWN);
849
bool MOVING_UP = !MOVING_DOWN;
850
851
List<Node *> selection = editor_selection->get_full_selected_node_list();
852
selection.sort_custom<Node::Comparator>(); // sort by index
853
if (MOVING_DOWN) {
854
selection.reverse();
855
}
856
857
bool is_nowhere_to_move = false;
858
for (Node *E : selection) {
859
// `move_child` + `get_index` doesn't really work for internal nodes.
860
ERR_FAIL_COND_MSG(E->is_internal(), "Trying to move internal node, this is not supported.");
861
862
if ((MOVING_DOWN && (E->get_index() == E->get_parent()->get_child_count(false) - 1)) || (MOVING_UP && (E->get_index() == 0))) {
863
is_nowhere_to_move = true;
864
break;
865
}
866
}
867
if (is_nowhere_to_move) {
868
break;
869
}
870
871
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
872
if (selection.size() == 1) {
873
undo_redo->create_action(TTR("Move Node in Parent"));
874
}
875
if (selection.size() > 1) {
876
undo_redo->create_action(TTR("Move Nodes in Parent"));
877
}
878
879
for (List<Node *>::Element *top_E = selection.front(), *bottom_E = selection.back(); top_E && bottom_E; top_E = top_E->next(), bottom_E = bottom_E->prev()) {
880
Node *top_node = top_E->get();
881
Node *bottom_node = bottom_E->get();
882
883
ERR_FAIL_NULL(top_node->get_parent());
884
ERR_FAIL_NULL(bottom_node->get_parent());
885
886
int bottom_node_pos = bottom_node->get_index(false);
887
int top_node_pos_next = top_node->get_index(false) + (MOVING_DOWN ? 1 : -1);
888
889
undo_redo->add_do_method(top_node->get_parent(), "move_child", top_node, top_node_pos_next);
890
undo_redo->add_undo_method(bottom_node->get_parent(), "move_child", bottom_node, bottom_node_pos);
891
}
892
893
undo_redo->commit_action();
894
895
NodePath np = selection.front()->get()->get_path();
896
TreeItem *item = scene_tree->get_scene_tree()->get_item_with_metadata(np);
897
callable_mp(scene_tree->get_scene_tree(), &Tree::scroll_to_item).call_deferred(item, false);
898
} break;
899
case TOOL_DUPLICATE: {
900
if (!profile_allow_editing) {
901
break;
902
}
903
904
if (!edited_scene) {
905
break;
906
}
907
908
if (editor_selection->is_selected(edited_scene)) {
909
current_option = -1;
910
accept->set_text(TTR("This operation can't be done on the tree root."));
911
accept->popup_centered();
912
break;
913
}
914
915
List<Node *> selection = editor_selection->get_top_selected_node_list();
916
if (selection.is_empty()) {
917
break;
918
}
919
920
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
921
undo_redo->create_action(TTR("Duplicate Node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get());
922
undo_redo->add_do_method(editor_selection, "clear");
923
924
Node *dupsingle = nullptr;
925
926
selection.sort_custom<Node::Comparator>();
927
928
HashMap<const Node *, Node *> add_below_map;
929
930
for (List<Node *>::Element *E = selection.back(); E; E = E->prev()) {
931
Node *node = E->get();
932
if (!add_below_map.has(node->get_parent())) {
933
add_below_map.insert(node->get_parent(), node);
934
}
935
}
936
937
HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &resources_local_to_scenes = clipboard_resource_remap[edited_scene->get_scene_file_path()];
938
939
for (Node *node : selection) {
940
Node *parent = node->get_parent();
941
942
List<Node *> owned;
943
Node *owner = node;
944
while (owner) {
945
List<Node *> cur_owned;
946
node->get_owned_by(owner, &cur_owned);
947
owner = owner->get_owner();
948
for (Node *F : cur_owned) {
949
owned.push_back(F);
950
}
951
}
952
953
HashMap<const Node *, Node *> duplimap;
954
Node *dup = node->duplicate_from_editor(duplimap, edited_scene, resources_local_to_scenes);
955
956
ERR_CONTINUE(!dup);
957
958
if (selection.size() == 1) {
959
dupsingle = dup;
960
}
961
962
dup->set_name(parent->validate_child_name(dup));
963
964
undo_redo->add_do_method(add_below_map[parent], "add_sibling", dup, true);
965
966
for (Node *F : owned) {
967
if (!duplimap.has(F)) {
968
continue;
969
}
970
Node *d = duplimap[F];
971
undo_redo->add_do_method(d, "set_owner", edited_scene);
972
}
973
undo_redo->add_do_method(editor_selection, "add_node", dup);
974
undo_redo->add_do_method(dup, "set_owner", edited_scene);
975
undo_redo->add_undo_method(parent, "remove_child", dup);
976
undo_redo->add_do_reference(dup);
977
978
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
979
980
undo_redo->add_do_method(ed, "live_debug_duplicate_node", edited_scene->get_path_to(node), dup->get_name());
981
undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).path_join(dup->get_name())));
982
983
add_below_map[parent] = dup;
984
}
985
986
undo_redo->commit_action();
987
988
for (KeyValue<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &KV : resources_local_to_scenes) {
989
for (KeyValue<Ref<Resource>, Ref<Resource>> &R : KV.value) {
990
if (R.value->is_local_to_scene()) {
991
R.value->setup_local_to_scene();
992
}
993
}
994
}
995
996
if (dupsingle) {
997
_push_item(dupsingle);
998
}
999
} break;
1000
case TOOL_REPARENT: {
1001
if (!profile_allow_editing) {
1002
break;
1003
}
1004
1005
if (!scene_tree->get_selected()) {
1006
break;
1007
}
1008
1009
if (editor_selection->is_selected(edited_scene)) {
1010
current_option = -1;
1011
accept->set_text(TTR("This operation can't be done on the tree root."));
1012
accept->popup_centered();
1013
break;
1014
}
1015
1016
if (!_validate_no_foreign()) {
1017
break;
1018
}
1019
1020
List<Node *> nodes = editor_selection->get_top_selected_node_list();
1021
HashSet<Node *> nodeset;
1022
for (Node *E : nodes) {
1023
nodeset.insert(E);
1024
}
1025
reparent_dialog->set_current(nodeset);
1026
reparent_dialog->popup_centered_clamped(Size2(350, 700) * EDSCALE);
1027
} break;
1028
case TOOL_MAKE_ROOT: {
1029
if (!profile_allow_editing) {
1030
break;
1031
}
1032
1033
List<Node *> nodes = editor_selection->get_top_selected_node_list();
1034
ERR_FAIL_COND(nodes.size() != 1);
1035
1036
Node *node = nodes.front()->get();
1037
Node *root = get_tree()->get_edited_scene_root();
1038
1039
if (node == root) {
1040
return;
1041
}
1042
1043
// `move_child` + `get_index` doesn't really work for internal nodes.
1044
ERR_FAIL_COND_MSG(node->is_internal(), "Trying to set internal node as scene root, this is not supported.");
1045
1046
//check that from node to root, all owners are right
1047
1048
if (root->get_scene_inherited_state().is_valid()) {
1049
accept->set_text(TTR("Can't reparent nodes in inherited scenes, order of nodes can't change."));
1050
accept->popup_centered();
1051
return;
1052
}
1053
1054
if (node->get_owner() != root) {
1055
accept->set_text(TTR("Node must belong to the edited scene to become root."));
1056
accept->popup_centered();
1057
return;
1058
}
1059
1060
if (node->is_instance()) {
1061
accept->set_text(TTR("Instantiated scenes can't become root"));
1062
accept->popup_centered();
1063
return;
1064
}
1065
1066
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
1067
undo_redo->create_action(TTR("Make node as Root"));
1068
undo_redo->add_do_method(node->get_parent(), "remove_child", node);
1069
undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", node);
1070
undo_redo->add_do_method(node, "add_child", root, true);
1071
undo_redo->add_do_method(node, "set_scene_file_path", root->get_scene_file_path());
1072
undo_redo->add_do_method(root, "set_scene_file_path", String());
1073
undo_redo->add_do_method(node, "set_owner", (Object *)nullptr);
1074
undo_redo->add_do_method(root, "set_owner", node);
1075
undo_redo->add_do_method(node, "set_unique_name_in_owner", false);
1076
_node_replace_owner(root, root, node, MODE_DO);
1077
1078
undo_redo->add_undo_method(root, "set_scene_file_path", root->get_scene_file_path());
1079
undo_redo->add_undo_method(node, "set_scene_file_path", String());
1080
undo_redo->add_undo_method(node, "remove_child", root);
1081
undo_redo->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", root);
1082
undo_redo->add_undo_method(node->get_parent(), "add_child", node, true);
1083
undo_redo->add_undo_method(node->get_parent(), "move_child", node, node->get_index(false));
1084
undo_redo->add_undo_method(root, "set_owner", (Object *)nullptr);
1085
undo_redo->add_undo_method(node, "set_owner", root);
1086
undo_redo->add_undo_method(node, "set_unique_name_in_owner", node->is_unique_name_in_owner());
1087
_node_replace_owner(root, root, root, MODE_UNDO);
1088
1089
undo_redo->add_do_method(scene_tree, "update_tree");
1090
undo_redo->add_undo_method(scene_tree, "update_tree");
1091
undo_redo->commit_action();
1092
} break;
1093
case TOOL_MULTI_EDIT: {
1094
if (!profile_allow_editing) {
1095
break;
1096
}
1097
1098
Node *root = EditorNode::get_singleton()->get_edited_scene();
1099
if (!root) {
1100
break;
1101
}
1102
Ref<MultiNodeEdit> mne = memnew(MultiNodeEdit);
1103
for (const KeyValue<ObjectID, Object *> &E : editor_selection->get_selection()) {
1104
Node *node = ObjectDB::get_instance<Node>(E.key);
1105
if (node) {
1106
mne->add_node(root->get_path_to(node));
1107
}
1108
}
1109
1110
_push_item(mne.ptr());
1111
1112
} break;
1113
1114
case TOOL_ERASE: {
1115
if (!profile_allow_editing) {
1116
break;
1117
}
1118
1119
List<Node *> remove_list = editor_selection->get_top_selected_node_list();
1120
1121
if (remove_list.is_empty()) {
1122
return;
1123
}
1124
1125
if (!_validate_no_foreign()) {
1126
break;
1127
}
1128
1129
bool allow_ask_delete_tracks = EDITOR_GET("docks/scene_tree/ask_before_deleting_related_animation_tracks").operator bool();
1130
bool has_tracks_to_delete = allow_ask_delete_tracks && _has_tracks_to_delete(edited_scene, remove_list);
1131
if (p_confirm_override && !has_tracks_to_delete) {
1132
_delete_confirm();
1133
} else {
1134
String msg;
1135
if (remove_list.size() > 1) {
1136
bool any_children = false;
1137
for (List<Node *>::ConstIterator itr = remove_list.begin(); !any_children && itr != remove_list.end(); ++itr) {
1138
any_children = (*itr)->get_child_count() > 0;
1139
}
1140
1141
msg = vformat(any_children ? TTR("Delete %d nodes and any children?") : TTR("Delete %d nodes?"), remove_list.size());
1142
} else {
1143
if (!p_confirm_override) {
1144
Node *node = remove_list.front()->get();
1145
if (node == editor_data->get_edited_scene_root()) {
1146
msg = vformat(TTR("Delete the root node \"%s\"?"), node->get_name());
1147
} else if (!node->is_instance() && node->get_child_count() > 0) {
1148
// Display this message only for non-instantiated scenes.
1149
msg = vformat(TTR("Delete node \"%s\" and its children?"), node->get_name());
1150
} else {
1151
msg = vformat(TTR("Delete node \"%s\"?"), node->get_name());
1152
}
1153
}
1154
1155
if (has_tracks_to_delete) {
1156
if (!msg.is_empty()) {
1157
msg += "\n";
1158
}
1159
msg += TTR("Some nodes are referenced by animation tracks.");
1160
delete_tracks_checkbox->show();
1161
} else {
1162
delete_tracks_checkbox->hide();
1163
}
1164
}
1165
1166
delete_dialog_label->set_text(msg);
1167
1168
// Resize the dialog to its minimum size.
1169
// This prevents the dialog from being too wide after displaying
1170
// a deletion confirmation for a node with a long name.
1171
delete_dialog->reset_size();
1172
delete_dialog->popup_centered();
1173
}
1174
1175
} break;
1176
case TOOL_NEW_SCENE_FROM: {
1177
if (!profile_allow_editing) {
1178
break;
1179
}
1180
1181
Node *scene = editor_data->get_edited_scene_root();
1182
1183
if (!scene) {
1184
accept->set_text(TTR("Saving the branch as a scene requires having a scene open in the editor."));
1185
accept->popup_centered();
1186
break;
1187
}
1188
1189
const List<Node *> selection = editor_selection->get_top_selected_node_list();
1190
1191
if (selection.size() != 1) {
1192
accept->set_text(vformat(TTR("Saving the branch as a scene requires selecting only one node, but you have selected %d nodes."), selection.size()));
1193
accept->popup_centered();
1194
break;
1195
}
1196
1197
Node *tocopy = selection.front()->get();
1198
1199
if (tocopy == scene) {
1200
accept->set_text(TTR("Can't save the root node branch as an instantiated scene.\nTo create an editable copy of the current scene, duplicate it using the FileSystem dock context menu\nor create an inherited scene using Scene > New Inherited Scene... instead."));
1201
accept->popup_centered();
1202
break;
1203
}
1204
1205
if (tocopy != editor_data->get_edited_scene_root() && tocopy->is_instance()) {
1206
accept->set_text(TTR("Can't save the branch of an already instantiated scene.\nTo create a variation of a scene, you can make an inherited scene based on the instantiated scene using Scene > New Inherited Scene... instead."));
1207
accept->popup_centered();
1208
break;
1209
}
1210
1211
if (tocopy->get_owner() != scene) {
1212
accept->set_text(TTR("Can't save a branch which is a child of an already instantiated scene.\nTo save this branch into its own scene, open the original scene, right click on this branch, and select \"Save Branch as Scene\"."));
1213
accept->popup_centered();
1214
break;
1215
}
1216
1217
if (scene->get_scene_inherited_state().is_valid() && scene->get_scene_inherited_state()->find_node_by_path(scene->get_path_to(tocopy)) >= 0) {
1218
accept->set_text(TTR("Can't save a branch which is part of an inherited scene.\nTo save this branch into its own scene, open the original scene, right click on this branch, and select \"Save Branch as Scene\"."));
1219
accept->popup_centered();
1220
break;
1221
}
1222
1223
new_scene_from_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
1224
if (determine_path_automatically) {
1225
new_scene_from_dialog->set_current_dir(editor_data->get_edited_scene_root()->get_scene_file_path().get_base_dir());
1226
} else {
1227
determine_path_automatically = true;
1228
}
1229
1230
List<String> extensions;
1231
Ref<PackedScene> sd = memnew(PackedScene);
1232
ResourceSaver::get_recognized_extensions(sd, &extensions);
1233
new_scene_from_dialog->clear_filters();
1234
for (const String &extension : extensions) {
1235
new_scene_from_dialog->add_filter("*." + extension, extension.to_upper());
1236
}
1237
1238
String existing;
1239
if (extensions.size()) {
1240
String root_name(tocopy->get_name());
1241
root_name = EditorNode::adjust_scene_name_casing(root_name);
1242
existing = root_name + "." + extensions.front()->get().to_lower();
1243
}
1244
new_scene_from_dialog->set_current_path(existing);
1245
1246
new_scene_from_dialog->set_title(TTR("Save New Scene As..."));
1247
new_scene_from_dialog->popup_file_dialog();
1248
} break;
1249
case TOOL_COPY_NODE_PATH: {
1250
const List<Node *> selection = editor_selection->get_top_selected_node_list();
1251
const List<Node *>::Element *e = selection.front();
1252
if (e) {
1253
Node *node = e->get();
1254
if (node) {
1255
Node *root = EditorNode::get_singleton()->get_edited_scene();
1256
NodePath path = root->get_path().rel_path_to(node->get_path());
1257
DisplayServer::get_singleton()->clipboard_set(String(path));
1258
}
1259
}
1260
} break;
1261
case TOOL_SHOW_IN_FILE_SYSTEM: {
1262
const List<Node *> selection = editor_selection->get_top_selected_node_list();
1263
const List<Node *>::Element *e = selection.front();
1264
if (e) {
1265
const Node *node = e->get();
1266
if (node) {
1267
FileSystemDock::get_singleton()->navigate_to_path(node->get_scene_file_path());
1268
}
1269
}
1270
} break;
1271
case TOOL_OPEN_DOCUMENTATION: {
1272
const List<Node *> selection = editor_selection->get_top_selected_node_list();
1273
for (const Node *node : selection) {
1274
String class_name;
1275
Ref<Script> script_base = node->get_script();
1276
while (script_base.is_valid()) {
1277
class_name = script_base->get_global_name();
1278
if (!class_name.is_empty()) {
1279
break;
1280
}
1281
script_base = script_base->get_base_script();
1282
}
1283
if (class_name.is_empty()) {
1284
class_name = node->get_class();
1285
}
1286
1287
ScriptEditor::get_singleton()->goto_help("class_name:" + class_name);
1288
}
1289
EditorNode::get_singleton()->get_editor_main_screen()->select(EditorMainScreen::EDITOR_SCRIPT);
1290
} break;
1291
case TOOL_AUTO_EXPAND: {
1292
scene_tree->set_auto_expand_selected(!EDITOR_GET("docks/scene_tree/auto_expand_to_selected"), true);
1293
} break;
1294
case TOOL_CENTER_PARENT: {
1295
EditorSettings::get_singleton()->set("docks/scene_tree/center_node_on_reparent", !EDITOR_GET("docks/scene_tree/center_node_on_reparent"));
1296
} break;
1297
case TOOL_HIDE_FILTERED_OUT_PARENTS: {
1298
scene_tree->set_hide_filtered_out_parents(!EDITOR_GET("docks/scene_tree/hide_filtered_out_parents"), true);
1299
} break;
1300
case TOOL_ACCESSIBILITY_WARNINGS: {
1301
scene_tree->set_accessibility_warnings(!EDITOR_GET("docks/scene_tree/accessibility_warnings"), true);
1302
} break;
1303
case TOOL_SCENE_EDITABLE_CHILDREN: {
1304
if (!profile_allow_editing) {
1305
break;
1306
}
1307
1308
const List<Node *> selection = editor_selection->get_top_selected_node_list();
1309
if (selection.size() != 1) {
1310
break;
1311
}
1312
1313
const List<Node *>::Element *e = selection.front();
1314
if (e) {
1315
Node *node = e->get();
1316
if (node) {
1317
bool is_external = node->is_instance();
1318
bool is_top_level = node->get_owner() == nullptr;
1319
if (!is_external || is_top_level) {
1320
break;
1321
}
1322
1323
bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(node);
1324
1325
if (editable) {
1326
editable_instance_remove_dialog->set_text(TTR("Disabling \"Editable Children\" will cause all properties of this subscene's descendant nodes to be reverted to their default."));
1327
editable_instance_remove_dialog->popup_centered();
1328
break;
1329
}
1330
_toggle_editable_children(node);
1331
}
1332
}
1333
} break;
1334
case TOOL_SCENE_USE_PLACEHOLDER: {
1335
if (!profile_allow_editing) {
1336
break;
1337
}
1338
1339
if (!_validate_no_foreign()) {
1340
break;
1341
}
1342
1343
const List<Node *> selection = editor_selection->get_top_selected_node_list();
1344
const List<Node *>::Element *e = selection.front();
1345
if (e) {
1346
Node *node = e->get();
1347
if (node) {
1348
bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(node);
1349
bool placeholder = node->get_scene_instance_load_placeholder();
1350
1351
// Fire confirmation dialog when children are editable.
1352
if (editable && !placeholder) {
1353
placeholder_editable_instance_remove_dialog->set_text(TTR("Enabling \"Load as Placeholder\" will disable \"Editable Children\" and cause all properties of the node to be reverted to their default."));
1354
placeholder_editable_instance_remove_dialog->popup_centered();
1355
break;
1356
}
1357
1358
placeholder = !placeholder;
1359
1360
if (placeholder) {
1361
EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node, false);
1362
}
1363
1364
node->set_scene_instance_load_placeholder(placeholder);
1365
scene_tree->update_tree();
1366
}
1367
}
1368
} break;
1369
case TOOL_SCENE_MAKE_LOCAL: {
1370
if (!profile_allow_editing) {
1371
break;
1372
}
1373
1374
if (!_validate_no_foreign()) {
1375
break;
1376
}
1377
1378
const List<Node *> selection = editor_selection->get_top_selected_node_list();
1379
const List<Node *>::Element *e = selection.front();
1380
if (e) {
1381
Node *node = e->get();
1382
if (node) {
1383
Node *root = EditorNode::get_singleton()->get_edited_scene();
1384
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
1385
if (!root) {
1386
break;
1387
}
1388
1389
ERR_FAIL_COND(!node->is_instance());
1390
undo_redo->create_action(TTR("Make Local"));
1391
undo_redo->add_do_method(node, "set_scene_file_path", "");
1392
undo_redo->add_undo_method(node, "set_scene_file_path", node->get_scene_file_path());
1393
_node_replace_owner(node, node, root);
1394
_node_strip_signal_inheritance(node);
1395
SignalsDock::get_singleton()->set_object(node); // Refresh.
1396
GroupsDock::get_singleton()->set_selection(Vector<Node *>{ node }); // Refresh.
1397
undo_redo->add_do_method(scene_tree, "update_tree");
1398
undo_redo->add_undo_method(scene_tree, "update_tree");
1399
undo_redo->commit_action();
1400
}
1401
}
1402
} break;
1403
case TOOL_SCENE_OPEN: {
1404
const List<Node *> selection = editor_selection->get_top_selected_node_list();
1405
const List<Node *>::Element *e = selection.front();
1406
if (e) {
1407
Node *node = e->get();
1408
if (node) {
1409
scene_tree->emit_signal(SNAME("open"), node->get_scene_file_path());
1410
}
1411
}
1412
} break;
1413
case TOOL_SCENE_CLEAR_INHERITANCE: {
1414
if (!profile_allow_editing) {
1415
break;
1416
}
1417
1418
clear_inherit_confirm->popup_centered();
1419
} break;
1420
case TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM: {
1421
if (!profile_allow_editing) {
1422
break;
1423
}
1424
1425
const List<Node *> selection = editor_selection->get_top_selected_node_list();
1426
const List<Node *>::Element *e = selection.front();
1427
if (e) {
1428
Node *node = e->get();
1429
if (node) {
1430
node->set_scene_inherited_state(Ref<SceneState>());
1431
editor_data->reload_scene_from_memory(editor_data->get_edited_scene(), true);
1432
scene_tree->clear_cache();
1433
InspectorDock::get_inspector_singleton()->update_tree();
1434
}
1435
}
1436
} break;
1437
case TOOL_SCENE_OPEN_INHERITED: {
1438
const List<Node *> selection = editor_selection->get_top_selected_node_list();
1439
const List<Node *>::Element *e = selection.front();
1440
if (e) {
1441
Node *node = e->get();
1442
if (node && node->get_scene_inherited_state().is_valid()) {
1443
scene_tree->emit_signal(SNAME("open"), node->get_scene_inherited_state()->get_path());
1444
}
1445
}
1446
} break;
1447
case TOOL_TOGGLE_SCENE_UNIQUE_NAME: {
1448
// Enabling/disabling based on the same node based on which the checkbox in the menu is checked/unchecked.
1449
const List<Node *>::Element *first_selected = editor_selection->get_top_selected_node_list().front();
1450
if (first_selected == nullptr) {
1451
return;
1452
}
1453
if (first_selected->get() == EditorNode::get_singleton()->get_edited_scene()) {
1454
// Exclude Root Node. It should never be unique name in its own scene!
1455
editor_selection->remove_node(first_selected->get());
1456
first_selected = editor_selection->get_top_selected_node_list().front();
1457
if (first_selected == nullptr) {
1458
return;
1459
}
1460
}
1461
1462
List<Node *> full_selection = editor_selection->get_full_selected_node_list();
1463
1464
// Check if all the nodes for this operation are invalid, and if they are, pop up a dialog and end here.
1465
bool all_nodes_owner_invalid = true;
1466
for (Node *node : full_selection) {
1467
if (node->get_owner() == get_tree()->get_edited_scene_root()) {
1468
all_nodes_owner_invalid = false;
1469
break;
1470
}
1471
}
1472
if (all_nodes_owner_invalid) {
1473
accept->set_text(TTR("Can't toggle unique name for nodes in subscene!"));
1474
accept->popup_centered();
1475
return;
1476
}
1477
1478
bool enabling = !first_selected->get()->is_unique_name_in_owner();
1479
1480
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
1481
1482
if (enabling) {
1483
Vector<Node *> new_unique_nodes;
1484
Vector<StringName> new_unique_names;
1485
Vector<StringName> cant_be_set_unique_names;
1486
1487
for (Node *node : full_selection) {
1488
if (node->is_unique_name_in_owner()) {
1489
continue;
1490
}
1491
if (node->get_owner() != get_tree()->get_edited_scene_root()) {
1492
continue;
1493
}
1494
1495
StringName name = node->get_name();
1496
if (new_unique_names.has(name) || get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(name)) != nullptr) {
1497
cant_be_set_unique_names.push_back(name);
1498
} else {
1499
new_unique_nodes.push_back(node);
1500
new_unique_names.push_back(name);
1501
}
1502
}
1503
1504
if (new_unique_nodes.size()) {
1505
undo_redo->create_action(TTR("Enable Scene Unique Name(s)"));
1506
for (Node *node : new_unique_nodes) {
1507
undo_redo->add_do_method(node, "set_unique_name_in_owner", true);
1508
undo_redo->add_undo_method(node, "set_unique_name_in_owner", false);
1509
}
1510
undo_redo->commit_action();
1511
}
1512
1513
if (cant_be_set_unique_names.size()) {
1514
String popup_text = TTR("Unique names already used by another node in the scene:");
1515
popup_text += "\n";
1516
for (const StringName &name : cant_be_set_unique_names) {
1517
popup_text += "\n" + String(name);
1518
}
1519
accept->set_text(popup_text);
1520
accept->popup_centered();
1521
}
1522
} else { // Disabling.
1523
undo_redo->create_action(TTR("Disable Scene Unique Name(s)"));
1524
for (Node *node : full_selection) {
1525
if (!node->is_unique_name_in_owner()) {
1526
continue;
1527
}
1528
if (node->get_owner() != get_tree()->get_edited_scene_root()) {
1529
continue;
1530
}
1531
undo_redo->add_do_method(node, "set_unique_name_in_owner", false);
1532
undo_redo->add_undo_method(node, "set_unique_name_in_owner", true);
1533
}
1534
undo_redo->commit_action();
1535
}
1536
} break;
1537
case TOOL_CREATE_2D_SCENE:
1538
case TOOL_CREATE_3D_SCENE:
1539
case TOOL_CREATE_USER_INTERFACE:
1540
case TOOL_CREATE_FAVORITE: {
1541
Node *new_node = nullptr;
1542
1543
if (TOOL_CREATE_FAVORITE == p_tool) {
1544
String name = selected_favorite_root.get_slicec(' ', 0);
1545
if (ScriptServer::is_global_class(name)) {
1546
Ref<Script> scr = ResourceLoader::load(ScriptServer::get_global_class_path(name), "Script");
1547
if (scr.is_valid()) {
1548
new_node = Object::cast_to<Node>(ClassDB::instantiate(scr->get_instance_base_type()));
1549
if (new_node) {
1550
new_node->set_script(scr);
1551
new_node->set_name(name);
1552
}
1553
}
1554
} else {
1555
new_node = Object::cast_to<Node>(ClassDB::instantiate(selected_favorite_root));
1556
}
1557
1558
if (!new_node) {
1559
new_node = memnew(Node);
1560
ERR_PRINT("Creating root from favorite '" + selected_favorite_root + "' failed. Creating 'Node' instead.");
1561
}
1562
} else {
1563
switch (p_tool) {
1564
case TOOL_CREATE_2D_SCENE:
1565
new_node = memnew(Node2D);
1566
break;
1567
case TOOL_CREATE_3D_SCENE:
1568
new_node = memnew(Node3D);
1569
break;
1570
case TOOL_CREATE_USER_INTERFACE: {
1571
Control *node = memnew(Control);
1572
// Making the root control full rect by default is more useful for resizable UIs.
1573
node->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
1574
node->set_grow_direction_preset(PRESET_FULL_RECT);
1575
new_node = node;
1576
1577
} break;
1578
}
1579
}
1580
1581
add_root_node(new_node);
1582
1583
if (GLOBAL_GET("editor/naming/node_name_casing").operator int() != NAME_CASING_PASCAL_CASE) {
1584
new_node->set_name(Node::adjust_name_casing(new_node->get_name()));
1585
}
1586
1587
EditorNode::get_singleton()->edit_node(new_node);
1588
editor_selection->clear();
1589
editor_selection->add_node(new_node);
1590
1591
scene_tree->get_scene_tree()->grab_focus(true);
1592
} break;
1593
1594
default: {
1595
if (p_tool >= EditorContextMenuPlugin::BASE_ID) {
1596
EditorContextMenuPluginManager::get_singleton()->activate_custom_option(EditorContextMenuPlugin::CONTEXT_SLOT_SCENE_TREE, p_tool, _get_selection_array());
1597
break;
1598
}
1599
1600
_filter_option_selected(p_tool);
1601
1602
if (p_tool >= EDIT_SUBRESOURCE_BASE) {
1603
int idx = p_tool - EDIT_SUBRESOURCE_BASE;
1604
1605
ERR_FAIL_INDEX(idx, subresources.size());
1606
1607
Object *obj = ObjectDB::get_instance(subresources[idx]);
1608
ERR_FAIL_NULL(obj);
1609
1610
_push_item(obj);
1611
}
1612
}
1613
}
1614
}
1615
1616
void SceneTreeDock::_property_selected(int p_idx) {
1617
ERR_FAIL_NULL(property_drop_node);
1618
_perform_property_drop(property_drop_node, menu_properties->get_item_metadata(p_idx), ResourceLoader::load(resource_drop_path));
1619
property_drop_node = nullptr;
1620
}
1621
1622
void SceneTreeDock::_perform_property_drop(Node *p_node, const String &p_property, Ref<Resource> p_res) {
1623
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
1624
undo_redo->create_action(vformat(TTR("Set %s"), p_property));
1625
undo_redo->add_do_property(p_node, p_property, p_res);
1626
undo_redo->add_undo_property(p_node, p_property, p_node->get(p_property));
1627
undo_redo->commit_action();
1628
}
1629
1630
void SceneTreeDock::add_root_node(Node *p_node) {
1631
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
1632
undo_redo->create_action_for_history(TTR("New Scene Root"), editor_data->get_current_edited_scene_history_id());
1633
undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", p_node);
1634
undo_redo->add_do_method(scene_tree, "update_tree");
1635
undo_redo->add_do_reference(p_node);
1636
undo_redo->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
1637
undo_redo->commit_action();
1638
}
1639
1640
void SceneTreeDock::_notification(int p_what) {
1641
switch (p_what) {
1642
case NOTIFICATION_READY: {
1643
if (!first_enter) {
1644
break;
1645
}
1646
first_enter = false;
1647
1648
EditorFeatureProfileManager::get_singleton()->connect("current_feature_profile_changed", callable_mp(this, &SceneTreeDock::_feature_profile_changed));
1649
1650
CanvasItemEditorPlugin *canvas_item_plugin = Object::cast_to<CanvasItemEditorPlugin>(editor_data->get_editor_by_name("2D"));
1651
if (canvas_item_plugin) {
1652
canvas_item_plugin->get_canvas_item_editor()->connect("item_lock_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree).bind(false));
1653
canvas_item_plugin->get_canvas_item_editor()->connect("item_group_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree).bind(false));
1654
scene_tree->connect("node_changed", callable_mp((CanvasItem *)canvas_item_plugin->get_canvas_item_editor()->get_viewport_control(), &CanvasItem::queue_redraw));
1655
}
1656
1657
Node3DEditorPlugin *spatial_editor_plugin = Object::cast_to<Node3DEditorPlugin>(editor_data->get_editor_by_name("3D"));
1658
spatial_editor_plugin->get_spatial_editor()->connect("item_lock_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree).bind(false));
1659
spatial_editor_plugin->get_spatial_editor()->connect("item_group_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree).bind(false));
1660
1661
filter->set_clear_button_enabled(true);
1662
1663
// create_root_dialog
1664
HBoxContainer *top_row = memnew(HBoxContainer);
1665
top_row->set_h_size_flags(SIZE_EXPAND_FILL);
1666
Label *l = memnew(Label(TTR("Create Root Node:")));
1667
l->set_theme_type_variation("HeaderSmall");
1668
top_row->add_child(l);
1669
top_row->add_spacer();
1670
1671
node_shortcuts_toggle = memnew(Button);
1672
node_shortcuts_toggle->set_flat(true);
1673
node_shortcuts_toggle->set_accessibility_name(TTRC("Favorite Nodes"));
1674
node_shortcuts_toggle->set_button_icon(get_editor_theme_icon(SNAME("Favorites")));
1675
node_shortcuts_toggle->set_toggle_mode(true);
1676
node_shortcuts_toggle->set_tooltip_text(TTR("Toggle the display of favorite nodes."));
1677
node_shortcuts_toggle->set_pressed(EDITOR_GET("_use_favorites_root_selection"));
1678
node_shortcuts_toggle->set_anchors_and_offsets_preset(Control::PRESET_CENTER_RIGHT);
1679
node_shortcuts_toggle->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_update_create_root_dialog).bind(false));
1680
top_row->add_child(node_shortcuts_toggle);
1681
1682
create_root_dialog->add_child(top_row);
1683
1684
ScrollContainer *scroll_container = memnew(ScrollContainer);
1685
create_root_dialog->add_child(scroll_container);
1686
scroll_container->set_v_size_flags(SIZE_EXPAND_FILL);
1687
scroll_container->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
1688
1689
VBoxContainer *node_shortcuts = memnew(VBoxContainer);
1690
scroll_container->add_child(node_shortcuts);
1691
node_shortcuts->set_h_size_flags(SIZE_EXPAND_FILL);
1692
1693
beginner_node_shortcuts = memnew(VBoxContainer);
1694
node_shortcuts->add_child(beginner_node_shortcuts);
1695
1696
button_2d = memnew(Button);
1697
beginner_node_shortcuts->add_child(button_2d);
1698
button_2d->set_text(TTR("2D Scene"));
1699
button_2d->set_button_icon(get_editor_theme_icon(SNAME("Node2D")));
1700
button_2d->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_CREATE_2D_SCENE, false));
1701
1702
button_3d = memnew(Button);
1703
beginner_node_shortcuts->add_child(button_3d);
1704
button_3d->set_text(TTR("3D Scene"));
1705
button_3d->set_button_icon(get_editor_theme_icon(SNAME("Node3D")));
1706
button_3d->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_CREATE_3D_SCENE, false));
1707
1708
button_ui = memnew(Button);
1709
beginner_node_shortcuts->add_child(button_ui);
1710
button_ui->set_text(TTR("User Interface"));
1711
button_ui->set_button_icon(get_editor_theme_icon(SNAME("Control")));
1712
button_ui->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_CREATE_USER_INTERFACE, false));
1713
1714
favorite_node_shortcuts = memnew(VBoxContainer);
1715
node_shortcuts->add_child(favorite_node_shortcuts);
1716
1717
button_custom = memnew(Button);
1718
node_shortcuts->add_child(button_custom);
1719
button_custom->set_text(TTR("Other Node"));
1720
button_custom->set_button_icon(get_editor_theme_icon(SNAME("Add")));
1721
button_custom->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_NEW, false));
1722
1723
button_clipboard = memnew(Button);
1724
node_shortcuts->add_child(button_clipboard);
1725
button_clipboard->set_text(TTR("Paste From Clipboard"));
1726
button_clipboard->set_button_icon(get_editor_theme_icon(SNAME("ActionPaste")));
1727
button_clipboard->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_PASTE, false));
1728
1729
_update_create_root_dialog(true);
1730
} break;
1731
1732
case NOTIFICATION_ENTER_TREE: {
1733
clear_inherit_confirm->connect(SceneStringName(confirmed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM, false));
1734
scene_tree->set_auto_expand_selected(EDITOR_GET("docks/scene_tree/auto_expand_to_selected"), false);
1735
scene_tree->set_hide_filtered_out_parents(EDITOR_GET("docks/scene_tree/hide_filtered_out_parents"), false);
1736
scene_tree->set_accessibility_warnings(EDITOR_GET("docks/scene_tree/accessibility_warnings"), false);
1737
} break;
1738
1739
case NOTIFICATION_EXIT_TREE: {
1740
clear_inherit_confirm->disconnect(SceneStringName(confirmed), callable_mp(this, &SceneTreeDock::_tool_selected));
1741
} break;
1742
1743
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
1744
if (EditorSettings::get_singleton()->check_changed_settings_in_group("docks/scene_tree")) {
1745
scene_tree->set_auto_expand_selected(EDITOR_GET("docks/scene_tree/auto_expand_to_selected"), false);
1746
scene_tree->set_hide_filtered_out_parents(EDITOR_GET("docks/scene_tree/hide_filtered_out_parents"), false);
1747
scene_tree->set_accessibility_warnings(EDITOR_GET("docks/scene_tree/accessibility_warnings"), false);
1748
}
1749
if (EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor")) {
1750
inspect_hovered_node_delay->set_wait_time(EDITOR_GET("interface/editor/dragging_hover_wait_seconds"));
1751
}
1752
} break;
1753
1754
case NOTIFICATION_THEME_CHANGED: {
1755
button_add->set_button_icon(get_editor_theme_icon(SNAME("Add")));
1756
button_instance->set_button_icon(get_editor_theme_icon(SNAME("Instance")));
1757
button_create_script->set_button_icon(get_editor_theme_icon(SNAME("ScriptCreate")));
1758
button_detach_script->set_button_icon(get_editor_theme_icon(SNAME("ScriptRemove")));
1759
button_extend_script->set_button_icon(get_editor_theme_icon(SNAME("ScriptExtend")));
1760
button_tree_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
1761
1762
filter->set_right_icon(get_editor_theme_icon(SNAME("Search")));
1763
1764
// These buttons are created on READY, because reasons...
1765
if (button_2d) {
1766
button_2d->set_button_icon(get_editor_theme_icon(SNAME("Node2D")));
1767
}
1768
if (button_3d) {
1769
button_3d->set_button_icon(get_editor_theme_icon(SNAME("Node3D")));
1770
}
1771
if (button_ui) {
1772
button_ui->set_button_icon(get_editor_theme_icon(SNAME("Control")));
1773
}
1774
if (button_custom) {
1775
button_custom->set_button_icon(get_editor_theme_icon(SNAME("Add")));
1776
}
1777
if (button_clipboard) {
1778
button_clipboard->set_button_icon(get_editor_theme_icon(SNAME("ActionPaste")));
1779
}
1780
1781
menu_subresources->add_theme_constant_override("icon_max_width", get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor)));
1782
} break;
1783
1784
case NOTIFICATION_PROCESS: {
1785
bool show_create_root = bool(EDITOR_GET("interface/editors/show_scene_tree_root_selection")) && get_tree()->get_edited_scene_root() == nullptr;
1786
1787
if (show_create_root != create_root_dialog->is_visible_in_tree() && !remote_tree->is_visible()) {
1788
if (show_create_root) {
1789
main_mc->set_theme_type_variation("");
1790
create_root_dialog->show();
1791
scene_tree->hide();
1792
} else {
1793
main_mc->set_theme_type_variation("NoBorderHorizontalBottom");
1794
create_root_dialog->hide();
1795
scene_tree->show();
1796
}
1797
}
1798
} break;
1799
1800
case NOTIFICATION_DRAG_END: {
1801
_reset_hovering_timer();
1802
if (tree_item_inspected) {
1803
_restore_treeitem_custom_color(tree_item_inspected);
1804
tree_item_inspected = nullptr;
1805
} else {
1806
return;
1807
}
1808
if (!hovered_but_reparenting) {
1809
InspectorDock *inspector_dock = InspectorDock::get_singleton();
1810
if (!inspector_dock->get_rect().has_point(inspector_dock->get_local_mouse_position())) {
1811
List<Node *> full_selection = editor_selection->get_full_selected_node_list();
1812
editor_selection->clear();
1813
for (Node *E : full_selection) {
1814
editor_selection->add_node(E);
1815
}
1816
return;
1817
}
1818
if (select_node_hovered_at_end_of_drag) {
1819
Node *node_inspected = Object::cast_to<Node>(InspectorDock::get_inspector_singleton()->get_edited_object());
1820
if (node_inspected) {
1821
editor_selection->clear();
1822
editor_selection->add_node(node_inspected);
1823
scene_tree->set_selected(node_inspected);
1824
select_node_hovered_at_end_of_drag = false;
1825
}
1826
}
1827
}
1828
hovered_but_reparenting = false;
1829
} break;
1830
}
1831
}
1832
1833
void SceneTreeDock::_node_replace_owner(Node *p_base, Node *p_node, Node *p_root, ReplaceOwnerMode p_mode) {
1834
if (p_node->get_owner() == p_base && p_node != p_root) {
1835
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
1836
switch (p_mode) {
1837
case MODE_BIDI: {
1838
bool disable_unique = p_node->is_unique_name_in_owner() && p_root->get_node_or_null(UNIQUE_NODE_PREFIX + String(p_node->get_name())) != nullptr;
1839
if (disable_unique) {
1840
// Will create a unique name conflict. Disable before setting owner.
1841
undo_redo->add_do_method(p_node, "set_unique_name_in_owner", false);
1842
}
1843
undo_redo->add_do_method(p_node, "set_owner", p_root);
1844
undo_redo->add_undo_method(p_node, "set_owner", p_base);
1845
if (disable_unique) {
1846
// Will create a unique name conflict. Enable after setting owner.
1847
undo_redo->add_undo_method(p_node, "set_unique_name_in_owner", true);
1848
}
1849
1850
} break;
1851
case MODE_DO: {
1852
undo_redo->add_do_method(p_node, "set_owner", p_root);
1853
1854
} break;
1855
case MODE_UNDO: {
1856
undo_redo->add_undo_method(p_node, "set_owner", p_root);
1857
1858
} break;
1859
}
1860
}
1861
1862
for (int i = 0; i < p_node->get_child_count(); i++) {
1863
_node_replace_owner(p_base, p_node->get_child(i), p_root, p_mode);
1864
}
1865
}
1866
1867
void SceneTreeDock::_node_strip_signal_inheritance(Node *p_node) {
1868
List<Object::Connection> conns;
1869
p_node->get_all_signal_connections(&conns);
1870
1871
for (Object::Connection conn : conns) {
1872
conn.signal.disconnect(conn.callable);
1873
conn.signal.connect(conn.callable, conn.flags & ~CONNECT_INHERITED);
1874
}
1875
for (int i = 0; i < p_node->get_child_count(); i++) {
1876
_node_strip_signal_inheritance(p_node->get_child(i));
1877
}
1878
}
1879
1880
void SceneTreeDock::_load_request(const String &p_path) {
1881
EditorNode::get_singleton()->load_scene(p_path);
1882
_local_tree_selected();
1883
}
1884
1885
void SceneTreeDock::_script_open_request(const Ref<Script> &p_script) {
1886
EditorNode::get_singleton()->push_item_no_inspector(p_script.ptr());
1887
}
1888
1889
void SceneTreeDock::_push_item(Object *p_object) {
1890
Node *node = Object::cast_to<Node>(p_object);
1891
if (node || !p_object) {
1892
// Assume that null object is a Node.
1893
EditorNode::get_singleton()->push_node_item(node);
1894
} else {
1895
EditorNode::get_singleton()->push_item(p_object);
1896
}
1897
1898
if (p_object == nullptr) {
1899
EditorNode::get_singleton()->hide_unused_editors(this);
1900
}
1901
}
1902
1903
void SceneTreeDock::_handle_select(Node *p_node) {
1904
if (tree_clicked) {
1905
pending_click_select = p_node;
1906
} else {
1907
_push_item(p_node);
1908
}
1909
}
1910
1911
void SceneTreeDock::_node_selected() {
1912
Node *node = scene_tree->get_selected();
1913
1914
if (!node) {
1915
return;
1916
}
1917
_handle_select(node);
1918
}
1919
1920
void SceneTreeDock::_node_renamed() {
1921
_node_selected();
1922
}
1923
1924
void SceneTreeDock::_set_owners(Node *p_owner, const Array &p_nodes) {
1925
for (int i = 0; i < p_nodes.size(); i++) {
1926
Node *n = Object::cast_to<Node>(p_nodes[i]);
1927
if (!n) {
1928
continue;
1929
}
1930
n->set_owner(p_owner);
1931
}
1932
}
1933
1934
void SceneTreeDock::_fill_path_renames(Vector<StringName> base_path, Vector<StringName> new_base_path, Node *p_node, HashMap<Node *, NodePath> *p_renames) {
1935
base_path.push_back(p_node->get_name());
1936
1937
NodePath new_path;
1938
if (!new_base_path.is_empty()) {
1939
new_base_path.push_back(p_node->get_name());
1940
new_path = NodePath(new_base_path, true);
1941
}
1942
1943
p_renames->insert(p_node, new_path);
1944
1945
for (int i = 0; i < p_node->get_child_count(); i++) {
1946
_fill_path_renames(base_path, new_base_path, p_node->get_child(i), p_renames);
1947
}
1948
}
1949
1950
bool SceneTreeDock::_has_tracks_to_delete(Node *p_node, List<Node *> &p_to_delete) const {
1951
// Skip if this node will be deleted.
1952
for (const Node *F : p_to_delete) {
1953
if (F == p_node || F->is_ancestor_of(p_node)) {
1954
return false;
1955
}
1956
}
1957
1958
// This is an AnimationPlayer that survives the deletion.
1959
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
1960
if (ap) {
1961
Node *root = ap->get_node(ap->get_root_node());
1962
if (root && !p_to_delete.find(root)) {
1963
List<StringName> anims;
1964
ap->get_animation_list(&anims);
1965
1966
for (const StringName &E : anims) {
1967
Ref<Animation> anim = ap->get_animation(E);
1968
if (anim.is_null()) {
1969
continue;
1970
}
1971
1972
for (int i = 0; i < anim->get_track_count(); i++) {
1973
NodePath track_np = anim->track_get_path(i);
1974
Node *n = root->get_node_or_null(track_np);
1975
if (n) {
1976
for (const Node *F : p_to_delete) {
1977
if (F == n || F->is_ancestor_of(n)) {
1978
return true;
1979
}
1980
}
1981
}
1982
}
1983
}
1984
}
1985
}
1986
1987
// Recursively check child nodes.
1988
for (int i = 0; i < p_node->get_child_count(); i++) {
1989
if (_has_tracks_to_delete(p_node->get_child(i), p_to_delete)) {
1990
return true;
1991
}
1992
}
1993
1994
return false;
1995
}
1996
1997
void SceneTreeDock::fill_path_renames(Node *p_node, Node *p_new_parent, HashMap<Node *, NodePath> *p_renames) {
1998
Vector<StringName> base_path;
1999
Node *n = p_node->get_parent();
2000
while (n) {
2001
base_path.push_back(n->get_name());
2002
n = n->get_parent();
2003
}
2004
2005
Vector<StringName> new_base_path;
2006
if (p_new_parent) {
2007
n = p_new_parent;
2008
while (n) {
2009
new_base_path.push_back(n->get_name());
2010
n = n->get_parent();
2011
}
2012
2013
// For the case Reparent to New Node, the new parent has not yet been added to the tree.
2014
if (!p_new_parent->is_inside_tree()) {
2015
new_base_path.append_array(base_path);
2016
}
2017
2018
new_base_path.reverse();
2019
}
2020
base_path.reverse();
2021
2022
_fill_path_renames(base_path, new_base_path, p_node, p_renames);
2023
}
2024
2025
bool SceneTreeDock::_update_node_path(Node *p_root_node, NodePath &r_node_path, HashMap<Node *, NodePath> *p_renames) const {
2026
Node *target_node = p_root_node->get_node_or_null(r_node_path);
2027
ERR_FAIL_NULL_V_MSG(target_node, false, "Found invalid node path '" + String(r_node_path) + "' on node '" + String(scene_root->get_path_to(p_root_node)) + "'");
2028
2029
// Try to find the target node in modified node paths.
2030
HashMap<Node *, NodePath>::Iterator found_node_path = p_renames->find(target_node);
2031
if (found_node_path) {
2032
String old_subnames;
2033
if (r_node_path.get_subname_count() > 0) {
2034
old_subnames = ":" + r_node_path.get_concatenated_subnames();
2035
}
2036
2037
HashMap<Node *, NodePath>::Iterator found_root_path = p_renames->find(p_root_node);
2038
NodePath root_path_new = found_root_path ? found_root_path->value : p_root_node->get_path();
2039
r_node_path = NodePath(String(root_path_new.rel_path_to(found_node_path->value)) + old_subnames);
2040
2041
return true;
2042
}
2043
2044
// Update the path if the base node has changed and has not been deleted.
2045
HashMap<Node *, NodePath>::Iterator found_root_path = p_renames->find(p_root_node);
2046
if (found_root_path) {
2047
NodePath root_path_new = found_root_path->value;
2048
if (!root_path_new.is_empty()) {
2049
String old_subnames;
2050
if (r_node_path.get_subname_count() > 0) {
2051
old_subnames = ":" + r_node_path.get_concatenated_subnames();
2052
}
2053
2054
NodePath old_abs_path = NodePath(String(p_root_node->get_path()).path_join(String(r_node_path)));
2055
old_abs_path.simplify();
2056
r_node_path = NodePath(String(root_path_new.rel_path_to(old_abs_path)) + old_subnames);
2057
}
2058
2059
return true;
2060
}
2061
2062
return false;
2063
}
2064
2065
_ALWAYS_INLINE_ static bool _recurse_into_property(const PropertyInfo &p_property) {
2066
// Only check these types for NodePaths.
2067
static const Variant::Type property_type_check[] = { Variant::OBJECT, Variant::NODE_PATH, Variant::ARRAY, Variant::DICTIONARY };
2068
2069
if (!(p_property.usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR))) {
2070
return false;
2071
}
2072
2073
// Avoid otherwise acceptable types if we marked them as irrelevant.
2074
if (p_property.hint == PROPERTY_HINT_NO_NODEPATH) {
2075
return false;
2076
}
2077
2078
for (Variant::Type type : property_type_check) {
2079
if (p_property.type == type) {
2080
return true;
2081
}
2082
}
2083
return false;
2084
}
2085
2086
void SceneTreeDock::_check_object_properties_recursive(Node *p_root_node, Object *p_obj, HashMap<Node *, NodePath> *p_renames, bool p_inside_resource) const {
2087
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2088
2089
List<PropertyInfo> properties;
2090
p_obj->get_property_list(&properties);
2091
2092
for (const PropertyInfo &E : properties) {
2093
if (!_recurse_into_property(E)) {
2094
continue;
2095
}
2096
2097
StringName propertyname = E.name;
2098
2099
Variant old_variant = p_obj->get(propertyname);
2100
Variant updated_variant = old_variant;
2101
if (_check_node_path_recursive(p_root_node, updated_variant, p_renames, p_inside_resource)) {
2102
undo_redo->add_do_property(p_obj, propertyname, updated_variant);
2103
undo_redo->add_undo_property(p_obj, propertyname, old_variant);
2104
}
2105
}
2106
}
2107
2108
bool SceneTreeDock::_check_node_path_recursive(Node *p_root_node, Variant &r_variant, HashMap<Node *, NodePath> *p_renames, bool p_inside_resource) const {
2109
switch (r_variant.get_type()) {
2110
case Variant::NODE_PATH: {
2111
NodePath node_path = r_variant;
2112
if (p_inside_resource && !p_root_node->has_node(node_path)) {
2113
// Resources may have NodePaths to nodes that aren't on the scene, so skip them.
2114
return false;
2115
}
2116
2117
if (!node_path.is_empty() && _update_node_path(p_root_node, node_path, p_renames)) {
2118
r_variant = node_path;
2119
return true;
2120
}
2121
} break;
2122
2123
case Variant::ARRAY: {
2124
Array a = r_variant;
2125
bool updated = false;
2126
for (int i = 0; i < a.size(); i++) {
2127
Variant value = a[i];
2128
if (_check_node_path_recursive(p_root_node, value, p_renames, p_inside_resource)) {
2129
if (!updated) {
2130
a = a.duplicate(); // Need to duplicate for undo-redo to work.
2131
updated = true;
2132
}
2133
a[i] = value;
2134
}
2135
}
2136
if (updated) {
2137
r_variant = a;
2138
return true;
2139
}
2140
} break;
2141
2142
case Variant::DICTIONARY: {
2143
Dictionary d = r_variant;
2144
bool updated = false;
2145
for (int i = 0; i < d.size(); i++) {
2146
Variant value = d.get_value_at_index(i);
2147
if (_check_node_path_recursive(p_root_node, value, p_renames, p_inside_resource)) {
2148
if (!updated) {
2149
d = d.duplicate(); // Need to duplicate for undo-redo to work.
2150
updated = true;
2151
}
2152
d[d.get_key_at_index(i)] = value;
2153
}
2154
}
2155
if (updated) {
2156
r_variant = d;
2157
return true;
2158
}
2159
} break;
2160
2161
case Variant::OBJECT: {
2162
Resource *resource = Object::cast_to<Resource>(r_variant);
2163
if (!resource) {
2164
break;
2165
}
2166
2167
if (Object::cast_to<Animation>(resource)) {
2168
// Animation resources are handled by animation editor.
2169
break;
2170
}
2171
2172
if (Object::cast_to<Material>(resource)) {
2173
// For performance reasons, assume that Materials don't have NodePaths in them.
2174
// TODO This check could be removed when String performance has improved.
2175
break;
2176
}
2177
2178
if (!resource->is_built_in()) {
2179
// For performance reasons, assume that scene paths are no concern for external resources.
2180
break;
2181
}
2182
2183
_check_object_properties_recursive(p_root_node, resource, p_renames, true);
2184
} break;
2185
2186
default: {
2187
}
2188
}
2189
2190
return false;
2191
}
2192
2193
void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath> *p_renames, HashMap<Ref<Animation>, HashSet<int>> *r_rem_anims) {
2194
HashMap<Ref<Animation>, HashSet<int>> rem_anims;
2195
if (!r_rem_anims) {
2196
r_rem_anims = &rem_anims;
2197
}
2198
2199
if (!p_base) {
2200
p_base = edited_scene;
2201
}
2202
2203
if (!p_base) {
2204
return;
2205
}
2206
2207
// No renaming if base node is deleted.
2208
HashMap<Node *, NodePath>::Iterator found_base_path = p_renames->find(p_base);
2209
if (found_base_path && found_base_path->value.is_empty()) {
2210
return;
2211
}
2212
2213
bool autorename_animation_tracks = bool(EDITOR_GET("editors/animation/autorename_animation_tracks"));
2214
2215
AnimationMixer *mixer = Object::cast_to<AnimationMixer>(p_base);
2216
if (autorename_animation_tracks && mixer) {
2217
// Don't rename if we're an AnimationTree pointing to an AnimationPlayer
2218
bool points_to_other_animation_player = false;
2219
AnimationTree *at = Object::cast_to<AnimationTree>(mixer);
2220
if (at) {
2221
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(at->get_node_or_null(at->get_animation_player()));
2222
if (ap) {
2223
points_to_other_animation_player = true;
2224
}
2225
}
2226
2227
if (!points_to_other_animation_player) {
2228
List<StringName> anims;
2229
mixer->get_animation_list(&anims);
2230
Node *root = mixer->get_node(mixer->get_root_node());
2231
2232
if (root) {
2233
HashMap<Node *, NodePath>::Iterator found_root_path = p_renames->find(root);
2234
NodePath new_root_path = found_root_path ? found_root_path->value : root->get_path();
2235
if (!new_root_path.is_empty()) { // No renaming if root node is deleted.
2236
for (const StringName &E : anims) {
2237
Ref<Animation> anim = mixer->get_animation(E);
2238
if (!r_rem_anims->has(anim)) {
2239
r_rem_anims->insert(anim, HashSet<int>());
2240
HashSet<int> &ran = r_rem_anims->find(anim)->value;
2241
for (int i = 0; i < anim->get_track_count(); i++) {
2242
ran.insert(i);
2243
}
2244
}
2245
2246
HashSet<int> &ran = r_rem_anims->find(anim)->value;
2247
2248
if (anim.is_null() || EditorNode::get_singleton()->is_resource_read_only(anim)) {
2249
continue;
2250
}
2251
2252
int tracks_removed = 0;
2253
2254
for (int i = 0; i < anim->get_track_count(); i++) {
2255
if (anim->track_is_imported(i)) {
2256
continue;
2257
}
2258
2259
NodePath track_np = anim->track_get_path(i);
2260
2261
Node *n = root->get_node_or_null(track_np);
2262
if (!n) {
2263
continue;
2264
}
2265
2266
if (!ran.has(i)) {
2267
continue; //channel was removed
2268
}
2269
2270
HashMap<Node *, NodePath>::Iterator found_path = p_renames->find(n);
2271
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2272
if (found_path) {
2273
if (found_path->value.is_empty()) {
2274
//will be erased
2275
2276
int idx = i - tracks_removed;
2277
tracks_removed++;
2278
2279
undo_redo->add_do_method(anim.ptr(), "remove_track", idx);
2280
undo_redo->add_undo_method(anim.ptr(), "add_track", anim->track_get_type(i), idx);
2281
undo_redo->add_undo_method(anim.ptr(), "track_set_path", idx, track_np);
2282
undo_redo->add_undo_method(anim.ptr(), "track_set_interpolation_type", idx, anim->track_get_interpolation_type(i));
2283
for (int j = 0; j < anim->track_get_key_count(i); j++) {
2284
undo_redo->add_undo_method(anim.ptr(), "track_insert_key", idx, anim->track_get_key_time(i, j), anim->track_get_key_value(i, j), anim->track_get_key_transition(i, j));
2285
}
2286
2287
ran.erase(i); //byebye channel
2288
2289
} else {
2290
//will be renamed
2291
NodePath rel_path = new_root_path.rel_path_to(found_path->value);
2292
2293
NodePath new_path = NodePath(rel_path.get_names(), track_np.get_subnames(), false);
2294
if (new_path == track_np) {
2295
continue; //bleh
2296
}
2297
undo_redo->add_do_method(anim.ptr(), "track_set_path", i, new_path);
2298
undo_redo->add_undo_method(anim.ptr(), "track_set_path", i, track_np);
2299
}
2300
}
2301
}
2302
}
2303
}
2304
}
2305
}
2306
}
2307
2308
// Renaming node paths used in node properties.
2309
_check_object_properties_recursive(p_base, p_base, p_renames);
2310
2311
for (int i = 0; i < p_base->get_child_count(); i++) {
2312
perform_node_renames(p_base->get_child(i), p_renames, r_rem_anims);
2313
}
2314
}
2315
2316
void SceneTreeDock::_node_prerenamed(Node *p_node, const String &p_new_name) {
2317
HashMap<Node *, NodePath> path_renames;
2318
2319
Vector<StringName> base_path;
2320
Node *n = p_node->get_parent();
2321
while (n) {
2322
base_path.push_back(n->get_name());
2323
n = n->get_parent();
2324
}
2325
base_path.reverse();
2326
2327
Vector<StringName> new_base_path = base_path;
2328
base_path.push_back(p_node->get_name());
2329
2330
new_base_path.push_back(p_new_name);
2331
2332
NodePath new_path(new_base_path, true);
2333
path_renames[p_node] = new_path;
2334
2335
for (int i = 0; i < p_node->get_child_count(); i++) {
2336
_fill_path_renames(base_path, new_base_path, p_node->get_child(i), &path_renames);
2337
}
2338
2339
perform_node_renames(nullptr, &path_renames);
2340
}
2341
2342
bool SceneTreeDock::_validate_no_foreign() {
2343
const List<Node *> selection = editor_selection->get_top_selected_node_list();
2344
2345
for (Node *E : selection) {
2346
if (E != edited_scene && E->get_owner() != edited_scene) {
2347
accept->set_text(TTR("Can't operate on nodes from a foreign scene!"));
2348
accept->popup_centered();
2349
return false;
2350
}
2351
2352
if (edited_scene->get_scene_inherited_state().is_valid()) {
2353
// When edited_scene inherits from another one the root Node will be the parent Scene,
2354
// we don't want to consider that Node a foreign one otherwise we would not be able to
2355
// delete it.
2356
if (edited_scene == E && current_option != TOOL_REPLACE) {
2357
continue;
2358
}
2359
2360
if (edited_scene == E || edited_scene->get_scene_inherited_state()->find_node_by_path(edited_scene->get_path_to(E)) >= 0) {
2361
accept->set_text(TTR("Can't operate on nodes the current scene inherits from!"));
2362
accept->popup_centered();
2363
return false;
2364
}
2365
}
2366
}
2367
2368
return true;
2369
}
2370
2371
bool SceneTreeDock::_validate_no_instance() {
2372
const List<Node *> selection = editor_selection->get_top_selected_node_list();
2373
2374
for (Node *E : selection) {
2375
if (E != edited_scene && E->is_instance()) {
2376
accept->set_text(TTR("This operation can't be done on instantiated scenes."));
2377
accept->popup_centered();
2378
return false;
2379
}
2380
}
2381
2382
return true;
2383
}
2384
2385
void SceneTreeDock::_node_reparent(NodePath p_path, bool p_keep_global_xform) {
2386
Node *new_parent = scene_root->get_node(p_path);
2387
ERR_FAIL_NULL(new_parent);
2388
2389
const List<Node *> selection = editor_selection->get_top_selected_node_list();
2390
2391
if (selection.is_empty()) {
2392
return; // Nothing to reparent.
2393
}
2394
2395
Vector<Node *> nodes;
2396
2397
for (Node *E : selection) {
2398
nodes.push_back(E);
2399
}
2400
2401
_do_reparent(new_parent, -1, nodes, p_keep_global_xform);
2402
}
2403
2404
void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, Vector<Node *> p_nodes, bool p_keep_global_xform) {
2405
ERR_FAIL_NULL(p_new_parent);
2406
2407
if (p_nodes.is_empty()) {
2408
return; // Nothing to reparent.
2409
}
2410
2411
p_nodes.sort_custom<Node::Comparator>(); //Makes result reliable.
2412
2413
const int first_idx = p_position_in_parent == -1 ? p_new_parent->get_child_count(false) : p_position_in_parent;
2414
int nodes_before = first_idx;
2415
bool no_change = true;
2416
for (int ni = 0; ni < p_nodes.size(); ni++) {
2417
if (p_nodes[ni] == p_new_parent) {
2418
return; // Attempt to reparent to itself.
2419
}
2420
// `move_child` + `get_index` doesn't really work for internal nodes.
2421
ERR_FAIL_COND_MSG(p_nodes[ni]->is_internal(), "Trying to move internal node, this is not supported.");
2422
2423
if (p_nodes[ni]->get_index(false) < first_idx) {
2424
nodes_before--;
2425
}
2426
2427
if (p_nodes[ni]->get_parent() != p_new_parent) {
2428
no_change = false;
2429
}
2430
}
2431
2432
for (int ni = 0; ni < p_nodes.size() && no_change; ni++) {
2433
if (p_nodes[ni]->get_index(false) != nodes_before + ni) {
2434
no_change = false;
2435
}
2436
}
2437
2438
if (no_change) {
2439
return; // Position and parent didn't change.
2440
}
2441
2442
// Prevent selecting the hovered node and keep the reparented node(s) selected instead.
2443
hovered_but_reparenting = true;
2444
2445
Node *validate = p_new_parent;
2446
while (validate) {
2447
ERR_FAIL_COND_MSG(p_nodes.has(validate), "Selection changed at some point. Can't reparent.");
2448
validate = validate->get_parent();
2449
}
2450
2451
// Sort by tree order, so re-adding is easy.
2452
p_nodes.sort_custom<Node::Comparator>();
2453
2454
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2455
undo_redo->create_action(TTR("Reparent Node"), UndoRedo::MERGE_DISABLE, p_nodes[0]);
2456
2457
HashMap<Node *, NodePath> path_renames;
2458
Vector<StringName> former_names;
2459
2460
int inc = 0;
2461
bool need_edit = false;
2462
2463
for (int ni = 0; ni < p_nodes.size(); ni++) {
2464
// No undo implemented for this yet.
2465
Node *node = p_nodes[ni];
2466
2467
fill_path_renames(node, p_new_parent, &path_renames);
2468
former_names.push_back(node->get_name());
2469
2470
List<Node *> owned;
2471
node->get_owned_by(node->get_owner(), &owned);
2472
Array owners;
2473
for (Node *E : owned) {
2474
owners.push_back(E);
2475
}
2476
2477
bool same_parent = p_new_parent == node->get_parent();
2478
if (same_parent && node->get_index(false) < p_position_in_parent + ni) {
2479
inc--; // If the child will generate a gap when moved, adjust.
2480
}
2481
2482
if (same_parent) {
2483
// When node is reparented to the same parent, EditorSelection does not change.
2484
// After hovering another node, the inspector has to be manually updated in this case.
2485
need_edit = select_node_hovered_at_end_of_drag;
2486
} else {
2487
undo_redo->add_do_method(node->get_parent(), "remove_child", node);
2488
undo_redo->add_do_method(p_new_parent, "add_child", node, true);
2489
}
2490
2491
int new_position_in_parent = p_position_in_parent == -1 ? -1 : p_position_in_parent + inc;
2492
if (new_position_in_parent >= 0 || same_parent) {
2493
undo_redo->add_do_method(p_new_parent, "move_child", node, new_position_in_parent);
2494
}
2495
2496
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
2497
String old_name = former_names[ni];
2498
String new_name = p_new_parent->validate_child_name(node);
2499
2500
// Name was modified, fix the path renames.
2501
if (old_name.casecmp_to(new_name) != 0) {
2502
// Fix the to name to have the new name.
2503
HashMap<Node *, NodePath>::Iterator found_path = path_renames.find(node);
2504
if (found_path) {
2505
NodePath old_new_name = found_path->value;
2506
2507
Vector<StringName> unfixed_new_names = old_new_name.get_names();
2508
Vector<StringName> fixed_new_names;
2509
2510
// Get last name and replace with fixed new name.
2511
for (int a = 0; a < (unfixed_new_names.size() - 1); a++) {
2512
fixed_new_names.push_back(unfixed_new_names[a]);
2513
}
2514
fixed_new_names.push_back(new_name);
2515
2516
NodePath fixed_node_path = NodePath(fixed_new_names, true);
2517
path_renames[node] = fixed_node_path;
2518
} else {
2519
ERR_PRINT("Internal error. Can't find renamed path for node '" + String(node->get_path()) + "'");
2520
}
2521
}
2522
2523
// FIXME: Live editing for "Reparent to New Node" option is broken.
2524
// We must get the path to `p_new_parent` *after* it was added to the scene.
2525
if (p_new_parent->is_inside_tree()) {
2526
undo_redo->add_do_method(ed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(p_new_parent), new_name, new_position_in_parent);
2527
undo_redo->add_undo_method(ed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(p_new_parent)).path_join(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index(false));
2528
}
2529
2530
if (p_keep_global_xform) {
2531
if (Object::cast_to<Node2D>(node)) {
2532
undo_redo->add_do_method(node, "set_global_transform", Object::cast_to<Node2D>(node)->get_global_transform());
2533
}
2534
if (Object::cast_to<Node3D>(node)) {
2535
undo_redo->add_do_method(node, "set_global_transform", Object::cast_to<Node3D>(node)->get_global_transform());
2536
}
2537
if (Object::cast_to<Control>(node)) {
2538
undo_redo->add_do_method(node, "set_global_position", Object::cast_to<Control>(node)->get_global_position());
2539
}
2540
}
2541
2542
undo_redo->add_do_method(this, "_set_owners", edited_scene, owners);
2543
2544
if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == node) {
2545
undo_redo->add_do_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node);
2546
}
2547
2548
undo_redo->add_undo_method(p_new_parent, "remove_child", node);
2549
undo_redo->add_undo_method(node, "set_name", former_names[ni]);
2550
2551
inc++;
2552
}
2553
2554
// Add and move in a second step (so old order is preserved).
2555
for (int ni = 0; ni < p_nodes.size(); ni++) {
2556
Node *node = p_nodes[ni];
2557
2558
List<Node *> owned;
2559
node->get_owned_by(node->get_owner(), &owned);
2560
Array owners;
2561
for (Node *E : owned) {
2562
owners.push_back(E);
2563
}
2564
2565
int child_pos = node->get_index(false);
2566
bool reparented_to_container = Object::cast_to<Container>(p_new_parent) && Object::cast_to<Control>(node);
2567
2568
undo_redo->add_undo_method(node->get_parent(), "add_child", node, true);
2569
undo_redo->add_undo_method(node->get_parent(), "move_child", node, child_pos);
2570
undo_redo->add_undo_method(this, "_set_owners", edited_scene, owners);
2571
if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == node) {
2572
undo_redo->add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node);
2573
}
2574
2575
if (p_keep_global_xform) {
2576
if (Object::cast_to<Node2D>(node)) {
2577
undo_redo->add_undo_method(node, "set_transform", Object::cast_to<Node2D>(node)->get_transform());
2578
}
2579
if (Object::cast_to<Node3D>(node)) {
2580
undo_redo->add_undo_method(node, "set_transform", Object::cast_to<Node3D>(node)->get_transform());
2581
}
2582
if (!reparented_to_container && Object::cast_to<Control>(node)) {
2583
undo_redo->add_undo_method(node, "set_position", Object::cast_to<Control>(node)->get_position());
2584
}
2585
}
2586
2587
if (reparented_to_container) {
2588
undo_redo->add_undo_method(node, "_edit_set_state", Object::cast_to<Control>(node)->_edit_get_state());
2589
}
2590
}
2591
2592
perform_node_renames(nullptr, &path_renames);
2593
2594
undo_redo->add_do_method(editor_selection, "clear");
2595
undo_redo->add_undo_method(editor_selection, "clear");
2596
List<Node *> full_selection = editor_selection->get_full_selected_node_list();
2597
for (Node *E : full_selection) {
2598
undo_redo->add_do_method(editor_selection, "add_node", E);
2599
undo_redo->add_undo_method(editor_selection, "add_node", E);
2600
}
2601
2602
if (need_edit) {
2603
EditorNode::get_singleton()->edit_current();
2604
editor_selection->clear();
2605
}
2606
2607
undo_redo->commit_action();
2608
}
2609
2610
void SceneTreeDock::_script_created(Ref<Script> p_script) {
2611
const List<Node *> &selected = editor_selection->get_top_selected_node_list();
2612
2613
if (selected.is_empty()) {
2614
return;
2615
}
2616
2617
if (p_script->is_built_in()) {
2618
p_script->set_path(edited_scene->get_scene_file_path() + "::" + p_script->generate_scene_unique_id());
2619
}
2620
2621
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2622
undo_redo->create_action(TTR("Attach Script"), UndoRedo::MERGE_DISABLE, selected.front()->get());
2623
for (Node *E : selected) {
2624
Ref<Script> existing = E->get_script();
2625
undo_redo->add_do_method(InspectorDock::get_singleton(), "store_script_properties", E);
2626
undo_redo->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", E);
2627
undo_redo->add_do_method(E, "set_script", p_script);
2628
undo_redo->add_undo_method(E, "set_script", existing);
2629
undo_redo->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", E);
2630
undo_redo->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", E);
2631
undo_redo->add_do_method(this, "_queue_update_script_button");
2632
undo_redo->add_undo_method(this, "_queue_update_script_button");
2633
}
2634
undo_redo->commit_action();
2635
2636
// Avoid changing the currently edited object.
2637
Object *edited_object = InspectorDock::get_inspector_singleton()->get_edited_object();
2638
2639
EditorNode::get_singleton()->push_item_no_inspector(p_script.ptr());
2640
_queue_update_script_button();
2641
2642
InspectorDock::get_inspector_singleton()->edit(edited_object);
2643
}
2644
2645
void SceneTreeDock::_shader_created(Ref<Shader> p_shader) {
2646
if (selected_shader_material.is_null()) {
2647
return;
2648
}
2649
2650
Ref<Shader> existing = selected_shader_material->get_shader();
2651
2652
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2653
undo_redo->create_action(TTR("Set Shader"));
2654
undo_redo->add_do_method(selected_shader_material.ptr(), "set_shader", p_shader);
2655
undo_redo->add_undo_method(selected_shader_material.ptr(), "set_shader", existing);
2656
undo_redo->commit_action();
2657
}
2658
2659
void SceneTreeDock::_script_creation_closed() {
2660
script_create_dialog->disconnect("script_created", callable_mp(this, &SceneTreeDock::_script_created));
2661
script_create_dialog->disconnect(SceneStringName(confirmed), callable_mp(this, &SceneTreeDock::_script_creation_closed));
2662
script_create_dialog->disconnect("canceled", callable_mp(this, &SceneTreeDock::_script_creation_closed));
2663
}
2664
2665
void SceneTreeDock::_shader_creation_closed() {
2666
shader_create_dialog->disconnect("shader_created", callable_mp(this, &SceneTreeDock::_shader_created));
2667
shader_create_dialog->disconnect(SceneStringName(confirmed), callable_mp(this, &SceneTreeDock::_shader_creation_closed));
2668
shader_create_dialog->disconnect("canceled", callable_mp(this, &SceneTreeDock::_shader_creation_closed));
2669
}
2670
2671
void SceneTreeDock::_toggle_editable_children_from_selection() {
2672
const List<Node *> selection = editor_selection->get_top_selected_node_list();
2673
const List<Node *>::Element *e = selection.front();
2674
2675
if (e) {
2676
_toggle_editable_children(e->get());
2677
}
2678
}
2679
2680
void SceneTreeDock::_toggle_placeholder_from_selection() {
2681
const List<Node *> selection = editor_selection->get_top_selected_node_list();
2682
const List<Node *>::Element *e = selection.front();
2683
2684
if (e) {
2685
Node *node = e->get();
2686
if (node) {
2687
_toggle_editable_children(node);
2688
2689
bool placeholder = node->get_scene_instance_load_placeholder();
2690
placeholder = !placeholder;
2691
2692
node->set_scene_instance_load_placeholder(placeholder);
2693
scene_tree->update_tree();
2694
}
2695
}
2696
}
2697
2698
void SceneTreeDock::_reparent_nodes_to_root(Node *p_root, const Array &p_nodes, Node *p_owner) {
2699
List<Node *> nodes;
2700
for (int i = 0; i < p_nodes.size(); i++) {
2701
Node *node = Object::cast_to<Node>(p_nodes[i]);
2702
ERR_FAIL_NULL(node);
2703
nodes.push_back(node);
2704
}
2705
2706
for (Node *node : nodes) {
2707
node->set_owner(p_owner);
2708
List<Node *> owned;
2709
node->get_owned_by(p_owner, &owned);
2710
String original_name = node->get_name();
2711
node->reparent(p_root);
2712
node->set_name(original_name);
2713
2714
for (Node *F : owned) {
2715
F->set_owner(p_owner);
2716
}
2717
}
2718
}
2719
2720
void SceneTreeDock::_reparent_nodes_to_paths_with_transform_and_name(Node *p_root, const Array &p_nodes, const Array &p_paths, const Array &p_transforms, const Array &p_names, Node *p_owner) {
2721
ERR_FAIL_COND(p_nodes.size() != p_paths.size());
2722
ERR_FAIL_COND(p_nodes.size() != p_transforms.size());
2723
ERR_FAIL_COND(p_nodes.size() != p_names.size());
2724
2725
for (int i = 0; i < p_nodes.size(); i++) {
2726
Node *node = Object::cast_to<Node>(p_nodes[i]);
2727
ERR_FAIL_NULL(node);
2728
const NodePath &np = p_paths[i];
2729
Node *parent_node = p_root->get_node_or_null(np);
2730
ERR_FAIL_NULL(parent_node);
2731
2732
List<Node *> owned;
2733
node->get_owned_by(p_owner, &owned);
2734
node->reparent(parent_node);
2735
node->set_name(p_names[i]);
2736
Node3D *node_3d = Object::cast_to<Node3D>(node);
2737
if (node_3d) {
2738
node_3d->set_transform(p_transforms[i]);
2739
} else {
2740
Node2D *node_2d = Object::cast_to<Node2D>(node);
2741
if (node_2d) {
2742
node_2d->set_transform(p_transforms[i]);
2743
}
2744
}
2745
2746
for (Node *F : owned) {
2747
F->set_owner(p_owner);
2748
}
2749
}
2750
}
2751
2752
void SceneTreeDock::_toggle_editable_children(Node *p_node) {
2753
if (!p_node) {
2754
return;
2755
}
2756
2757
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2758
2759
undo_redo->create_action(TTR("Toggle Editable Children"));
2760
2761
bool editable = !EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node);
2762
2763
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_editable_instance", p_node, !editable);
2764
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_editable_instance", p_node, editable);
2765
2766
if (editable) {
2767
bool original_scene_instance_load_placeholder = p_node->get_scene_instance_load_placeholder();
2768
2769
undo_redo->add_undo_method(p_node, "set_scene_instance_load_placeholder", original_scene_instance_load_placeholder);
2770
undo_redo->add_do_method(p_node, "set_scene_instance_load_placeholder", false);
2771
} else {
2772
List<Node *> owned;
2773
p_node->get_owned_by(edited_scene, &owned);
2774
2775
// Get the original paths, transforms, and names for undo.
2776
Array owned_nodes_array;
2777
Array paths_array;
2778
Array transform_array;
2779
Array name_array;
2780
2781
for (Node *owned_node : owned) {
2782
if (owned_node != p_node && owned_node != edited_scene && owned_node->get_owner() == edited_scene && owned_node->get_parent()->get_owner() != edited_scene) {
2783
owned_nodes_array.push_back(owned_node);
2784
paths_array.push_back(p_node->get_path_to(owned_node->get_parent()));
2785
name_array.push_back(owned_node->get_name());
2786
Node3D *node_3d = Object::cast_to<Node3D>(owned_node);
2787
if (node_3d) {
2788
transform_array.push_back(node_3d->get_transform());
2789
} else {
2790
Node2D *node_2d = Object::cast_to<Node2D>(owned_node);
2791
if (node_2d) {
2792
transform_array.push_back(node_2d->get_transform());
2793
} else {
2794
transform_array.push_back(Variant());
2795
}
2796
}
2797
}
2798
}
2799
2800
if (!owned_nodes_array.is_empty()) {
2801
undo_redo->add_undo_method(this, "_reparent_nodes_to_paths_with_transform_and_name", p_node, owned_nodes_array, paths_array, transform_array, name_array, edited_scene);
2802
undo_redo->add_do_method(this, "_reparent_nodes_to_root", p_node, owned_nodes_array, edited_scene);
2803
}
2804
}
2805
2806
undo_redo->add_undo_method(Node3DEditor::get_singleton(), "update_all_gizmos", p_node);
2807
undo_redo->add_do_method(Node3DEditor::get_singleton(), "update_all_gizmos", p_node);
2808
2809
undo_redo->add_undo_method(scene_tree, "update_tree");
2810
undo_redo->add_do_method(scene_tree, "update_tree");
2811
2812
undo_redo->commit_action();
2813
}
2814
2815
void SceneTreeDock::_delete_confirm(bool p_cut) {
2816
List<Node *> remove_list = editor_selection->get_top_selected_node_list();
2817
2818
if (remove_list.is_empty()) {
2819
return;
2820
}
2821
2822
bool entire_scene = false;
2823
2824
for (const Node *E : remove_list) {
2825
if (E == edited_scene) {
2826
entire_scene = true;
2827
break;
2828
}
2829
}
2830
2831
if (!entire_scene) {
2832
for (const Node *E : remove_list) {
2833
// `move_child` + `get_index` doesn't really work for internal nodes.
2834
ERR_FAIL_COND_MSG(E->is_internal(), "Trying to remove internal node, this is not supported.");
2835
}
2836
}
2837
2838
EditorNode::get_singleton()->hide_unused_editors(this);
2839
2840
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2841
undo_redo->create_action(p_cut ? TTR("Cut Node(s)") : TTR("Remove Node(s)"), UndoRedo::MERGE_DISABLE, remove_list.front()->get());
2842
2843
if (entire_scene) {
2844
undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
2845
undo_redo->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", edited_scene);
2846
undo_redo->add_undo_method(edited_scene, "set_owner", edited_scene->get_owner());
2847
undo_redo->add_undo_method(scene_tree, "update_tree");
2848
undo_redo->add_undo_reference(edited_scene);
2849
} else {
2850
if (delete_tracks_checkbox->is_pressed() || p_cut) {
2851
remove_list.sort_custom<Node::Comparator>(); // Sort nodes to keep positions.
2852
HashMap<Node *, NodePath> path_renames;
2853
2854
//delete from animation
2855
for (Node *n : remove_list) {
2856
if (!n->is_inside_tree() || !n->get_parent()) {
2857
continue;
2858
}
2859
2860
fill_path_renames(n, nullptr, &path_renames);
2861
}
2862
2863
perform_node_renames(nullptr, &path_renames);
2864
}
2865
2866
//delete for read
2867
for (Node *n : remove_list) {
2868
if (!n->is_inside_tree() || !n->get_parent()) {
2869
continue;
2870
}
2871
2872
List<Node *> owned;
2873
n->get_owned_by(n->get_owner(), &owned);
2874
Array owners;
2875
for (Node *F : owned) {
2876
owners.push_back(F);
2877
}
2878
2879
undo_redo->add_do_method(n->get_parent(), "remove_child", n);
2880
undo_redo->add_undo_method(n->get_parent(), "add_child", n, true);
2881
undo_redo->add_undo_method(n->get_parent(), "move_child", n, n->get_index(false));
2882
if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == n) {
2883
undo_redo->add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", n);
2884
}
2885
undo_redo->add_undo_method(this, "_set_owners", edited_scene, owners);
2886
undo_redo->add_undo_reference(n);
2887
2888
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
2889
undo_redo->add_do_method(ed, "live_debug_remove_and_keep_node", edited_scene->get_path_to(n), n->get_instance_id());
2890
undo_redo->add_undo_method(ed, "live_debug_restore_node", n->get_instance_id(), edited_scene->get_path_to(n->get_parent()), n->get_index(false));
2891
}
2892
}
2893
undo_redo->commit_action();
2894
2895
// hack, force 2d editor viewport to refresh after deletion
2896
if (CanvasItemEditor *editor = CanvasItemEditor::get_singleton()) {
2897
editor->get_viewport_control()->queue_redraw();
2898
}
2899
2900
_push_item(nullptr);
2901
2902
// Fixes the EditorSelectionHistory from still offering deleted notes
2903
EditorSelectionHistory *editor_history = EditorNode::get_singleton()->get_editor_selection_history();
2904
editor_history->cleanup_history();
2905
InspectorDock::get_singleton()->call("_prepare_history");
2906
InspectorDock::get_singleton()->update(nullptr);
2907
SignalsDock::get_singleton()->set_object(nullptr);
2908
GroupsDock::get_singleton()->set_selection(Vector<Node *>());
2909
}
2910
2911
void SceneTreeDock::_update_script_button() {
2912
bool can_create_script = false;
2913
bool can_detach_script = false;
2914
bool can_extend_script = false;
2915
2916
if (profile_allow_script_editing) {
2917
Array selection = editor_selection->get_selected_nodes();
2918
2919
for (int i = 0; i < selection.size(); i++) {
2920
Node *n = Object::cast_to<Node>(selection[i]);
2921
Ref<Script> s = n->get_script();
2922
Ref<Script> cts;
2923
2924
if (n->has_meta(SceneStringName(_custom_type_script))) {
2925
cts = PropertyUtils::get_custom_type_script(n);
2926
}
2927
2928
if (selection.size() == 1) {
2929
if (s.is_valid()) {
2930
if (cts.is_valid() && s == cts) {
2931
can_extend_script = true;
2932
}
2933
} else {
2934
can_create_script = true;
2935
}
2936
}
2937
2938
if (s.is_valid()) {
2939
if (cts.is_valid()) {
2940
if (s != cts) {
2941
can_detach_script = true;
2942
break;
2943
}
2944
} else {
2945
can_detach_script = true;
2946
break;
2947
}
2948
}
2949
}
2950
}
2951
2952
button_create_script->set_visible(can_create_script);
2953
button_detach_script->set_visible(can_detach_script);
2954
button_extend_script->set_visible(can_extend_script);
2955
2956
update_script_button_queued = false;
2957
}
2958
2959
void SceneTreeDock::_queue_update_script_button() {
2960
if (update_script_button_queued) {
2961
return;
2962
}
2963
update_script_button_queued = true;
2964
callable_mp(this, &SceneTreeDock::_update_script_button).call_deferred();
2965
}
2966
2967
void SceneTreeDock::_selection_changed() {
2968
int selection_size = editor_selection->get_selection().size();
2969
if (selection_size > 1) {
2970
//automatically turn on multi-edit
2971
_tool_selected(TOOL_MULTI_EDIT);
2972
} else if (selection_size == 1) {
2973
Node *node = ObjectDB::get_instance<Node>(editor_selection->get_selection().begin()->key);
2974
if (node) {
2975
_handle_select(node);
2976
}
2977
} else if (selection_size == 0) {
2978
_push_item(nullptr);
2979
}
2980
2981
// Untrack script changes in previously selected nodes.
2982
clear_previous_node_selection();
2983
2984
// Track script changes in newly selected nodes.
2985
node_previous_selection.reserve(editor_selection->get_selection().size());
2986
for (const KeyValue<ObjectID, Object *> &E : editor_selection->get_selection()) {
2987
Node *node = ObjectDB::get_instance<Node>(E.key);
2988
if (node) {
2989
node_previous_selection.push_back(E.key);
2990
node->connect(CoreStringName(script_changed), callable_mp(this, &SceneTreeDock::_queue_update_script_button));
2991
}
2992
}
2993
_queue_update_script_button();
2994
}
2995
2996
Node *SceneTreeDock::_do_create(Node *p_parent) {
2997
Variant c = create_dialog->instantiate_selected();
2998
Node *child = Object::cast_to<Node>(c);
2999
ERR_FAIL_NULL_V(child, nullptr);
3000
3001
String new_name = p_parent->validate_child_name(child);
3002
if (GLOBAL_GET("editor/naming/node_name_casing").operator int() != NAME_CASING_PASCAL_CASE) {
3003
new_name = adjust_name_casing(new_name);
3004
}
3005
child->set_name(new_name);
3006
3007
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
3008
undo_redo->create_action_for_history(TTR("Create Node"), editor_data->get_current_edited_scene_history_id());
3009
3010
if (edited_scene) {
3011
undo_redo->add_do_method(p_parent, "add_child", child, true);
3012
undo_redo->add_do_method(child, "set_owner", edited_scene);
3013
undo_redo->add_do_reference(child);
3014
undo_redo->add_undo_method(p_parent, "remove_child", child);
3015
3016
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
3017
undo_redo->add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(p_parent), child->get_class(), new_name);
3018
undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).path_join(new_name)));
3019
3020
} else {
3021
undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", child);
3022
undo_redo->add_do_method(scene_tree, "update_tree");
3023
undo_redo->add_do_reference(child);
3024
undo_redo->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
3025
}
3026
3027
undo_redo->add_do_method(this, "_post_do_create", child);
3028
undo_redo->commit_action();
3029
3030
return child;
3031
}
3032
3033
void SceneTreeDock::_post_do_create(Node *p_child) {
3034
editor_selection->clear();
3035
editor_selection->add_node(p_child);
3036
_push_item(p_child);
3037
3038
// Make editor more comfortable, so some controls don't appear super shrunk.
3039
Control *control = Object::cast_to<Control>(p_child);
3040
if (control) {
3041
Size2 ms = control->get_minimum_size();
3042
if (ms.width < 4) {
3043
ms.width = 40;
3044
}
3045
if (ms.height < 4) {
3046
ms.height = 40;
3047
}
3048
if (control->is_layout_rtl()) {
3049
control->set_position(control->get_position() - Vector2(ms.x, 0));
3050
}
3051
control->set_size(ms);
3052
}
3053
3054
emit_signal(SNAME("node_created"), p_child);
3055
}
3056
3057
void SceneTreeDock::_create() {
3058
if (current_option == TOOL_NEW) {
3059
Node *parent = nullptr;
3060
3061
if (edited_scene) {
3062
// If root exists in edited scene
3063
parent = scene_tree->get_selected();
3064
if (!parent) {
3065
parent = edited_scene;
3066
}
3067
3068
} else {
3069
// If no root exist in edited scene
3070
parent = scene_root;
3071
ERR_FAIL_NULL(parent);
3072
}
3073
3074
_do_create(parent);
3075
3076
} else if (current_option == TOOL_REPLACE) {
3077
const List<Node *> selection = editor_selection->get_top_selected_node_list();
3078
ERR_FAIL_COND(selection.is_empty());
3079
3080
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
3081
ur->create_action(TTR("Change type of node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get());
3082
3083
for (Node *n : selection) {
3084
ERR_FAIL_NULL(n);
3085
3086
Variant c = create_dialog->instantiate_selected();
3087
3088
ERR_FAIL_COND(!c);
3089
Node *new_node = Object::cast_to<Node>(c);
3090
ERR_FAIL_NULL(new_node);
3091
replace_node(n, new_node);
3092
}
3093
3094
ur->commit_action(false);
3095
} else if (current_option == TOOL_REPARENT_TO_NEW_NODE) {
3096
const List<Node *> selection = editor_selection->get_top_selected_node_list();
3097
ERR_FAIL_COND(selection.is_empty());
3098
3099
// Find top level node in selection
3100
bool only_one_top_node = true;
3101
3102
Node *first = selection.front()->get();
3103
ERR_FAIL_NULL(first);
3104
int smaller_path_to_top = first->get_path_to(scene_root).get_name_count();
3105
Node *top_node = first;
3106
3107
bool center_parent = EDITOR_GET("docks/scene_tree/center_node_on_reparent");
3108
Vector<Node *> top_level_nodes;
3109
3110
for (const List<Node *>::Element *E = selection.front()->next(); E; E = E->next()) {
3111
Node *n = E->get();
3112
ERR_FAIL_NULL(n);
3113
3114
int path_length = n->get_path_to(scene_root).get_name_count();
3115
3116
if (top_node != n) {
3117
if (smaller_path_to_top > path_length) {
3118
top_node = n;
3119
smaller_path_to_top = path_length;
3120
only_one_top_node = true;
3121
if (center_parent) {
3122
top_level_nodes.clear();
3123
top_level_nodes.append(n);
3124
}
3125
} else if (smaller_path_to_top == path_length) {
3126
if (only_one_top_node && top_node->get_parent() != n->get_parent()) {
3127
only_one_top_node = false;
3128
}
3129
if (center_parent) {
3130
top_level_nodes.append(n);
3131
}
3132
}
3133
}
3134
}
3135
3136
Node *parent = nullptr;
3137
int original_position = -1;
3138
if (only_one_top_node) {
3139
parent = top_node->get_parent();
3140
original_position = top_node->get_index(false);
3141
} else {
3142
parent = top_node->get_parent()->get_parent();
3143
}
3144
3145
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
3146
undo_redo->create_action_for_history(TTR("Reparent to New Node"), editor_data->get_current_edited_scene_history_id());
3147
3148
Node *last_created = _do_create(parent);
3149
3150
Vector<Node *> nodes;
3151
for (Node *E : selection) {
3152
nodes.push_back(E);
3153
}
3154
3155
if (center_parent) {
3156
// Find parent type and only average positions of relevant nodes.
3157
Node3D *parent_node_3d = Object::cast_to<Node3D>(last_created);
3158
if (parent_node_3d) {
3159
Vector3 position;
3160
uint32_t node_count = 0;
3161
for (const Node *node : nodes) {
3162
const Node3D *node_3d = Object::cast_to<Node3D>(node);
3163
if (node_3d) {
3164
position += node_3d->get_global_position();
3165
node_count++;
3166
}
3167
}
3168
3169
if (node_count > 0) {
3170
parent_node_3d->set_global_position(position / node_count);
3171
}
3172
}
3173
3174
Node2D *parent_node_2d = Object::cast_to<Node2D>(last_created);
3175
if (parent_node_2d) {
3176
Vector2 position;
3177
uint32_t node_count = 0;
3178
for (const Node *node : nodes) {
3179
const Node2D *node_2d = Object::cast_to<Node2D>(node);
3180
if (node_2d) {
3181
position += node_2d->get_global_position();
3182
node_count++;
3183
}
3184
}
3185
3186
if (node_count > 0) {
3187
parent_node_2d->set_global_position(position / (real_t)node_count);
3188
}
3189
}
3190
}
3191
3192
_do_reparent(last_created, -1, nodes, true);
3193
3194
if (only_one_top_node) {
3195
undo_redo->add_do_method(parent, "move_child", last_created, original_position);
3196
}
3197
undo_redo->commit_action();
3198
}
3199
3200
scene_tree->get_scene_tree()->grab_focus(true);
3201
}
3202
3203
void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node) {
3204
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
3205
ur->create_action(TTR("Change type of node(s)"), UndoRedo::MERGE_DISABLE, p_node);
3206
3207
ur->add_do_method(this, "replace_node", p_node, p_by_node, true);
3208
ur->add_do_reference(p_by_node);
3209
3210
_replace_node(p_node, p_by_node, true);
3211
3212
ur->add_undo_method(this, "replace_node", p_by_node, p_node, false);
3213
ur->add_undo_reference(p_node);
3214
3215
perform_node_replace(nullptr, p_node, p_by_node);
3216
3217
ur->commit_action(false);
3218
}
3219
3220
void SceneTreeDock::_replace_node(Node *p_node, Node *p_by_node, bool p_keep_properties) {
3221
ERR_FAIL_COND_MSG(!p_node->is_inside_tree(), "_replace_node() can't be called on a node outside of tree. You might have called it twice.");
3222
Node *oldnode = p_node;
3223
Node *newnode = p_by_node;
3224
3225
if (p_keep_properties) {
3226
Node *default_oldnode = nullptr;
3227
3228
// If we're dealing with a custom node type, we need to create a default instance of the custom type instead of the native type for property comparison.
3229
if (oldnode->has_meta(SceneStringName(_custom_type_script))) {
3230
Ref<Script> cts = PropertyUtils::get_custom_type_script(oldnode);
3231
ERR_FAIL_COND_MSG(cts.is_null(), "Invalid custom type script.");
3232
default_oldnode = Object::cast_to<Node>(get_editor_data()->script_class_instance(cts->get_global_name()));
3233
if (default_oldnode) {
3234
default_oldnode->set_name(cts->get_global_name());
3235
get_editor_data()->instantiate_object_properties(default_oldnode);
3236
} else {
3237
// Legacy custom type, registered with "add_custom_type()".
3238
// TODO: Should probably be deprecated in 4.x.
3239
const EditorData::CustomType *custom_type = get_editor_data()->get_custom_type_by_path(cts->get_path());
3240
if (custom_type) {
3241
default_oldnode = Object::cast_to<Node>(get_editor_data()->instantiate_custom_type(custom_type->name, cts->get_instance_base_type()));
3242
}
3243
}
3244
}
3245
3246
if (!default_oldnode) {
3247
default_oldnode = Object::cast_to<Node>(ClassDB::instantiate(oldnode->get_class()));
3248
}
3249
3250
List<PropertyInfo> pinfo;
3251
oldnode->get_property_list(&pinfo);
3252
3253
for (const PropertyInfo &E : pinfo) {
3254
if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
3255
continue;
3256
}
3257
3258
bool valid;
3259
const Variant &default_val = default_oldnode->get(E.name, &valid);
3260
if (!valid || default_val != oldnode->get(E.name)) {
3261
newnode->set(E.name, oldnode->get(E.name));
3262
}
3263
}
3264
3265
memdelete(default_oldnode);
3266
}
3267
3268
_push_item(nullptr);
3269
3270
//reconnect signals
3271
List<MethodInfo> sl;
3272
3273
oldnode->get_signal_list(&sl);
3274
for (const MethodInfo &E : sl) {
3275
List<Object::Connection> cl;
3276
oldnode->get_signal_connection_list(E.name, &cl);
3277
3278
for (const Object::Connection &c : cl) {
3279
if (!(c.flags & Object::CONNECT_PERSIST)) {
3280
continue;
3281
}
3282
newnode->connect(c.signal.get_name(), c.callable, c.flags);
3283
}
3284
}
3285
3286
// HACK: Remember size of anchored control.
3287
Control *old_control = Object::cast_to<Control>(oldnode);
3288
Size2 size;
3289
if (old_control) {
3290
size = old_control->get_size();
3291
}
3292
3293
String newname = oldnode->get_name();
3294
if (oldnode == edited_scene) {
3295
EditorNode::get_singleton()->set_edited_scene_root(newnode, false);
3296
}
3297
oldnode->replace_by(newnode, true);
3298
3299
// Re-apply size of anchored control.
3300
Control *new_control = Object::cast_to<Control>(newnode);
3301
if (old_control && new_control) {
3302
new_control->set_size(size);
3303
}
3304
3305
//small hack to make collisionshapes and other kind of nodes to work
3306
for (int i = 0; i < newnode->get_child_count(); i++) {
3307
Node *c = newnode->get_child(i);
3308
c->call("set_transform", c->call("get_transform"));
3309
}
3310
newnode->set_name(newname);
3311
3312
_push_item(newnode);
3313
}
3314
3315
void SceneTreeDock::perform_node_replace(Node *p_base, Node *p_node, Node *p_by_node) {
3316
if (!p_base) {
3317
p_base = edited_scene;
3318
}
3319
3320
if (!p_base) {
3321
return;
3322
}
3323
3324
// Renaming node used in node properties.
3325
List<PropertyInfo> properties;
3326
p_base->get_property_list(&properties);
3327
3328
for (const PropertyInfo &E : properties) {
3329
if (!(E.usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR))) {
3330
continue;
3331
}
3332
String propertyname = E.name;
3333
Variant old_variant = p_base->get(propertyname);
3334
Variant updated_variant = old_variant;
3335
String warn_message;
3336
3337
if (_check_node_recursive(updated_variant, p_node, p_by_node, E.hint_string, warn_message)) {
3338
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
3339
undo_redo->add_do_property(p_base, propertyname, updated_variant);
3340
undo_redo->add_undo_property(p_base, propertyname, old_variant);
3341
if (!warn_message.is_empty()) {
3342
String node_path = (String(edited_scene->get_name()) + "/" + String(edited_scene->get_path_to(p_base))).trim_suffix("/.");
3343
WARN_PRINT(warn_message + vformat("Removing the node from variable \"%s\" on node \"%s\".", propertyname, node_path));
3344
}
3345
}
3346
}
3347
3348
for (int i = 0; i < p_base->get_child_count(); i++) {
3349
perform_node_replace(p_base->get_child(i), p_node, p_by_node);
3350
}
3351
}
3352
3353
bool SceneTreeDock::_check_node_recursive(Variant &r_variant, Node *p_node, Node *p_by_node, const String type_hint, String &r_warn_message) {
3354
switch (r_variant.get_type()) {
3355
case Variant::OBJECT: {
3356
if (p_node == r_variant) {
3357
if (p_by_node->is_class(type_hint) || EditorNode::get_singleton()->is_object_of_custom_type(p_by_node, type_hint)) {
3358
r_variant = p_by_node;
3359
} else {
3360
r_variant = memnew(Object);
3361
r_warn_message = vformat("The node's new type is incompatible with an exported variable (expected %s, but type is %s).", type_hint, p_by_node->get_class());
3362
}
3363
return true;
3364
}
3365
} break;
3366
3367
case Variant::ARRAY: {
3368
Array a = r_variant;
3369
bool updated = false;
3370
for (int i = 0; i < a.size(); i++) {
3371
Variant value = a[i];
3372
if (_check_node_recursive(value, p_node, p_by_node, type_hint.get_slicec(':', 1), r_warn_message)) {
3373
if (!updated) {
3374
a = a.duplicate(); // Need to duplicate for undo-redo to work.
3375
updated = true;
3376
}
3377
a[i] = value;
3378
}
3379
}
3380
if (updated) {
3381
r_variant = a;
3382
return true;
3383
}
3384
} break;
3385
default: {
3386
}
3387
}
3388
3389
return false;
3390
}
3391
3392
void SceneTreeDock::set_edited_scene(Node *p_scene) {
3393
edited_scene = p_scene;
3394
}
3395
3396
static bool _is_same_selection(const Vector<Node *> &p_first, const HashMap<ObjectID, Object *> &p_second) {
3397
if (p_first.size() != p_second.size()) {
3398
return false;
3399
}
3400
for (Node *node : p_first) {
3401
if (!p_second.has(node->get_instance_id())) {
3402
return false;
3403
}
3404
}
3405
return true;
3406
}
3407
3408
void SceneTreeDock::clear_previous_node_selection() {
3409
for (const ObjectID &id : node_previous_selection) {
3410
Node *node = ObjectDB::get_instance<Node>(id);
3411
if (node) {
3412
node->disconnect(CoreStringName(script_changed), callable_mp(this, &SceneTreeDock::_queue_update_script_button));
3413
}
3414
}
3415
node_previous_selection.clear();
3416
}
3417
3418
void SceneTreeDock::set_selection(const Vector<Node *> &p_nodes) {
3419
// If the nodes selected are the same independently of order then return early.
3420
if (_is_same_selection(p_nodes, editor_selection->get_selection())) {
3421
return;
3422
}
3423
editor_selection->clear();
3424
for (Node *node : p_nodes) {
3425
editor_selection->add_node(node);
3426
}
3427
}
3428
3429
void SceneTreeDock::set_selected(Node *p_node, bool p_emit_selected) {
3430
scene_tree->set_selected(p_node, p_emit_selected);
3431
}
3432
3433
void SceneTreeDock::_new_scene_from(const String &p_file) {
3434
const List<Node *> selection = editor_selection->get_top_selected_node_list();
3435
3436
if (selection.size() != 1) {
3437
accept->set_text(TTR("This operation requires a single selected node."));
3438
accept->popup_centered();
3439
return;
3440
}
3441
3442
if (EditorNode::get_singleton()->is_scene_open(p_file)) {
3443
accept->set_text(TTR("Can't overwrite scene that is still open!"));
3444
accept->popup_centered();
3445
return;
3446
}
3447
3448
Node *base = selection.front()->get();
3449
3450
HashMap<const Node *, Node *> duplimap;
3451
HashMap<const Node *, Node *> inverse_duplimap;
3452
Node *copy = base->duplicate_from_editor(duplimap);
3453
3454
for (const KeyValue<const Node *, Node *> &item : duplimap) {
3455
inverse_duplimap[item.value] = const_cast<Node *>(item.key);
3456
}
3457
3458
if (copy) {
3459
// Handle Unique Nodes.
3460
for (int i = 0; i < copy->get_child_count(false); i++) {
3461
_set_node_owner_recursive(copy->get_child(i, false), copy, inverse_duplimap);
3462
}
3463
// Root node cannot ever be unique name in its own Scene!
3464
copy->set_unique_name_in_owner(false);
3465
3466
const Dictionary dict = new_scene_from_dialog->get_selected_options();
3467
bool reset_position = dict.get(TTR("Reset Position"), true);
3468
bool reset_scale = dict.get(TTR("Reset Scale"), false);
3469
bool reset_rotation = dict.get(TTR("Reset Rotation"), false);
3470
3471
Node2D *copy_2d = Object::cast_to<Node2D>(copy);
3472
if (copy_2d != nullptr) {
3473
if (reset_position) {
3474
copy_2d->set_position(Vector2(0, 0));
3475
}
3476
if (reset_rotation) {
3477
copy_2d->set_rotation(0);
3478
}
3479
if (reset_scale) {
3480
copy_2d->set_scale(Size2(1, 1));
3481
}
3482
}
3483
Node3D *copy_3d = Object::cast_to<Node3D>(copy);
3484
if (copy_3d != nullptr) {
3485
if (reset_position) {
3486
copy_3d->set_position(Vector3(0, 0, 0));
3487
}
3488
if (reset_rotation) {
3489
copy_3d->set_rotation(Vector3(0, 0, 0));
3490
}
3491
if (reset_scale) {
3492
copy_3d->set_scale(Vector3(1, 1, 1));
3493
}
3494
}
3495
3496
Ref<PackedScene> sdata = memnew(PackedScene);
3497
Error err = sdata->pack(copy);
3498
memdelete(copy);
3499
3500
if (err != OK) {
3501
accept->set_text(TTR("Couldn't save new scene. Likely dependencies (instances) couldn't be satisfied."));
3502
accept->popup_centered();
3503
return;
3504
}
3505
3506
int flg = 0;
3507
if (EDITOR_GET("filesystem/on_save/compress_binary_resources")) {
3508
flg |= ResourceSaver::FLAG_COMPRESS;
3509
}
3510
3511
err = ResourceSaver::save(sdata, p_file, flg);
3512
if (err != OK) {
3513
accept->set_text(TTR("Error saving scene."));
3514
accept->popup_centered();
3515
return;
3516
}
3517
_replace_with_branch_scene(p_file, base);
3518
} else {
3519
accept->set_text(TTR("Error duplicating scene to save it."));
3520
accept->popup_centered();
3521
return;
3522
}
3523
}
3524
3525
void SceneTreeDock::_set_node_owner_recursive(Node *p_node, Node *p_owner, const HashMap<const Node *, Node *> &p_inverse_duplimap) {
3526
HashMap<const Node *, Node *>::ConstIterator E = p_inverse_duplimap.find(p_node);
3527
3528
if (E) {
3529
const Node *original = E->value;
3530
if (original->get_owner()) {
3531
p_node->set_owner(p_owner);
3532
}
3533
}
3534
3535
for (int i = 0; i < p_node->get_child_count(false); i++) {
3536
_set_node_owner_recursive(p_node->get_child(i, false), p_owner, p_inverse_duplimap);
3537
}
3538
}
3539
3540
static bool _is_node_visible(Node *p_node) {
3541
if (!p_node->get_owner()) {
3542
return false;
3543
}
3544
if (p_node->get_owner() != EditorNode::get_singleton()->get_edited_scene() && !EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node->get_owner())) {
3545
return false;
3546
}
3547
3548
return true;
3549
}
3550
3551
static bool _has_visible_children(Node *p_node) {
3552
bool collapsed = p_node->is_displayed_folded();
3553
if (collapsed) {
3554
return false;
3555
}
3556
3557
for (int i = 0; i < p_node->get_child_count(); i++) {
3558
Node *child = p_node->get_child(i);
3559
if (!_is_node_visible(child)) {
3560
continue;
3561
}
3562
3563
return true;
3564
}
3565
3566
return false;
3567
}
3568
3569
void SceneTreeDock::_normalize_drop(Node *&to_node, int &to_pos, int p_type) {
3570
to_pos = -1;
3571
3572
if (p_type == -1) {
3573
//drop at above selected node
3574
if (to_node == EditorNode::get_singleton()->get_edited_scene()) {
3575
to_node = nullptr;
3576
ERR_FAIL_MSG("Cannot perform drop above the root node!");
3577
}
3578
3579
to_pos = to_node->get_index(false);
3580
to_node = to_node->get_parent();
3581
3582
} else if (p_type == 1) {
3583
//drop at below selected node
3584
if (to_node == EditorNode::get_singleton()->get_edited_scene()) {
3585
//if at lower sibling of root node
3586
to_pos = 0; //just insert at beginning of root node
3587
return;
3588
}
3589
3590
Node *lower_sibling = nullptr;
3591
3592
if (_has_visible_children(to_node)) {
3593
to_pos = 0;
3594
} else {
3595
for (int i = to_node->get_index(false) + 1; i < to_node->get_parent()->get_child_count(false); i++) {
3596
Node *c = to_node->get_parent()->get_child(i, false);
3597
if (_is_node_visible(c)) {
3598
lower_sibling = c;
3599
break;
3600
}
3601
}
3602
if (lower_sibling) {
3603
to_pos = lower_sibling->get_index(false);
3604
}
3605
3606
to_node = to_node->get_parent();
3607
}
3608
}
3609
}
3610
3611
Array SceneTreeDock::_get_selection_array() {
3612
const List<Node *> selection = editor_selection->get_top_selected_node_list();
3613
TypedArray<Node> array;
3614
array.resize(selection.size());
3615
3616
int i = 0;
3617
for (const Node *E : selection) {
3618
array[i++] = E;
3619
}
3620
return array;
3621
}
3622
3623
void SceneTreeDock::_files_dropped(const Vector<String> &p_files, NodePath p_to, int p_type) {
3624
Node *node = get_node(p_to);
3625
ERR_FAIL_NULL(node);
3626
ERR_FAIL_COND(p_files.is_empty());
3627
3628
const String &res_path = p_files[0];
3629
const StringName res_type = EditorFileSystem::get_singleton()->get_file_type(res_path);
3630
const bool is_dropping_scene = ClassDB::is_parent_class(res_type, "PackedScene");
3631
3632
// Dropping as property.
3633
if (p_type == 0 && p_files.size() == 1 && !is_dropping_scene) {
3634
List<String> valid_properties;
3635
3636
List<PropertyInfo> pinfo;
3637
node->get_property_list(&pinfo);
3638
3639
for (const PropertyInfo &p : pinfo) {
3640
if (!(p.usage & PROPERTY_USAGE_EDITOR) || !(p.usage & PROPERTY_USAGE_STORAGE) || p.hint != PROPERTY_HINT_RESOURCE_TYPE) {
3641
continue;
3642
}
3643
Vector<String> valid_types = p.hint_string.split(",");
3644
3645
for (const String &prop_type : valid_types) {
3646
if (res_type == prop_type || ClassDB::is_parent_class(res_type, prop_type) || EditorNode::get_editor_data().script_class_is_parent(res_type, prop_type)) {
3647
valid_properties.push_back(p.name);
3648
break;
3649
}
3650
}
3651
}
3652
3653
if (valid_properties.size() > 1) {
3654
property_drop_node = node;
3655
resource_drop_path = res_path;
3656
3657
const EditorPropertyNameProcessor::Style style = InspectorDock::get_singleton()->get_property_name_style();
3658
menu_properties->clear();
3659
for (const String &p : valid_properties) {
3660
menu_properties->add_item(EditorPropertyNameProcessor::get_singleton()->process_name(p, style, p, node->get_class_name()));
3661
menu_properties->set_item_metadata(-1, p);
3662
}
3663
3664
menu_properties->reset_size();
3665
menu_properties->set_position(get_screen_position() + get_local_mouse_position());
3666
menu_properties->popup();
3667
return;
3668
}
3669
if (!valid_properties.is_empty()) {
3670
_perform_property_drop(node, valid_properties.front()->get(), ResourceLoader::load(res_path));
3671
return;
3672
}
3673
}
3674
3675
// Either instantiate scenes or create AudioStreamPlayers.
3676
int to_pos = -1;
3677
_normalize_drop(node, to_pos, p_type);
3678
if (is_dropping_scene) {
3679
_perform_instantiate_scenes(p_files, node, to_pos);
3680
} else if (ClassDB::is_parent_class(res_type, "AudioStream")) {
3681
_perform_create_audio_stream_players(p_files, node, to_pos);
3682
}
3683
}
3684
3685
void SceneTreeDock::_script_dropped(const String &p_file, NodePath p_to) {
3686
Ref<Script> scr = ResourceLoader::load(p_file);
3687
ERR_FAIL_COND(scr.is_null());
3688
Node *n = get_node(p_to);
3689
3690
if (!n) {
3691
return;
3692
}
3693
3694
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
3695
if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
3696
Object *obj = ClassDB::instantiate(scr->get_instance_base_type());
3697
ERR_FAIL_NULL(obj);
3698
3699
Node *new_node = Object::cast_to<Node>(obj);
3700
if (!new_node) {
3701
if (!obj->is_ref_counted()) {
3702
memdelete(obj);
3703
}
3704
ERR_FAIL_MSG("Script does not extend Node-derived type.");
3705
}
3706
new_node->set_name(Node::adjust_name_casing(p_file.get_file().get_basename()));
3707
new_node->set_script(scr);
3708
3709
undo_redo->create_action(TTR("Instantiate Script"));
3710
undo_redo->add_do_method(n, "add_child", new_node, true);
3711
undo_redo->add_do_method(new_node, "set_owner", edited_scene);
3712
undo_redo->add_do_method(editor_selection, "clear");
3713
undo_redo->add_do_method(editor_selection, "add_node", new_node);
3714
undo_redo->add_do_reference(new_node);
3715
undo_redo->add_undo_method(n, "remove_child", new_node);
3716
3717
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
3718
undo_redo->add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(n), new_node->get_class(), new_node->get_name());
3719
undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(n)).path_join(new_node->get_name())));
3720
undo_redo->commit_action();
3721
} else {
3722
// Check if dropped script is compatible.
3723
if (n->has_meta(SceneStringName(_custom_type_script))) {
3724
Ref<Script> ct_scr = PropertyUtils::get_custom_type_script(n);
3725
if (!scr->inherits_script(ct_scr)) {
3726
String custom_type_name = ct_scr->get_global_name();
3727
3728
// Legacy custom type, registered with "add_custom_type()".
3729
if (custom_type_name.is_empty()) {
3730
const EditorData::CustomType *custom_type = get_editor_data()->get_custom_type_by_path(ct_scr->get_path());
3731
if (custom_type) {
3732
custom_type_name = custom_type->name;
3733
} else {
3734
custom_type_name = TTR("<unknown>");
3735
}
3736
}
3737
3738
WARN_PRINT_ED(vformat("Script does not extend type: '%s'.", custom_type_name));
3739
return;
3740
}
3741
}
3742
3743
undo_redo->create_action(TTR("Attach Script"), UndoRedo::MERGE_DISABLE, n);
3744
undo_redo->add_do_method(InspectorDock::get_singleton(), "store_script_properties", n);
3745
undo_redo->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", n);
3746
undo_redo->add_do_method(n, "set_script", scr);
3747
undo_redo->add_undo_method(n, "set_script", n->get_script());
3748
undo_redo->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", n);
3749
undo_redo->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", n);
3750
undo_redo->add_do_method(this, "_queue_update_script_button");
3751
undo_redo->add_undo_method(this, "_queue_update_script_button");
3752
undo_redo->commit_action();
3753
}
3754
}
3755
3756
void SceneTreeDock::_nodes_dragged(const Array &p_nodes, NodePath p_to, int p_type) {
3757
if (!_validate_no_foreign()) {
3758
return;
3759
}
3760
3761
const List<Node *> selection = editor_selection->get_top_selected_node_list();
3762
3763
if (selection.is_empty()) {
3764
return; //nothing to reparent
3765
}
3766
3767
Node *to_node = get_node(p_to);
3768
if (!to_node) {
3769
return;
3770
}
3771
3772
Vector<Node *> nodes;
3773
for (Node *E : selection) {
3774
nodes.push_back(E);
3775
}
3776
3777
int to_pos = -1;
3778
3779
_normalize_drop(to_node, to_pos, p_type);
3780
_do_reparent(to_node, to_pos, nodes, !Input::get_singleton()->is_key_pressed(Key::SHIFT));
3781
}
3782
3783
void SceneTreeDock::_add_children_to_popup(Object *p_obj, int p_depth) {
3784
if (p_depth > 8) {
3785
return;
3786
}
3787
3788
List<PropertyInfo> pinfo;
3789
p_obj->get_property_list(&pinfo);
3790
for (const PropertyInfo &E : pinfo) {
3791
if (!(E.usage & PROPERTY_USAGE_EDITOR)) {
3792
continue;
3793
}
3794
if (E.hint != PROPERTY_HINT_RESOURCE_TYPE) {
3795
continue;
3796
}
3797
3798
Variant value = p_obj->get(E.name);
3799
if (value.get_type() != Variant::OBJECT) {
3800
continue;
3801
}
3802
Object *obj = value;
3803
if (!obj) {
3804
continue;
3805
}
3806
3807
Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj);
3808
3809
if (menu->get_item_count() == 0) {
3810
menu->add_submenu_node_item(TTR("Sub-Resources"), menu_subresources);
3811
}
3812
menu_subresources->add_icon_item(icon, E.name.capitalize(), EDIT_SUBRESOURCE_BASE + subresources.size());
3813
menu_subresources->set_item_indent(-1, p_depth);
3814
subresources.push_back(obj->get_instance_id());
3815
3816
_add_children_to_popup(obj, p_depth + 1);
3817
}
3818
}
3819
3820
void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
3821
ERR_FAIL_COND(!EditorNode::get_singleton()->get_edited_scene());
3822
menu->clear(false);
3823
3824
const List<Node *> selection = editor_selection->get_top_selected_node_list();
3825
List<Node *> full_selection = editor_selection->get_full_selected_node_list(); // Above method only returns nodes with common parent.
3826
3827
scene_tree->get_scene_tree()->grab_focus(true);
3828
3829
if (selection.is_empty()) {
3830
if (!profile_allow_editing) {
3831
return;
3832
}
3833
3834
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Add")), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW);
3835
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Instance")), ED_GET_SHORTCUT("scene_tree/instantiate_scene"), TOOL_INSTANTIATE);
3836
EditorContextMenuPluginManager::get_singleton()->add_options_from_plugins(menu, EditorContextMenuPlugin::CONTEXT_SLOT_SCENE_TREE, PackedStringArray());
3837
3838
menu->reset_size();
3839
menu->set_position(p_menu_pos);
3840
menu->popup();
3841
return;
3842
}
3843
3844
bool section_started = false;
3845
bool section_ended = false;
3846
3847
// Marks beginning of a new separated section. When used multiple times in a row, only first use has effect.
3848
#define BEGIN_SECTION() \
3849
{ \
3850
if (section_ended) { \
3851
section_ended = false; \
3852
menu->add_separator(); \
3853
} \
3854
section_started = true; \
3855
}
3856
// Marks end of a section.
3857
#define END_SECTION() \
3858
{ \
3859
if (section_started) { \
3860
section_ended = true; \
3861
section_started = false; \
3862
} \
3863
}
3864
3865
Ref<Script> existing_script;
3866
bool existing_script_removable = true;
3867
bool allow_attach_new_script = true;
3868
if (selection.size() == 1) {
3869
BEGIN_SECTION()
3870
Node *selected = selection.front()->get();
3871
3872
if (profile_allow_editing) {
3873
subresources.clear();
3874
menu_subresources->clear();
3875
menu_subresources->reset_size();
3876
_add_children_to_popup(selected, 0);
3877
if (menu->get_item_count() > 0) {
3878
menu->add_separator();
3879
}
3880
3881
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Add")), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW);
3882
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Instance")), ED_GET_SHORTCUT("scene_tree/instantiate_scene"), TOOL_INSTANTIATE);
3883
}
3884
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Collapse")), ED_GET_SHORTCUT("scene_tree/expand_collapse_all"), TOOL_EXPAND_COLLAPSE);
3885
3886
existing_script = selected->get_script();
3887
3888
if (EditorNode::get_singleton()->get_object_custom_type_base(selected) == existing_script) {
3889
existing_script_removable = false;
3890
}
3891
3892
if (selected->has_meta(SceneStringName(_custom_type_script))) {
3893
allow_attach_new_script = false;
3894
}
3895
END_SECTION()
3896
}
3897
3898
if (profile_allow_editing) {
3899
BEGIN_SECTION()
3900
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ActionCut")), ED_GET_SHORTCUT("scene_tree/cut_node"), TOOL_CUT);
3901
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ActionCopy")), ED_GET_SHORTCUT("scene_tree/copy_node"), TOOL_COPY);
3902
if (selection.size() == 1 && !node_clipboard.is_empty()) {
3903
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ActionPaste")), ED_GET_SHORTCUT("scene_tree/paste_node"), TOOL_PASTE);
3904
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ActionPaste")), ED_GET_SHORTCUT("scene_tree/paste_node_as_sibling"), TOOL_PASTE_AS_SIBLING);
3905
if (selection.front()->get() == edited_scene) {
3906
menu->set_item_disabled(-1, true);
3907
}
3908
}
3909
END_SECTION()
3910
}
3911
3912
if (profile_allow_script_editing) {
3913
if (full_selection.size() == 1) {
3914
BEGIN_SECTION()
3915
if (allow_attach_new_script) {
3916
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ScriptCreate")), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT);
3917
}
3918
3919
if (existing_script.is_valid() && !existing_script->is_built_in()) {
3920
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ScriptExtend")), ED_GET_SHORTCUT("scene_tree/extend_script"), TOOL_EXTEND_SCRIPT);
3921
}
3922
}
3923
if (existing_script.is_valid() && existing_script_removable) {
3924
BEGIN_SECTION()
3925
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ScriptRemove")), ED_GET_SHORTCUT("scene_tree/detach_script"), TOOL_DETACH_SCRIPT);
3926
} else if (full_selection.size() > 1) {
3927
bool script_exists = false;
3928
for (Node *E : full_selection) {
3929
if (!E->get_script().is_null()) {
3930
script_exists = true;
3931
break;
3932
}
3933
}
3934
3935
if (script_exists) {
3936
BEGIN_SECTION()
3937
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ScriptRemove")), ED_GET_SHORTCUT("scene_tree/detach_script"), TOOL_DETACH_SCRIPT);
3938
}
3939
}
3940
END_SECTION()
3941
}
3942
3943
if (profile_allow_editing) {
3944
bool can_rename = true;
3945
bool can_replace = true;
3946
3947
for (Node *E : selection) {
3948
if (E != edited_scene && (E->get_owner() != edited_scene || E->is_instance())) {
3949
can_replace = false;
3950
if (!E->is_instance()) {
3951
can_rename = false;
3952
}
3953
}
3954
3955
if (edited_scene->get_scene_inherited_state().is_valid()) {
3956
if (E == edited_scene || edited_scene->get_scene_inherited_state()->find_node_by_path(edited_scene->get_path_to(E)) >= 0) {
3957
can_replace = false;
3958
can_rename = false;
3959
}
3960
}
3961
3962
if (!can_rename && !can_replace) {
3963
break;
3964
}
3965
}
3966
3967
if (can_rename || can_replace) {
3968
BEGIN_SECTION()
3969
if (can_rename) {
3970
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Rename")), ED_GET_SHORTCUT("scene_tree/rename"), TOOL_RENAME);
3971
}
3972
if (can_replace) {
3973
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Reload")), ED_GET_SHORTCUT("scene_tree/change_node_type"), TOOL_REPLACE);
3974
}
3975
END_SECTION()
3976
}
3977
3978
if (scene_tree->get_selected() != edited_scene) {
3979
BEGIN_SECTION()
3980
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("MoveUp")), ED_GET_SHORTCUT("scene_tree/move_up"), TOOL_MOVE_UP);
3981
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("MoveDown")), ED_GET_SHORTCUT("scene_tree/move_down"), TOOL_MOVE_DOWN);
3982
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Duplicate")), ED_GET_SHORTCUT("scene_tree/duplicate"), TOOL_DUPLICATE);
3983
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Reparent")), ED_GET_SHORTCUT("scene_tree/reparent"), TOOL_REPARENT);
3984
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ReparentToNewNode")), ED_GET_SHORTCUT("scene_tree/reparent_to_new_node"), TOOL_REPARENT_TO_NEW_NODE);
3985
if (selection.size() == 1) {
3986
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("NewRoot")), ED_GET_SHORTCUT("scene_tree/make_root"), TOOL_MAKE_ROOT);
3987
}
3988
END_SECTION()
3989
}
3990
}
3991
if (selection.size() == 1) {
3992
if (profile_allow_editing) {
3993
BEGIN_SECTION()
3994
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("CreateNewSceneFrom")), ED_GET_SHORTCUT("scene_tree/save_branch_as_scene"), TOOL_NEW_SCENE_FROM);
3995
END_SECTION()
3996
}
3997
3998
if (full_selection.size() == 1) {
3999
BEGIN_SECTION()
4000
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("CopyNodePath")), ED_GET_SHORTCUT("scene_tree/copy_node_path"), TOOL_COPY_NODE_PATH);
4001
END_SECTION()
4002
}
4003
}
4004
4005
if (profile_allow_editing) {
4006
// Allow multi-toggling scene unique names but only if all selected nodes are owned by the edited scene root.
4007
bool all_owned = true;
4008
for (Node *node : full_selection) {
4009
if (node->get_owner() != EditorNode::get_singleton()->get_edited_scene()) {
4010
all_owned = false;
4011
break;
4012
}
4013
}
4014
if (all_owned) {
4015
// Group "toggle_unique_name" with "copy_node_path", if it is available.
4016
if (menu->get_item_index(TOOL_COPY_NODE_PATH) == -1) {
4017
BEGIN_SECTION()
4018
}
4019
Node *node = full_selection.front()->get();
4020
menu->add_icon_check_item(get_editor_theme_icon(SNAME("SceneUniqueName")), TTRC("Access as Unique Name"), TOOL_TOGGLE_SCENE_UNIQUE_NAME);
4021
menu->set_item_shortcut(menu->get_item_index(TOOL_TOGGLE_SCENE_UNIQUE_NAME), ED_GET_SHORTCUT("scene_tree/toggle_unique_name"));
4022
menu->set_item_checked(menu->get_item_index(TOOL_TOGGLE_SCENE_UNIQUE_NAME), node->is_unique_name_in_owner());
4023
}
4024
END_SECTION()
4025
}
4026
4027
if (selection.size() == 1) {
4028
bool is_external = selection.front()->get()->is_instance();
4029
if (is_external) {
4030
bool is_inherited = selection.front()->get()->get_scene_inherited_state().is_valid();
4031
bool is_top_level = selection.front()->get()->get_owner() == nullptr;
4032
if (is_inherited && is_top_level) {
4033
BEGIN_SECTION()
4034
if (profile_allow_editing) {
4035
menu->add_item(TTR("Clear Inheritance"), TOOL_SCENE_CLEAR_INHERITANCE);
4036
}
4037
menu->add_icon_item(get_editor_theme_icon(SNAME("Load")), TTR("Open in Editor"), TOOL_SCENE_OPEN_INHERITED);
4038
} else if (!is_top_level) {
4039
BEGIN_SECTION()
4040
bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(selection.front()->get());
4041
bool placeholder = selection.front()->get()->get_scene_instance_load_placeholder();
4042
if (profile_allow_editing) {
4043
menu->add_check_item(TTR("Editable Children"), TOOL_SCENE_EDITABLE_CHILDREN);
4044
menu->set_item_shortcut(-1, ED_GET_SHORTCUT("scene_tree/toggle_editable_children"));
4045
4046
menu->add_check_item(TTR("Load as Placeholder"), TOOL_SCENE_USE_PLACEHOLDER);
4047
menu->add_item(TTR("Make Local"), TOOL_SCENE_MAKE_LOCAL);
4048
}
4049
menu->add_icon_item(get_editor_theme_icon(SNAME("Load")), TTR("Open in Editor"), TOOL_SCENE_OPEN);
4050
if (profile_allow_editing) {
4051
menu->set_item_checked(menu->get_item_idx_from_text(TTR("Editable Children")), editable);
4052
menu->set_item_checked(menu->get_item_idx_from_text(TTR("Load as Placeholder")), placeholder);
4053
}
4054
}
4055
}
4056
END_SECTION()
4057
}
4058
4059
if (profile_allow_editing && selection.size() > 1) {
4060
//this is not a commonly used action, it makes no sense for it to be where it was nor always present.
4061
BEGIN_SECTION()
4062
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Rename")), ED_GET_SHORTCUT("scene_tree/batch_rename"), TOOL_BATCH_RENAME);
4063
END_SECTION()
4064
}
4065
BEGIN_SECTION()
4066
if (full_selection.size() == 1 && selection.front()->get()->is_instance()) {
4067
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ShowInFileSystem")), ED_GET_SHORTCUT("scene_tree/show_in_file_system"), TOOL_SHOW_IN_FILE_SYSTEM);
4068
}
4069
4070
menu->add_icon_item(get_editor_theme_icon(SNAME("Help")), TTR("Open Documentation"), TOOL_OPEN_DOCUMENTATION);
4071
4072
if (profile_allow_editing) {
4073
menu->add_separator();
4074
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Remove")), ED_GET_SHORTCUT("scene_tree/delete"), TOOL_ERASE);
4075
}
4076
END_SECTION()
4077
4078
#undef BEGIN_SECTION
4079
#undef END_SECTIOn
4080
4081
Vector<String> p_paths;
4082
Node *root = EditorNode::get_singleton()->get_edited_scene();
4083
for (const List<Node *>::Element *E = selection.front(); E; E = E->next()) {
4084
String node_path = String(root->get_path().rel_path_to(E->get()->get_path()));
4085
p_paths.push_back(node_path);
4086
}
4087
EditorContextMenuPluginManager::get_singleton()->add_options_from_plugins(menu, EditorContextMenuPlugin::CONTEXT_SLOT_SCENE_TREE, p_paths);
4088
4089
menu->reset_size();
4090
menu->set_position(p_menu_pos);
4091
menu->popup();
4092
}
4093
4094
void SceneTreeDock::_update_tree_menu() {
4095
PopupMenu *tree_menu = button_tree_menu->get_popup();
4096
tree_menu->clear();
4097
4098
tree_menu->add_check_item(TTR("Auto Expand to Selected"), TOOL_AUTO_EXPAND);
4099
tree_menu->set_item_checked(-1, EDITOR_GET("docks/scene_tree/auto_expand_to_selected"));
4100
4101
tree_menu->add_check_item(TTR("Center Node on Reparent"), TOOL_CENTER_PARENT);
4102
tree_menu->set_item_checked(-1, EDITOR_GET("docks/scene_tree/center_node_on_reparent"));
4103
tree_menu->set_item_tooltip(-1, TTR("If enabled, Reparent to New Node will create the new node in the center of the selected nodes, if possible."));
4104
4105
tree_menu->add_check_item(TTR("Hide Filtered Out Parents"), TOOL_HIDE_FILTERED_OUT_PARENTS);
4106
tree_menu->set_item_checked(-1, EDITOR_GET("docks/scene_tree/hide_filtered_out_parents"));
4107
4108
tree_menu->add_separator();
4109
tree_menu->add_check_item(TTR("Show Accessibility Warnings"), TOOL_ACCESSIBILITY_WARNINGS);
4110
tree_menu->set_item_checked(tree_menu->get_item_index(TOOL_ACCESSIBILITY_WARNINGS), EDITOR_GET("docks/scene_tree/accessibility_warnings"));
4111
4112
PopupMenu *resource_list = memnew(PopupMenu);
4113
resource_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
4114
resource_list->connect("about_to_popup", callable_mp(this, &SceneTreeDock::_list_all_subresources).bind(resource_list));
4115
resource_list->connect("index_pressed", callable_mp(this, &SceneTreeDock::_edit_subresource).bind(resource_list));
4116
tree_menu->add_submenu_node_item(TTR("All Scene Sub-Resources"), resource_list);
4117
4118
_append_filter_options_to(tree_menu);
4119
}
4120
4121
void SceneTreeDock::_filter_changed(const String &p_filter) {
4122
scene_tree->set_filter(p_filter);
4123
4124
String warning = scene_tree->get_filter_term_warning();
4125
if (!warning.is_empty()) {
4126
filter->add_theme_icon_override(SNAME("clear"), get_editor_theme_icon(SNAME("NodeWarning")));
4127
filter->set_tooltip_text(warning);
4128
} else {
4129
filter->remove_theme_icon_override(SNAME("clear"));
4130
filter->set_tooltip_text(TTR("Filter nodes by entering a part of their name, type (if prefixed with \"type:\" or \"t:\")\nor group (if prefixed with \"group:\" or \"g:\"). Filtering is case-insensitive."));
4131
}
4132
}
4133
4134
void SceneTreeDock::_filter_gui_input(const Ref<InputEvent> &p_event) {
4135
Ref<InputEventMouseButton> mb = p_event;
4136
if (mb.is_null()) {
4137
return;
4138
}
4139
4140
if (mb->is_pressed() && mb->get_button_index() == MouseButton::MIDDLE) {
4141
if (filter_quick_menu == nullptr) {
4142
filter_quick_menu = memnew(PopupMenu);
4143
filter_quick_menu->set_theme_type_variation("FlatMenuButton");
4144
_append_filter_options_to(filter_quick_menu);
4145
filter_quick_menu->connect(SceneStringName(id_pressed), callable_mp(this, &SceneTreeDock::_filter_option_selected));
4146
filter->add_child(filter_quick_menu);
4147
}
4148
4149
filter_quick_menu->set_position(get_screen_position() + get_local_mouse_position());
4150
filter_quick_menu->reset_size();
4151
filter_quick_menu->popup();
4152
filter_quick_menu->grab_focus();
4153
accept_event();
4154
}
4155
}
4156
4157
void SceneTreeDock::_filter_option_selected(int p_option) {
4158
String filter_parameter;
4159
switch (p_option) {
4160
case FILTER_BY_TYPE: {
4161
filter_parameter = "type";
4162
} break;
4163
case FILTER_BY_GROUP: {
4164
filter_parameter = "group";
4165
} break;
4166
}
4167
4168
if (!filter_parameter.is_empty()) {
4169
set_filter((get_filter() + " " + filter_parameter + ":").strip_edges());
4170
filter->set_caret_column(filter->get_text().length());
4171
filter->grab_focus();
4172
}
4173
}
4174
4175
void SceneTreeDock::_append_filter_options_to(PopupMenu *p_menu) {
4176
if (p_menu->get_item_count() > 0) {
4177
p_menu->add_separator();
4178
}
4179
4180
p_menu->add_item(TTRC("Filter by Type"), FILTER_BY_TYPE);
4181
p_menu->set_item_tooltip(-1, TTRC("Selects all Nodes of the given type.\nInserts \"type:\". You can also use the shorthand \"t:\"."));
4182
4183
p_menu->add_item(TTRC("Filter by Group"), FILTER_BY_GROUP);
4184
p_menu->set_item_tooltip(-1, TTRC("Selects all Nodes belonging to the given group.\nIf empty, selects any Node belonging to any group.\nInserts \"group:\". You can also use the shorthand \"g:\"."));
4185
}
4186
4187
String SceneTreeDock::get_filter() {
4188
return filter->get_text();
4189
}
4190
4191
void SceneTreeDock::set_filter(const String &p_filter) {
4192
filter->set_text(p_filter);
4193
scene_tree->set_filter(p_filter);
4194
}
4195
4196
void SceneTreeDock::save_branch_to_file(const String &p_directory) {
4197
new_scene_from_dialog->set_current_dir(p_directory);
4198
determine_path_automatically = false;
4199
_tool_selected(TOOL_NEW_SCENE_FROM);
4200
}
4201
4202
void SceneTreeDock::_focus_node() {
4203
Node *node = scene_tree->get_selected();
4204
// This method handles the item_icon_double_clicked signal and there is no guarantee anything is actually selected.
4205
if (!node) {
4206
return;
4207
}
4208
4209
if (node->is_class("CanvasItem")) {
4210
CanvasItemEditorPlugin *editor = Object::cast_to<CanvasItemEditorPlugin>(editor_data->get_editor_by_name("2D"));
4211
editor->get_canvas_item_editor()->focus_selection();
4212
} else {
4213
Node3DEditorPlugin *editor = Object::cast_to<Node3DEditorPlugin>(editor_data->get_editor_by_name("3D"));
4214
editor->get_spatial_editor()->get_editor_viewport(0)->focus_selection();
4215
}
4216
}
4217
4218
void SceneTreeDock::attach_script_to_selected(bool p_extend) {
4219
if (ScriptServer::get_language_count() == 0) {
4220
EditorNode::get_singleton()->show_warning(TTR("Cannot attach a script: there are no languages registered.\nThis is probably because this editor was built with all language modules disabled."));
4221
return;
4222
}
4223
4224
if (!profile_allow_script_editing) {
4225
return;
4226
}
4227
4228
const List<Node *> selection = editor_selection->get_top_selected_node_list();
4229
if (selection.is_empty()) {
4230
return;
4231
}
4232
4233
Node *selected = scene_tree->get_selected();
4234
if (!selected) {
4235
selected = selection.front()->get();
4236
}
4237
4238
Ref<Script> existing = selected->get_script();
4239
4240
String path = selected->get_scene_file_path();
4241
if (path.is_empty()) {
4242
String root_path = editor_data->get_edited_scene_root()->get_scene_file_path();
4243
if (root_path.is_empty()) {
4244
path = String("res://").path_join(selected->get_name());
4245
} else {
4246
path = root_path.get_base_dir().path_join(selected->get_name());
4247
}
4248
}
4249
4250
String inherits = selected->get_class();
4251
4252
if (p_extend && existing.is_valid()) {
4253
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
4254
ScriptLanguage *l = ScriptServer::get_language(i);
4255
if (l->get_type() == existing->get_class()) {
4256
String name = l->get_global_class_name(existing->get_path());
4257
if (ScriptServer::is_global_class(name) && EDITOR_GET("interface/editors/derive_script_globals_by_name").operator bool()) {
4258
inherits = name;
4259
} else if (l->can_inherit_from_file()) {
4260
inherits = "\"" + existing->get_path() + "\"";
4261
}
4262
break;
4263
}
4264
}
4265
}
4266
4267
script_create_dialog->connect("script_created", callable_mp(this, &SceneTreeDock::_script_created));
4268
script_create_dialog->connect(SceneStringName(confirmed), callable_mp(this, &SceneTreeDock::_script_creation_closed));
4269
script_create_dialog->connect("canceled", callable_mp(this, &SceneTreeDock::_script_creation_closed));
4270
script_create_dialog->set_inheritance_base_type("Node");
4271
script_create_dialog->config(inherits, path);
4272
script_create_dialog->popup_centered();
4273
}
4274
4275
void SceneTreeDock::open_script_dialog(Node *p_for_node, bool p_extend) {
4276
scene_tree->set_selected(p_for_node, false);
4277
4278
if (p_extend) {
4279
_tool_selected(TOOL_EXTEND_SCRIPT);
4280
} else {
4281
_tool_selected(TOOL_ATTACH_SCRIPT);
4282
}
4283
}
4284
4285
void SceneTreeDock::attach_shader_to_selected(int p_preferred_mode) {
4286
if (selected_shader_material.is_null()) {
4287
return;
4288
}
4289
4290
String path = selected_shader_material->get_path();
4291
if (path.get_base_dir().is_empty()) {
4292
String root_path;
4293
if (editor_data->get_edited_scene_root()) {
4294
root_path = editor_data->get_edited_scene_root()->get_scene_file_path();
4295
}
4296
String shader_name;
4297
if (selected_shader_material->get_name().is_empty()) {
4298
shader_name = root_path.get_file();
4299
} else {
4300
shader_name = selected_shader_material->get_name();
4301
}
4302
if (shader_name.is_empty()) {
4303
shader_name = "new_shader";
4304
}
4305
if (root_path.is_empty()) {
4306
path = String("res://").path_join(shader_name);
4307
} else {
4308
path = root_path.get_base_dir().path_join(shader_name);
4309
}
4310
}
4311
4312
shader_create_dialog->connect("shader_created", callable_mp(this, &SceneTreeDock::_shader_created));
4313
shader_create_dialog->connect(SceneStringName(confirmed), callable_mp(this, &SceneTreeDock::_shader_creation_closed));
4314
shader_create_dialog->connect("canceled", callable_mp(this, &SceneTreeDock::_shader_creation_closed));
4315
shader_create_dialog->config(path, true, true, "", p_preferred_mode);
4316
shader_create_dialog->popup_centered();
4317
}
4318
4319
void SceneTreeDock::open_shader_dialog(const Ref<ShaderMaterial> &p_for_material, int p_preferred_mode) {
4320
selected_shader_material = p_for_material;
4321
attach_shader_to_selected(p_preferred_mode);
4322
}
4323
4324
void SceneTreeDock::open_add_child_dialog() {
4325
create_dialog->set_base_type("CanvasItem");
4326
_tool_selected(TOOL_NEW, true);
4327
reset_create_dialog = true;
4328
}
4329
4330
void SceneTreeDock::open_instance_child_dialog() {
4331
_tool_selected(TOOL_INSTANTIATE, true);
4332
}
4333
4334
List<Node *> SceneTreeDock::paste_nodes(bool p_paste_as_sibling) {
4335
List<Node *> pasted_nodes;
4336
4337
if (node_clipboard.is_empty()) {
4338
return pasted_nodes;
4339
}
4340
4341
bool has_cycle = false;
4342
if (edited_scene && !edited_scene->get_scene_file_path().is_empty()) {
4343
for (Node *E : node_clipboard) {
4344
if (edited_scene->get_scene_file_path() == E->get_scene_file_path()) {
4345
has_cycle = true;
4346
break;
4347
}
4348
}
4349
}
4350
4351
if (has_cycle) {
4352
current_option = -1;
4353
accept->set_text(TTR("Can't paste root node into the same scene."));
4354
accept->popup_centered();
4355
return pasted_nodes;
4356
}
4357
4358
Node *paste_parent = edited_scene;
4359
Node *paste_sibling = nullptr;
4360
4361
const List<Node *> selection = editor_selection->get_top_selected_node_list();
4362
if (selection.size() > 0) {
4363
paste_parent = selection.back()->get();
4364
}
4365
4366
if (p_paste_as_sibling) {
4367
if (paste_parent == edited_scene) {
4368
return pasted_nodes; // Don't paste as sibling of scene root.
4369
}
4370
4371
paste_sibling = paste_parent;
4372
paste_parent = paste_parent->get_parent();
4373
}
4374
4375
Node *owner = nullptr;
4376
if (paste_parent) {
4377
owner = paste_parent->get_owner();
4378
}
4379
if (!owner) {
4380
owner = paste_parent;
4381
}
4382
4383
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
4384
if (paste_parent) {
4385
ur->create_action(vformat(p_paste_as_sibling ? TTR("Paste Node(s) as Sibling of %s") : TTR("Paste Node(s) as Child of %s"), paste_sibling ? paste_sibling->get_name() : paste_parent->get_name()), UndoRedo::MERGE_DISABLE, edited_scene);
4386
} else {
4387
ur->create_action(TTR("Paste Node(s) as Root"), UndoRedo::MERGE_DISABLE, edited_scene);
4388
}
4389
ur->add_do_method(editor_selection, "clear");
4390
4391
String target_scene;
4392
if (edited_scene) {
4393
target_scene = edited_scene->get_scene_file_path();
4394
}
4395
HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &resources_local_to_scenes = clipboard_resource_remap[target_scene]; // Record the mappings in the sub-scene.
4396
if (target_scene != clipboard_source_scene) {
4397
if (!resources_local_to_scenes.has(nullptr)) {
4398
HashMap<Ref<Resource>, Ref<Resource>> remap;
4399
for (Node *E : node_clipboard) {
4400
_create_remap_for_node(E, remap);
4401
}
4402
resources_local_to_scenes[nullptr] = remap;
4403
}
4404
}
4405
4406
for (Node *node : node_clipboard) {
4407
HashMap<const Node *, Node *> duplimap;
4408
4409
Node *dup = node->duplicate_from_editor(duplimap, edited_scene, resources_local_to_scenes);
4410
ERR_CONTINUE(!dup);
4411
4412
pasted_nodes.push_back(dup);
4413
4414
if (!paste_parent) {
4415
paste_parent = dup;
4416
owner = dup;
4417
dup->set_scene_file_path(String()); // Make sure the scene path is empty, to avoid accidental references.
4418
ur->add_do_method(EditorNode::get_singleton(), "set_edited_scene", dup);
4419
} else {
4420
ur->add_do_method(paste_parent, "add_child", dup, true);
4421
if (paste_sibling) {
4422
ur->add_do_method(paste_parent, "move_child", dup, paste_sibling->get_index() + 1);
4423
}
4424
}
4425
4426
for (KeyValue<const Node *, Node *> &E2 : duplimap) {
4427
Node *d = E2.value;
4428
// When copying, all nodes that should have an owner assigned here were given nullptr as an owner
4429
// and added to the node_clipboard_edited_scene_owned list.
4430
if (d != dup && E2.key->get_owner() == nullptr) {
4431
if (node_clipboard_edited_scene_owned.find(const_cast<Node *>(E2.key))) {
4432
ur->add_do_method(d, "set_owner", owner);
4433
}
4434
}
4435
}
4436
4437
if (dup != owner) {
4438
ur->add_do_method(dup, "set_owner", edited_scene);
4439
}
4440
ur->add_do_method(editor_selection, "add_node", dup);
4441
4442
if (dup == paste_parent) {
4443
ur->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
4444
} else {
4445
ur->add_undo_method(paste_parent, "remove_child", dup);
4446
}
4447
ur->add_do_reference(dup);
4448
4449
if (node_clipboard.size() == 1) {
4450
ur->add_do_method(EditorNode::get_singleton(), "push_item", dup);
4451
}
4452
}
4453
4454
ur->commit_action();
4455
4456
for (KeyValue<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &KV : resources_local_to_scenes) {
4457
for (KeyValue<Ref<Resource>, Ref<Resource>> &R : KV.value) {
4458
if (R.value->is_local_to_scene()) {
4459
R.value->setup_local_to_scene();
4460
}
4461
}
4462
}
4463
4464
return pasted_nodes;
4465
}
4466
4467
List<Node *> SceneTreeDock::get_node_clipboard() const {
4468
return node_clipboard;
4469
}
4470
4471
void SceneTreeDock::add_remote_tree_editor(Tree *p_remote) {
4472
ERR_FAIL_COND(remote_tree != nullptr);
4473
main_mc->add_child(p_remote);
4474
remote_tree = p_remote;
4475
remote_tree->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_TOP);
4476
remote_tree->hide();
4477
remote_tree->connect("open", callable_mp(this, &SceneTreeDock::_load_request));
4478
}
4479
4480
void SceneTreeDock::show_remote_tree() {
4481
_remote_tree_selected();
4482
}
4483
4484
void SceneTreeDock::hide_remote_tree() {
4485
_local_tree_selected();
4486
}
4487
4488
void SceneTreeDock::show_tab_buttons() {
4489
button_hb->show();
4490
}
4491
4492
void SceneTreeDock::hide_tab_buttons() {
4493
button_hb->hide();
4494
}
4495
4496
void SceneTreeDock::_remote_tree_selected() {
4497
main_mc->set_theme_type_variation("NoBorderHorizontalBottom");
4498
scene_tree->hide();
4499
create_root_dialog->hide();
4500
if (remote_tree) {
4501
remote_tree->show();
4502
}
4503
edit_remote->set_pressed(true);
4504
edit_local->set_pressed(false);
4505
4506
emit_signal(SNAME("remote_tree_selected"));
4507
}
4508
4509
void SceneTreeDock::_local_tree_selected() {
4510
if (!bool(EDITOR_GET("interface/editors/show_scene_tree_root_selection")) || get_tree()->get_edited_scene_root() != nullptr) {
4511
scene_tree->show();
4512
}
4513
if (remote_tree) {
4514
remote_tree->hide();
4515
}
4516
edit_remote->set_pressed(false);
4517
edit_local->set_pressed(true);
4518
}
4519
4520
void SceneTreeDock::_update_create_root_dialog(bool p_initializing) {
4521
if (!p_initializing) {
4522
EditorSettings::get_singleton()->set_setting("_use_favorites_root_selection", node_shortcuts_toggle->is_pressed());
4523
EditorSettings::get_singleton()->save();
4524
}
4525
4526
if (node_shortcuts_toggle->is_pressed()) {
4527
for (int i = 0; i < favorite_node_shortcuts->get_child_count(); i++) {
4528
favorite_node_shortcuts->get_child(i)->queue_free();
4529
}
4530
4531
Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites.Node"), FileAccess::READ);
4532
if (f.is_valid()) {
4533
while (!f->eof_reached()) {
4534
String l = f->get_line().strip_edges();
4535
4536
if (!l.is_empty()) {
4537
Button *button = memnew(Button);
4538
favorite_node_shortcuts->add_child(button);
4539
button->set_text(l);
4540
button->set_clip_text(true);
4541
String name = l.get_slicec(' ', 0);
4542
if (ScriptServer::is_global_class(name)) {
4543
name = ScriptServer::get_global_class_native_base(name);
4544
}
4545
button->set_button_icon(EditorNode::get_singleton()->get_class_icon(name));
4546
button->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_favorite_root_selected).bind(l));
4547
}
4548
}
4549
}
4550
4551
if (!favorite_node_shortcuts->is_visible_in_tree()) {
4552
favorite_node_shortcuts->show();
4553
beginner_node_shortcuts->hide();
4554
}
4555
} else {
4556
if (!beginner_node_shortcuts->is_visible_in_tree()) {
4557
beginner_node_shortcuts->show();
4558
favorite_node_shortcuts->hide();
4559
}
4560
button_clipboard->set_visible(!node_clipboard.is_empty());
4561
}
4562
}
4563
4564
void SceneTreeDock::_favorite_root_selected(const String &p_class) {
4565
selected_favorite_root = p_class;
4566
_tool_selected(TOOL_CREATE_FAVORITE);
4567
}
4568
4569
void SceneTreeDock::_feature_profile_changed() {
4570
Ref<EditorFeatureProfile> profile = EditorFeatureProfileManager::get_singleton()->get_current_profile();
4571
4572
if (profile.is_valid()) {
4573
profile_allow_editing = !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCENE_TREE);
4574
profile_allow_script_editing = !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCRIPT);
4575
bool profile_allow_3d = !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D);
4576
4577
button_3d->set_visible(profile_allow_3d);
4578
button_add->set_visible(profile_allow_editing);
4579
button_instance->set_visible(profile_allow_editing);
4580
scene_tree->set_can_rename(profile_allow_editing);
4581
4582
} else {
4583
button_3d->set_visible(true);
4584
button_add->set_visible(true);
4585
button_instance->set_visible(true);
4586
scene_tree->set_can_rename(true);
4587
profile_allow_editing = true;
4588
profile_allow_script_editing = true;
4589
}
4590
4591
_queue_update_script_button();
4592
}
4593
4594
void SceneTreeDock::_clear_clipboard() {
4595
for (Node *E : node_clipboard) {
4596
memdelete(E);
4597
}
4598
node_clipboard.clear();
4599
node_clipboard_edited_scene_owned.clear();
4600
clipboard_resource_remap.clear();
4601
}
4602
4603
void SceneTreeDock::_create_remap_for_node(Node *p_node, HashMap<Ref<Resource>, Ref<Resource>> &r_remap) {
4604
List<PropertyInfo> props;
4605
p_node->get_property_list(&props);
4606
4607
Vector<SceneState::PackState> states_stack;
4608
bool states_stack_ready = false;
4609
4610
for (const PropertyInfo &E : props) {
4611
if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
4612
continue;
4613
}
4614
4615
Variant v = p_node->get(E.name);
4616
if (v.is_ref_counted()) {
4617
Ref<Resource> res = v;
4618
if (res.is_valid()) {
4619
if (!states_stack_ready) {
4620
states_stack = PropertyUtils::get_node_states_stack(p_node);
4621
states_stack_ready = true;
4622
}
4623
4624
bool is_valid_default = false;
4625
Variant orig = PropertyUtils::get_property_default_value(p_node, E.name, &is_valid_default, &states_stack);
4626
if (is_valid_default && !PropertyUtils::is_property_value_different(p_node, v, orig)) {
4627
continue;
4628
}
4629
4630
if (res->is_built_in() && !r_remap.has(res)) {
4631
_create_remap_for_resource(res, r_remap);
4632
}
4633
}
4634
}
4635
}
4636
4637
for (int i = 0; i < p_node->get_child_count(); i++) {
4638
_create_remap_for_node(p_node->get_child(i), r_remap);
4639
}
4640
}
4641
4642
void SceneTreeDock::_create_remap_for_resource(Ref<Resource> p_resource, HashMap<Ref<Resource>, Ref<Resource>> &r_remap) {
4643
r_remap[p_resource] = p_resource->duplicate();
4644
4645
List<PropertyInfo> props;
4646
p_resource->get_property_list(&props);
4647
4648
for (const PropertyInfo &E : props) {
4649
if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
4650
continue;
4651
}
4652
4653
Variant v = p_resource->get(E.name);
4654
if (v.is_ref_counted()) {
4655
Ref<Resource> res = v;
4656
if (res.is_valid()) {
4657
if (res->is_built_in() && !r_remap.has(res)) {
4658
_create_remap_for_resource(res, r_remap);
4659
}
4660
}
4661
}
4662
}
4663
}
4664
4665
void SceneTreeDock::_list_all_subresources(PopupMenu *p_menu) {
4666
p_menu->clear();
4667
4668
List<Pair<Ref<Resource>, Node *>> all_resources;
4669
if (edited_scene) {
4670
_gather_resources(edited_scene, all_resources);
4671
}
4672
4673
HashMap<String, List<Pair<Ref<Resource>, Node *>>> resources_by_type;
4674
HashMap<Ref<Resource>, int> unique_resources;
4675
4676
for (const Pair<Ref<Resource>, Node *> &pair : all_resources) {
4677
if (!unique_resources.has(pair.first)) {
4678
resources_by_type[pair.first->get_class()].push_back(pair);
4679
}
4680
unique_resources[pair.first]++;
4681
}
4682
4683
for (KeyValue<String, List<Pair<Ref<Resource>, Node *>>> kv : resources_by_type) {
4684
p_menu->add_icon_item(EditorNode::get_singleton()->get_class_icon(kv.key), kv.key);
4685
p_menu->set_item_as_separator(-1, true);
4686
4687
for (const Pair<Ref<Resource>, Node *> &pair : kv.value) {
4688
String display_text;
4689
if (pair.first->get_name().is_empty()) {
4690
display_text = vformat(TTR("<Unnamed> at %s"), pair.second->get_name());
4691
} else {
4692
display_text = pair.first->get_name();
4693
}
4694
4695
if (unique_resources[pair.first] > 1) {
4696
display_text += " " + vformat(TTR("(used %d times)"), unique_resources[pair.first]);
4697
}
4698
4699
p_menu->add_item(display_text);
4700
p_menu->set_item_tooltip(-1, pair.first->get_path());
4701
p_menu->set_item_metadata(-1, pair.first->get_instance_id());
4702
}
4703
}
4704
4705
if (resources_by_type.is_empty()) {
4706
p_menu->add_item(TTR("None"));
4707
p_menu->set_item_disabled(-1, true);
4708
}
4709
4710
p_menu->reset_size();
4711
}
4712
4713
void SceneTreeDock::_gather_resources(Node *p_node, List<Pair<Ref<Resource>, Node *>> &r_resources) {
4714
if (p_node != edited_scene && p_node->get_owner() != edited_scene) {
4715
return;
4716
}
4717
4718
List<PropertyInfo> pinfo;
4719
p_node->get_property_list(&pinfo);
4720
for (const PropertyInfo &E : pinfo) {
4721
if (!(E.usage & PROPERTY_USAGE_EDITOR)) {
4722
continue;
4723
}
4724
if (E.hint != PROPERTY_HINT_RESOURCE_TYPE) {
4725
continue;
4726
}
4727
4728
Variant value = p_node->get(E.name);
4729
if (value.get_type() != Variant::OBJECT) {
4730
continue;
4731
}
4732
Ref<Resource> res = value;
4733
if (res.is_null()) {
4734
continue;
4735
}
4736
4737
if (!res->is_built_in() || res->get_path().get_slice("::", 0) != edited_scene->get_scene_file_path()) {
4738
// Ignore external and foreign resources.
4739
continue;
4740
}
4741
4742
const Pair<Ref<Resource>, Node *> pair(res, p_node);
4743
r_resources.push_back(pair);
4744
}
4745
4746
for (int i = 0; i < p_node->get_child_count(); i++) {
4747
_gather_resources(p_node->get_child(i), r_resources);
4748
}
4749
}
4750
4751
void SceneTreeDock::_edit_subresource(int p_idx, const PopupMenu *p_from_menu) {
4752
const ObjectID &id = p_from_menu->get_item_metadata(p_idx);
4753
4754
Object *obj = ObjectDB::get_instance(id);
4755
ERR_FAIL_NULL(obj);
4756
4757
_push_item(obj);
4758
}
4759
4760
void SceneTreeDock::_bind_methods() {
4761
ClassDB::bind_method(D_METHOD("_post_do_create"), &SceneTreeDock::_post_do_create);
4762
ClassDB::bind_method(D_METHOD("_set_owners"), &SceneTreeDock::_set_owners);
4763
ClassDB::bind_method(D_METHOD("_reparent_nodes_to_root"), &SceneTreeDock::_reparent_nodes_to_root);
4764
ClassDB::bind_method(D_METHOD("_reparent_nodes_to_paths_with_transform_and_name"), &SceneTreeDock::_reparent_nodes_to_paths_with_transform_and_name);
4765
4766
ClassDB::bind_method(D_METHOD("_queue_update_script_button"), &SceneTreeDock::_queue_update_script_button);
4767
4768
ClassDB::bind_method(D_METHOD("instantiate"), &SceneTreeDock::instantiate);
4769
ClassDB::bind_method(D_METHOD("get_tree_editor"), &SceneTreeDock::get_tree_editor);
4770
ClassDB::bind_method(D_METHOD("replace_node"), &SceneTreeDock::_replace_node);
4771
4772
ADD_SIGNAL(MethodInfo("remote_tree_selected"));
4773
ADD_SIGNAL(MethodInfo("add_node_used"));
4774
ADD_SIGNAL(MethodInfo("node_created", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, Node::get_class_static())));
4775
}
4776
4777
SceneTreeDock *SceneTreeDock::singleton = nullptr;
4778
4779
void SceneTreeDock::_update_configuration_warning() {
4780
if (singleton) {
4781
callable_mp(singleton->scene_tree, &SceneTreeEditor::update_warning).call_deferred();
4782
}
4783
}
4784
4785
SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selection, EditorData &p_editor_data) {
4786
set_name(TTRC("Scene"));
4787
set_icon_name("PackedScene");
4788
set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("docks/open_scene", TTRC("Open Scene Dock")));
4789
set_default_slot(EditorDock::DOCK_SLOT_LEFT_UR);
4790
4791
singleton = this;
4792
editor_data = &p_editor_data;
4793
editor_selection = p_editor_selection;
4794
scene_root = p_scene_root;
4795
4796
VBoxContainer *main_vbox = memnew(VBoxContainer);
4797
add_child(main_vbox);
4798
4799
HBoxContainer *filter_hbc = memnew(HBoxContainer);
4800
filter_hbc->add_theme_constant_override("separate", 0);
4801
4802
ED_SHORTCUT("scene_tree/rename", TTRC("Rename"), Key::F2);
4803
ED_SHORTCUT_OVERRIDE("scene_tree/rename", "macos", Key::ENTER);
4804
4805
ED_SHORTCUT("scene_tree/batch_rename", TTRC("Batch Rename..."), KeyModifierMask::SHIFT | Key::F2);
4806
ED_SHORTCUT_OVERRIDE("scene_tree/batch_rename", "macos", KeyModifierMask::SHIFT | Key::ENTER);
4807
4808
ED_SHORTCUT("scene_tree/add_child_node", TTRC("Add Child Node..."), KeyModifierMask::CMD_OR_CTRL | Key::A);
4809
ED_SHORTCUT("scene_tree/instantiate_scene", TTRC("Instantiate Child Scene..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::A);
4810
ED_SHORTCUT("scene_tree/expand_collapse_all", TTRC("Expand/Collapse Branch"));
4811
ED_SHORTCUT("scene_tree/cut_node", TTRC("Cut"), KeyModifierMask::CMD_OR_CTRL | Key::X);
4812
ED_SHORTCUT("scene_tree/copy_node", TTRC("Copy"), KeyModifierMask::CMD_OR_CTRL | Key::C);
4813
ED_SHORTCUT("scene_tree/paste_node", TTRC("Paste"), KeyModifierMask::CMD_OR_CTRL | Key::V);
4814
ED_SHORTCUT("scene_tree/paste_node_as_sibling", TTRC("Paste as Sibling"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::V);
4815
ED_SHORTCUT("scene_tree/change_node_type", TTRC("Change Type..."));
4816
ED_SHORTCUT("scene_tree/attach_script", TTRC("Attach Script..."));
4817
ED_SHORTCUT("scene_tree/extend_script", TTRC("Extend Script..."));
4818
ED_SHORTCUT("scene_tree/detach_script", TTRC("Detach Script"));
4819
ED_SHORTCUT("scene_tree/move_up", TTRC("Move Up"), KeyModifierMask::CMD_OR_CTRL | Key::UP);
4820
ED_SHORTCUT("scene_tree/move_down", TTRC("Move Down"), KeyModifierMask::CMD_OR_CTRL | Key::DOWN);
4821
ED_SHORTCUT("scene_tree/duplicate", TTRC("Duplicate"), KeyModifierMask::CMD_OR_CTRL | Key::D);
4822
ED_SHORTCUT("scene_tree/reparent", TTRC("Reparent..."));
4823
ED_SHORTCUT("scene_tree/reparent_to_new_node", TTRC("Reparent to New Node..."));
4824
ED_SHORTCUT("scene_tree/make_root", TTRC("Make Scene Root"));
4825
ED_SHORTCUT("scene_tree/save_branch_as_scene", TTRC("Save Branch as Scene..."));
4826
ED_SHORTCUT("scene_tree/copy_node_path", TTRC("Copy Node Path"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::C);
4827
ED_SHORTCUT("scene_tree/show_in_file_system", TTRC("Show in FileSystem"));
4828
ED_SHORTCUT("scene_tree/toggle_unique_name", TTRC("Toggle Access as Unique Name"));
4829
ED_SHORTCUT("scene_tree/toggle_editable_children", TTRC("Toggle Editable Children"));
4830
ED_SHORTCUT("scene_tree/delete_no_confirm", TTRC("Delete (No Confirm)"), KeyModifierMask::SHIFT | Key::KEY_DELETE);
4831
ED_SHORTCUT("scene_tree/delete", TTRC("Delete"), Key::KEY_DELETE);
4832
4833
button_add = memnew(Button);
4834
button_add->set_theme_type_variation("FlatMenuButton");
4835
button_add->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_NEW, false));
4836
button_add->set_tooltip_text(TTRC("Add/Create a New Node."));
4837
button_add->set_shortcut(ED_GET_SHORTCUT("scene_tree/add_child_node"));
4838
filter_hbc->add_child(button_add);
4839
4840
button_instance = memnew(Button);
4841
button_instance->set_theme_type_variation("FlatMenuButton");
4842
button_instance->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_INSTANTIATE, false));
4843
button_instance->set_tooltip_text(TTRC("Instantiate a scene file as a Node. Creates an inherited scene if no root node exists."));
4844
button_instance->set_shortcut(ED_GET_SHORTCUT("scene_tree/instantiate_scene"));
4845
filter_hbc->add_child(button_instance);
4846
main_vbox->add_child(filter_hbc);
4847
4848
// The "Filter Nodes" text input above the Scene Tree Editor.
4849
filter = memnew(LineEdit);
4850
filter->set_h_size_flags(SIZE_EXPAND_FILL);
4851
filter->set_placeholder(TTRC("Filter Nodes"));
4852
filter->set_accessibility_name(TTRC("Filter Nodes"));
4853
filter->set_tooltip_text(TTRC("Filter nodes by entering a part of their name, type (if prefixed with \"type:\" or \"t:\")\nor group (if prefixed with \"group:\" or \"g:\"). Filtering is case-insensitive."));
4854
filter_hbc->add_child(filter);
4855
filter->add_theme_constant_override("minimum_character_width", 0);
4856
filter->connect(SceneStringName(text_changed), callable_mp(this, &SceneTreeDock::_filter_changed));
4857
filter->connect(SceneStringName(gui_input), callable_mp(this, &SceneTreeDock::_filter_gui_input));
4858
filter->get_menu()->connect(SceneStringName(id_pressed), callable_mp(this, &SceneTreeDock::_filter_option_selected));
4859
_append_filter_options_to(filter->get_menu());
4860
4861
button_create_script = memnew(Button);
4862
button_create_script->set_theme_type_variation("FlatMenuButton");
4863
button_create_script->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_ATTACH_SCRIPT, false));
4864
button_create_script->set_tooltip_text(TTRC("Attach a new or existing script to the selected node."));
4865
button_create_script->set_shortcut(ED_GET_SHORTCUT("scene_tree/attach_script"));
4866
filter_hbc->add_child(button_create_script);
4867
button_create_script->hide();
4868
4869
button_detach_script = memnew(Button);
4870
button_detach_script->set_theme_type_variation("FlatMenuButton");
4871
button_detach_script->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_DETACH_SCRIPT, false));
4872
button_detach_script->set_tooltip_text(TTRC("Detach the script from the selected node."));
4873
button_detach_script->set_shortcut(ED_GET_SHORTCUT("scene_tree/detach_script"));
4874
filter_hbc->add_child(button_detach_script);
4875
button_detach_script->hide();
4876
4877
button_extend_script = memnew(Button);
4878
button_extend_script->set_flat(true);
4879
button_extend_script->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_EXTEND_SCRIPT, false));
4880
button_extend_script->set_tooltip_text(TTRC("Extend the script of the selected node."));
4881
button_extend_script->set_shortcut(ED_GET_SHORTCUT("scene_tree/extend_script"));
4882
filter_hbc->add_child(button_extend_script);
4883
button_extend_script->hide();
4884
4885
button_tree_menu = memnew(MenuButton);
4886
button_tree_menu->set_flat(false);
4887
button_tree_menu->set_theme_type_variation("FlatMenuButton");
4888
button_tree_menu->set_tooltip_text(TTR("Extra scene options."));
4889
button_tree_menu->connect("about_to_popup", callable_mp(this, &SceneTreeDock::_update_tree_menu));
4890
filter_hbc->add_child(button_tree_menu);
4891
4892
PopupMenu *tree_menu = button_tree_menu->get_popup();
4893
tree_menu->connect(SceneStringName(id_pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(false));
4894
4895
button_hb = memnew(HBoxContainer);
4896
main_vbox->add_child(button_hb);
4897
4898
edit_remote = memnew(Button);
4899
edit_remote->set_theme_type_variation(SceneStringName(FlatButton));
4900
edit_remote->set_h_size_flags(SIZE_EXPAND_FILL);
4901
edit_remote->set_text(TTR("Remote"));
4902
edit_remote->set_toggle_mode(true);
4903
edit_remote->set_tooltip_text(TTR("If selected, the Remote scene tree dock will cause the project to stutter every time it updates.\nSwitch back to the Local scene tree dock to improve performance."));
4904
button_hb->add_child(edit_remote);
4905
edit_remote->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_remote_tree_selected));
4906
4907
edit_local = memnew(Button);
4908
edit_local->set_theme_type_variation(SceneStringName(FlatButton));
4909
edit_local->set_h_size_flags(SIZE_EXPAND_FILL);
4910
edit_local->set_text(TTR("Local"));
4911
edit_local->set_toggle_mode(true);
4912
edit_local->set_pressed(true);
4913
button_hb->add_child(edit_local);
4914
edit_local->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_local_tree_selected));
4915
4916
remote_tree = nullptr;
4917
button_hb->hide();
4918
4919
main_mc = memnew(MarginContainer);
4920
main_vbox->add_child(main_mc);
4921
main_mc->set_theme_type_variation("NoBorderHorizontalBottom");
4922
main_mc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
4923
4924
create_root_dialog = memnew(VBoxContainer);
4925
main_mc->add_child(create_root_dialog);
4926
create_root_dialog->set_v_size_flags(SIZE_EXPAND_FILL);
4927
create_root_dialog->hide();
4928
4929
scene_tree = memnew(SceneTreeEditor(false, true, true));
4930
main_mc->add_child(scene_tree);
4931
scene_tree->get_scene_tree()->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_TOP);
4932
scene_tree->connect("rmb_pressed", callable_mp(this, &SceneTreeDock::_tree_rmb));
4933
4934
scene_tree->connect("node_selected", callable_mp(this, &SceneTreeDock::_node_selected), CONNECT_DEFERRED);
4935
scene_tree->connect("node_renamed", callable_mp(this, &SceneTreeDock::_node_renamed), CONNECT_DEFERRED);
4936
scene_tree->connect("node_prerename", callable_mp(this, &SceneTreeDock::_node_prerenamed));
4937
scene_tree->connect("open", callable_mp(this, &SceneTreeDock::_load_request));
4938
scene_tree->connect("open_script", callable_mp(this, &SceneTreeDock::_script_open_request));
4939
scene_tree->connect("nodes_rearranged", callable_mp(this, &SceneTreeDock::_nodes_dragged));
4940
scene_tree->connect("files_dropped", callable_mp(this, &SceneTreeDock::_files_dropped));
4941
scene_tree->connect("script_dropped", callable_mp(this, &SceneTreeDock::_script_dropped));
4942
scene_tree->connect("nodes_dragged", callable_mp(this, &SceneTreeDock::_nodes_drag_begin));
4943
scene_tree->get_scene_tree()->get_vscroll_bar()->connect("value_changed", callable_mp(this, &SceneTreeDock::_reset_hovering_timer).unbind(1));
4944
4945
scene_tree->get_scene_tree()->connect(SceneStringName(gui_input), callable_mp(this, &SceneTreeDock::_scene_tree_gui_input));
4946
scene_tree->get_scene_tree()->connect("item_icon_double_clicked", callable_mp(this, &SceneTreeDock::_focus_node));
4947
4948
editor_selection->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed));
4949
4950
scene_tree->set_as_scene_tree_dock();
4951
scene_tree->set_editor_selection(editor_selection);
4952
4953
inspect_hovered_node_delay = memnew(Timer);
4954
inspect_hovered_node_delay->connect("timeout", callable_mp(this, &SceneTreeDock::_inspect_hovered_node));
4955
inspect_hovered_node_delay->set_one_shot(true);
4956
add_child(inspect_hovered_node_delay);
4957
4958
create_dialog = memnew(CreateDialog);
4959
create_dialog->set_base_type("Node");
4960
add_child(create_dialog);
4961
create_dialog->connect("create", callable_mp(this, &SceneTreeDock::_create));
4962
create_dialog->connect("favorites_updated", callable_mp(this, &SceneTreeDock::_update_create_root_dialog).bind(false));
4963
4964
rename_dialog = memnew(RenameDialog(scene_tree));
4965
add_child(rename_dialog);
4966
4967
script_create_dialog = memnew(ScriptCreateDialog);
4968
script_create_dialog->set_inheritance_base_type("Node");
4969
add_child(script_create_dialog);
4970
4971
shader_create_dialog = memnew(ShaderCreateDialog);
4972
add_child(shader_create_dialog);
4973
4974
reparent_dialog = memnew(ReparentDialog);
4975
add_child(reparent_dialog);
4976
reparent_dialog->connect("reparent", callable_mp(this, &SceneTreeDock::_node_reparent));
4977
4978
accept = memnew(AcceptDialog);
4979
add_child(accept);
4980
4981
set_process_shortcut_input(true);
4982
4983
delete_dialog = memnew(ConfirmationDialog);
4984
add_child(delete_dialog);
4985
delete_dialog->connect(SceneStringName(confirmed), callable_mp(this, &SceneTreeDock::_delete_confirm).bind(false));
4986
4987
VBoxContainer *vb = memnew(VBoxContainer);
4988
delete_dialog->add_child(vb);
4989
4990
delete_dialog_label = memnew(Label);
4991
delete_dialog_label->set_focus_mode(FOCUS_ACCESSIBILITY);
4992
vb->add_child(delete_dialog_label);
4993
4994
delete_tracks_checkbox = memnew(CheckBox(TTR("Delete Related Animation Tracks")));
4995
delete_tracks_checkbox->set_pressed(true);
4996
vb->add_child(delete_tracks_checkbox);
4997
4998
editable_instance_remove_dialog = memnew(ConfirmationDialog);
4999
add_child(editable_instance_remove_dialog);
5000
editable_instance_remove_dialog->connect(SceneStringName(confirmed), callable_mp(this, &SceneTreeDock::_toggle_editable_children_from_selection));
5001
5002
placeholder_editable_instance_remove_dialog = memnew(ConfirmationDialog);
5003
add_child(placeholder_editable_instance_remove_dialog);
5004
placeholder_editable_instance_remove_dialog->connect(SceneStringName(confirmed), callable_mp(this, &SceneTreeDock::_toggle_placeholder_from_selection));
5005
5006
new_scene_from_dialog = memnew(EditorFileDialog);
5007
new_scene_from_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
5008
new_scene_from_dialog->add_option(TTR("Reset Position"), Vector<String>(), true);
5009
new_scene_from_dialog->add_option(TTR("Reset Rotation"), Vector<String>(), false);
5010
new_scene_from_dialog->add_option(TTR("Reset Scale"), Vector<String>(), false);
5011
add_child(new_scene_from_dialog);
5012
new_scene_from_dialog->connect("file_selected", callable_mp(this, &SceneTreeDock::_new_scene_from));
5013
5014
menu = memnew(PopupMenu);
5015
add_child(menu);
5016
menu->connect(SceneStringName(id_pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(false));
5017
5018
menu_subresources = memnew(PopupMenu);
5019
menu_subresources->connect(SceneStringName(id_pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(false));
5020
menu->add_child(menu_subresources);
5021
5022
menu_properties = memnew(PopupMenu);
5023
add_child(menu_properties);
5024
menu_properties->connect(SceneStringName(id_pressed), callable_mp(this, &SceneTreeDock::_property_selected));
5025
5026
clear_inherit_confirm = memnew(ConfirmationDialog);
5027
clear_inherit_confirm->set_text(TTR("Clear Inheritance? (No Undo!)"));
5028
clear_inherit_confirm->set_ok_button_text(TTR("Clear"));
5029
add_child(clear_inherit_confirm);
5030
5031
set_process_input(true);
5032
set_process(true);
5033
5034
EDITOR_DEF("_use_favorites_root_selection", false);
5035
5036
Resource::_update_configuration_warning = _update_configuration_warning;
5037
}
5038
5039
SceneTreeDock::~SceneTreeDock() {
5040
singleton = nullptr;
5041
if (!node_clipboard.is_empty()) {
5042
_clear_clipboard();
5043
}
5044
}
5045
5046