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