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