summaryrefslogtreecommitdiffstats
path: root/editor/scene_tree_dock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/scene_tree_dock.cpp')
-rw-r--r--editor/scene_tree_dock.cpp354
1 files changed, 267 insertions, 87 deletions
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 26ddec6603..9209c26876 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -56,12 +56,11 @@
#include "editor/shader_create_dialog.h"
#include "editor/themes/editor_scale.h"
#include "scene/animation/animation_tree.h"
+#include "scene/audio/audio_stream_player.h"
#include "scene/gui/check_box.h"
-#include "scene/main/window.h"
#include "scene/property_utils.h"
#include "scene/resources/packed_scene.h"
#include "servers/display_server.h"
-#include "servers/rendering_server.h"
#include "modules/modules_enabled.gen.h" // For regex.
#ifdef MODULE_REGEX_ENABLED
@@ -76,6 +75,43 @@ void SceneTreeDock::_quick_open() {
instantiate_scenes(quick_open->get_selected_files(), scene_tree->get_selected());
}
+void SceneTreeDock::_inspect_hovered_node() {
+ scene_tree->set_selected(node_hovered_now);
+ scene_tree->set_marked(node_hovered_now);
+ Tree *tree = scene_tree->get_scene_tree();
+ TreeItem *item = tree->get_item_at_position(tree->get_local_mouse_position());
+ if (item) {
+ item->set_as_cursor(0);
+ }
+ InspectorDock::get_inspector_singleton()->edit(node_hovered_now);
+ InspectorDock::get_inspector_singleton()->propagate_notification(NOTIFICATION_DRAG_BEGIN); // Enable inspector drag preview after it updated.
+ InspectorDock::get_singleton()->update(node_hovered_now);
+ EditorNode::get_singleton()->hide_unused_editors();
+}
+
+void SceneTreeDock::_handle_hover_to_inspect() {
+ Tree *tree = scene_tree->get_scene_tree();
+ TreeItem *item = tree->get_item_at_position(tree->get_local_mouse_position());
+
+ if (item) {
+ const NodePath &np = item->get_metadata(0);
+ node_hovered_now = get_node_or_null(np);
+ if (node_hovered_previously != node_hovered_now) {
+ inspect_hovered_node_delay->start();
+ }
+ node_hovered_previously = node_hovered_now;
+ } else {
+ _reset_hovering_timer();
+ }
+}
+
+void SceneTreeDock::_reset_hovering_timer() {
+ if (!inspect_hovered_node_delay->is_stopped()) {
+ inspect_hovered_node_delay->stop();
+ }
+ node_hovered_previously = nullptr;
+}
+
void SceneTreeDock::input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
@@ -92,6 +128,17 @@ void SceneTreeDock::input(const Ref<InputEvent> &p_event) {
_push_item(pending_click_select);
pending_click_select = nullptr;
}
+
+ if (mb->is_released()) {
+ if (scene_tree->has_marked()) {
+ scene_tree->set_marked(nullptr);
+ }
+ _reset_hovering_timer();
+ }
+ }
+
+ if (tree_clicked && get_viewport()->gui_is_dragging()) {
+ _handle_hover_to_inspect();
}
}
@@ -208,8 +255,8 @@ void SceneTreeDock::instantiate_scenes(const Vector<String> &p_files, Node *p_pa
_perform_instantiate_scenes(p_files, parent, -1);
}
-void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, Node *parent, int p_pos) {
- ERR_FAIL_NULL(parent);
+void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, Node *p_parent, int p_pos) {
+ ERR_FAIL_NULL(p_parent);
Vector<Node *> instances;
@@ -256,25 +303,25 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Instantiate Scene(s)"));
+ undo_redo->create_action_for_history(TTRN("Instantiate Scene", "Instantiate Scenes", instances.size()), editor_data->get_current_edited_scene_history_id());
+ undo_redo->add_do_method(editor_selection, "clear");
for (int i = 0; i < instances.size(); i++) {
Node *instantiated_scene = instances[i];
- undo_redo->add_do_method(parent, "add_child", instantiated_scene, true);
+ undo_redo->add_do_method(p_parent, "add_child", instantiated_scene, true);
if (p_pos >= 0) {
- undo_redo->add_do_method(parent, "move_child", instantiated_scene, p_pos + i);
+ undo_redo->add_do_method(p_parent, "move_child", instantiated_scene, p_pos + i);
}
undo_redo->add_do_method(instantiated_scene, "set_owner", edited_scene);
- undo_redo->add_do_method(editor_selection, "clear");
undo_redo->add_do_method(editor_selection, "add_node", instantiated_scene);
undo_redo->add_do_reference(instantiated_scene);
- undo_redo->add_undo_method(parent, "remove_child", instantiated_scene);
+ undo_redo->add_undo_method(p_parent, "remove_child", instantiated_scene);
- String new_name = parent->validate_child_name(instantiated_scene);
+ String new_name = p_parent->validate_child_name(instantiated_scene);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- undo_redo->add_do_method(ed, "live_debug_instantiate_node", edited_scene->get_path_to(parent), p_files[i], new_name);
- undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).path_join(new_name)));
+ undo_redo->add_do_method(ed, "live_debug_instantiate_node", edited_scene->get_path_to(p_parent), p_files[i], new_name);
+ undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).path_join(new_name)));
}
undo_redo->commit_action();
@@ -284,6 +331,75 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N
}
}
+void SceneTreeDock::_perform_create_audio_stream_players(const Vector<String> &p_files, Node *p_parent, int p_pos) {
+ ERR_FAIL_NULL(p_parent);
+
+ StringName node_type = "AudioStreamPlayer";
+ if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
+ if (Object::cast_to<Node2D>(p_parent)) {
+ node_type = "AudioStreamPlayer2D";
+ } else if (Object::cast_to<Node3D>(p_parent)) {
+ node_type = "AudioStreamPlayer3D";
+ }
+ }
+
+ Vector<Node *> nodes;
+ bool error = false;
+
+ for (const String &path : p_files) {
+ Ref<AudioStream> stream = ResourceLoader::load(path);
+ if (stream.is_null()) {
+ current_option = -1;
+ accept->set_text(vformat(TTR("Error loading audio stream from %s"), path));
+ accept->popup_centered();
+ error = true;
+ break;
+ }
+
+ Node *player = Object::cast_to<Node>(ClassDB::instantiate(node_type));
+ player->set("stream", stream);
+
+ // Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others.
+ const String &node_name = Node::adjust_name_casing(path.get_file().get_basename());
+ if (!node_name.is_empty()) {
+ player->set_name(node_name);
+ }
+
+ nodes.push_back(player);
+ }
+
+ if (error) {
+ for (Node *node : nodes) {
+ memdelete(node);
+ }
+ return;
+ }
+
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action_for_history(TTRN("Create AudioStreamPlayer", "Create AudioStreamPlayers", nodes.size()), editor_data->get_current_edited_scene_history_id());
+ undo_redo->add_do_method(editor_selection, "clear");
+
+ for (int i = 0; i < nodes.size(); i++) {
+ Node *node = nodes[i];
+
+ undo_redo->add_do_method(p_parent, "add_child", node, true);
+ if (p_pos >= 0) {
+ undo_redo->add_do_method(p_parent, "move_child", node, p_pos + i);
+ }
+ undo_redo->add_do_method(node, "set_owner", edited_scene);
+ undo_redo->add_do_method(editor_selection, "add_node", node);
+ undo_redo->add_do_reference(node);
+ undo_redo->add_undo_method(p_parent, "remove_child", node);
+
+ String new_name = p_parent->validate_child_name(node);
+ EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
+ undo_redo->add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(p_parent), node->get_class(), new_name);
+ undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).path_join(new_name)));
+ }
+
+ undo_redo->commit_action();
+}
+
void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) {
// `move_child` + `get_index` doesn't really work for internal nodes.
ERR_FAIL_COND_MSG(base->get_internal_mode() != INTERNAL_MODE_DISABLED, "Trying to replace internal node, this is not supported.");
@@ -682,9 +798,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
undo_redo->create_action(TTR("Move Nodes in Parent"));
}
- for (int i = 0; i < selection.size(); i++) {
- Node *top_node = selection[i];
- Node *bottom_node = selection[selection.size() - 1 - i];
+ 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()) {
+ Node *top_node = top_E->get();
+ Node *bottom_node = bottom_E->get();
ERR_FAIL_NULL(top_node->get_parent());
ERR_FAIL_NULL(bottom_node->get_parent());
@@ -922,14 +1038,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
String msg;
if (remove_list.size() > 1) {
bool any_children = false;
- for (int i = 0; !any_children && i < remove_list.size(); i++) {
- any_children = remove_list[i]->get_child_count() > 0;
+ for (List<Node *>::ConstIterator itr = remove_list.begin(); !any_children && itr != remove_list.end(); ++itr) {
+ any_children = (*itr)->get_child_count() > 0;
}
msg = vformat(any_children ? TTR("Delete %d nodes and any children?") : TTR("Delete %d nodes?"), remove_list.size());
} else {
if (!p_confirm_override) {
- Node *node = remove_list[0];
+ Node *node = remove_list.front()->get();
if (node == editor_data->get_edited_scene_root()) {
msg = vformat(TTR("Delete the root node \"%s\"?"), node->get_name());
} else if (node->get_scene_file_path().is_empty() && node->get_child_count() > 0) {
@@ -1014,8 +1130,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Ref<PackedScene> sd = memnew(PackedScene);
ResourceSaver::get_recognized_extensions(sd, &extensions);
new_scene_from_dialog->clear_filters();
- for (int i = 0; i < extensions.size(); i++) {
- new_scene_from_dialog->add_filter("*." + extensions[i], extensions[i].to_upper());
+ for (const String &extension : extensions) {
+ new_scene_from_dialog->add_filter("*." + extension, extension.to_upper());
}
String existing;
@@ -1053,8 +1169,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
} break;
case TOOL_OPEN_DOCUMENTATION: {
List<Node *> selection = editor_selection->get_selected_node_list();
- for (int i = 0; i < selection.size(); i++) {
- ScriptEditor::get_singleton()->goto_help("class_name:" + selection[i]->get_class());
+ for (const Node *node : selection) {
+ ScriptEditor::get_singleton()->goto_help("class_name:" + node->get_class());
}
EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT);
} break;
@@ -1251,7 +1367,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
StringName name = node->get_name();
- if (new_unique_names.find(name) != -1 || get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(name)) != nullptr) {
+ if (new_unique_names.has(name) || get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(name)) != nullptr) {
cant_be_set_unique_names.push_back(name);
} else {
new_unique_nodes.push_back(node);
@@ -1424,7 +1540,7 @@ void SceneTreeDock::_notification(int p_what) {
node_shortcuts_toggle->set_tooltip_text(TTR("Toggle the display of favorite nodes."));
node_shortcuts_toggle->set_pressed(EDITOR_GET("_use_favorites_root_selection"));
node_shortcuts_toggle->set_anchors_and_offsets_preset(Control::PRESET_CENTER_RIGHT);
- node_shortcuts_toggle->connect("pressed", callable_mp(this, &SceneTreeDock::_update_create_root_dialog));
+ node_shortcuts_toggle->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_update_create_root_dialog));
top_row->add_child(node_shortcuts_toggle);
create_root_dialog->add_child(top_row);
@@ -1445,19 +1561,19 @@ void SceneTreeDock::_notification(int p_what) {
beginner_node_shortcuts->add_child(button_2d);
button_2d->set_text(TTR("2D Scene"));
button_2d->set_icon(get_editor_theme_icon(SNAME("Node2D")));
- button_2d->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_CREATE_2D_SCENE, false));
+ button_2d->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_CREATE_2D_SCENE, false));
button_3d = memnew(Button);
beginner_node_shortcuts->add_child(button_3d);
button_3d->set_text(TTR("3D Scene"));
button_3d->set_icon(get_editor_theme_icon(SNAME("Node3D")));
- button_3d->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_CREATE_3D_SCENE, false));
+ button_3d->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_CREATE_3D_SCENE, false));
button_ui = memnew(Button);
beginner_node_shortcuts->add_child(button_ui);
button_ui->set_text(TTR("User Interface"));
button_ui->set_icon(get_editor_theme_icon(SNAME("Control")));
- button_ui->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_CREATE_USER_INTERFACE, false));
+ button_ui->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_CREATE_USER_INTERFACE, false));
favorite_node_shortcuts = memnew(VBoxContainer);
node_shortcuts->add_child(favorite_node_shortcuts);
@@ -1466,13 +1582,13 @@ void SceneTreeDock::_notification(int p_what) {
node_shortcuts->add_child(button_custom);
button_custom->set_text(TTR("Other Node"));
button_custom->set_icon(get_editor_theme_icon(SNAME("Add")));
- button_custom->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_NEW, false));
+ button_custom->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_NEW, false));
button_clipboard = memnew(Button);
node_shortcuts->add_child(button_clipboard);
button_clipboard->set_text(TTR("Paste From Clipboard"));
button_clipboard->set_icon(get_editor_theme_icon(SNAME("ActionPaste")));
- button_clipboard->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_PASTE, false));
+ button_clipboard->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_PASTE, false));
_update_create_root_dialog();
} break;
@@ -1539,6 +1655,10 @@ void SceneTreeDock::_notification(int p_what) {
}
}
} break;
+
+ case NOTIFICATION_DRAG_END: {
+ _reset_hovering_timer();
+ } break;
}
}
@@ -2027,17 +2147,19 @@ bool SceneTreeDock::_validate_no_foreign() {
return false;
}
- // When edited_scene inherits from another one the root Node will be the parent Scene,
- // we don't want to consider that Node a foreign one otherwise we would not be able to
- // delete it.
- if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene == E) {
- continue;
- }
+ if (edited_scene->get_scene_inherited_state().is_valid()) {
+ // When edited_scene inherits from another one the root Node will be the parent Scene,
+ // we don't want to consider that Node a foreign one otherwise we would not be able to
+ // delete it.
+ if (edited_scene == E && current_option != TOOL_REPLACE) {
+ continue;
+ }
- if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene->get_scene_inherited_state()->find_node_by_path(edited_scene->get_path_to(E)) >= 0) {
- accept->set_text(TTR("Can't operate on nodes the current scene inherits from!"));
- accept->popup_centered();
- return false;
+ if (edited_scene == E || edited_scene->get_scene_inherited_state()->find_node_by_path(edited_scene->get_path_to(E)) >= 0) {
+ accept->set_text(TTR("Can't operate on nodes the current scene inherits from!"));
+ accept->popup_centered();
+ return false;
+ }
}
}
@@ -2562,7 +2684,7 @@ void SceneTreeDock::_update_script_button() {
button_create_script->hide();
button_detach_script->hide();
} else if (editor_selection->get_selection().size() == 1) {
- Node *n = editor_selection->get_selected_node_list()[0];
+ Node *n = editor_selection->get_selected_node_list().front()->get();
if (n->get_script().is_null()) {
button_create_script->show();
button_detach_script->hide();
@@ -2813,21 +2935,24 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node) {
void SceneTreeDock::_replace_node(Node *p_node, Node *p_by_node, bool p_keep_properties, bool p_remove_old) {
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.");
- Node *n = p_node;
+ Node *oldnode = p_node;
Node *newnode = p_by_node;
if (p_keep_properties) {
- Node *default_oldnode = Object::cast_to<Node>(ClassDB::instantiate(n->get_class()));
+ Node *default_oldnode = Object::cast_to<Node>(ClassDB::instantiate(oldnode->get_class()));
+
List<PropertyInfo> pinfo;
- n->get_property_list(&pinfo);
+ oldnode->get_property_list(&pinfo);
for (const PropertyInfo &E : pinfo) {
if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
continue;
}
- if (default_oldnode->get(E.name) != n->get(E.name)) {
- newnode->set(E.name, n->get(E.name));
+ bool valid;
+ const Variant &default_val = default_oldnode->get(E.name, &valid);
+ if (!valid || default_val != oldnode->get(E.name)) {
+ newnode->set(E.name, oldnode->get(E.name));
}
}
@@ -2839,10 +2964,10 @@ void SceneTreeDock::_replace_node(Node *p_node, Node *p_by_node, bool p_keep_pro
//reconnect signals
List<MethodInfo> sl;
- n->get_signal_list(&sl);
+ oldnode->get_signal_list(&sl);
for (const MethodInfo &E : sl) {
List<Object::Connection> cl;
- n->get_signal_connection_list(E.name, &cl);
+ oldnode->get_signal_connection_list(E.name, &cl);
for (const Object::Connection &c : cl) {
if (!(c.flags & Object::CONNECT_PERSIST)) {
@@ -2852,15 +2977,28 @@ void SceneTreeDock::_replace_node(Node *p_node, Node *p_by_node, bool p_keep_pro
}
}
- String newname = n->get_name();
+ // HACK: Remember size of anchored control.
+ Control *old_control = Object::cast_to<Control>(oldnode);
+ Size2 size;
+ if (old_control) {
+ size = old_control->get_size();
+ }
+
+ String newname = oldnode->get_name();
List<Node *> to_erase;
- for (int i = 0; i < n->get_child_count(); i++) {
- if (n->get_child(i)->get_owner() == nullptr && n->is_owned_by_parent()) {
- to_erase.push_back(n->get_child(i));
+ for (int i = 0; i < oldnode->get_child_count(); i++) {
+ if (oldnode->get_child(i)->get_owner() == nullptr && oldnode->is_owned_by_parent()) {
+ to_erase.push_back(oldnode->get_child(i));
}
}
- n->replace_by(newnode, true);
+ oldnode->replace_by(newnode, true);
+
+ // Re-apply size of anchored control.
+ Control *new_control = Object::cast_to<Control>(newnode);
+ if (old_control && new_control) {
+ new_control->set_size(size);
+ }
//small hack to make collisionshapes and other kind of nodes to work
for (int i = 0; i < newnode->get_child_count(); i++) {
@@ -2876,7 +3014,7 @@ void SceneTreeDock::_replace_node(Node *p_node, Node *p_by_node, bool p_keep_pro
_push_item(newnode);
if (p_remove_old) {
- memdelete(n);
+ memdelete(oldnode);
while (to_erase.front()) {
memdelete(to_erase.front()->get());
@@ -2966,6 +3104,29 @@ void SceneTreeDock::set_edited_scene(Node *p_scene) {
edited_scene = p_scene;
}
+static bool _is_same_selection(const Vector<Node *> &p_first, const List<Node *> &p_second) {
+ if (p_first.size() != p_second.size()) {
+ return false;
+ }
+ for (Node *node : p_second) {
+ if (!p_first.has(node)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void SceneTreeDock::set_selection(const Vector<Node *> &p_nodes) {
+ // If the nodes selected are the same independently of order then return early.
+ if (_is_same_selection(p_nodes, editor_selection->get_full_selected_node_list())) {
+ return;
+ }
+ editor_selection->clear();
+ for (Node *node : p_nodes) {
+ editor_selection->add_node(node);
+ }
+}
+
void SceneTreeDock::set_selected(Node *p_node, bool p_emit_selected) {
scene_tree->set_selected(p_node, p_emit_selected);
}
@@ -3121,15 +3282,13 @@ void SceneTreeDock::_normalize_drop(Node *&to_node, int &to_pos, int p_type) {
void SceneTreeDock::_files_dropped(const Vector<String> &p_files, NodePath p_to, int p_type) {
Node *node = get_node(p_to);
ERR_FAIL_NULL(node);
+ ERR_FAIL_COND(p_files.is_empty());
- if (scene_tree->get_scene_tree()->get_drop_mode_flags() & Tree::DROP_MODE_INBETWEEN) {
- // Dropped PackedScene, instance it.
- int to_pos = -1;
- _normalize_drop(node, to_pos, p_type);
- _perform_instantiate_scenes(p_files, node, to_pos);
- } else {
- const String &res_path = p_files[0];
- StringName res_type = EditorFileSystem::get_singleton()->get_file_type(res_path);
+ const String &res_path = p_files[0];
+ const StringName res_type = EditorFileSystem::get_singleton()->get_file_type(res_path);
+
+ // Dropping as property when possible.
+ if (p_type == 0 && p_files.size() == 1) {
List<String> valid_properties;
List<PropertyInfo> pinfo;
@@ -3163,10 +3322,22 @@ void SceneTreeDock::_files_dropped(const Vector<String> &p_files, NodePath p_to,
menu_properties->reset_size();
menu_properties->set_position(get_screen_position() + get_local_mouse_position());
menu_properties->popup();
- } else if (!valid_properties.is_empty()) {
- _perform_property_drop(node, valid_properties[0], ResourceLoader::load(res_path));
+ return;
+ }
+ if (!valid_properties.is_empty()) {
+ _perform_property_drop(node, valid_properties.front()->get(), ResourceLoader::load(res_path));
+ return;
}
}
+
+ // Either instantiate scenes or create AudioStreamPlayers.
+ int to_pos = -1;
+ _normalize_drop(node, to_pos, p_type);
+ if (ClassDB::is_parent_class(res_type, "PackedScene")) {
+ _perform_instantiate_scenes(p_files, node, to_pos);
+ } else if (ClassDB::is_parent_class(res_type, "AudioStream")) {
+ _perform_create_audio_stream_players(p_files, node, to_pos);
+ }
}
void SceneTreeDock::_script_dropped(const String &p_file, NodePath p_to) {
@@ -3312,13 +3483,13 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
Ref<Script> existing_script;
bool existing_script_removable = true;
if (selection.size() == 1) {
- Node *selected = selection[0];
+ Node *selected = selection.front()->get();
if (profile_allow_editing) {
subresources.clear();
menu_subresources->clear();
menu_subresources->reset_size();
- _add_children_to_popup(selection.front()->get(), 0);
+ _add_children_to_popup(selected, 0);
if (menu->get_item_count() > 0) {
menu->add_separator();
}
@@ -3391,6 +3562,13 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
can_replace = false;
break;
}
+
+ if (edited_scene->get_scene_inherited_state().is_valid()) {
+ if (E == edited_scene || edited_scene->get_scene_inherited_state()->find_node_by_path(edited_scene->get_path_to(E)) >= 0) {
+ can_replace = false;
+ break;
+ }
+ }
}
if (can_replace) {
@@ -3435,17 +3613,17 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
if (menu->get_item_index(TOOL_COPY_NODE_PATH) == -1) {
menu->add_separator();
}
- Node *node = full_selection[0];
+ Node *node = full_selection.front()->get();
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("SceneUniqueName")), ED_GET_SHORTCUT("scene_tree/toggle_unique_name"), TOOL_TOGGLE_SCENE_UNIQUE_NAME);
menu->set_item_text(menu->get_item_index(TOOL_TOGGLE_SCENE_UNIQUE_NAME), node->is_unique_name_in_owner() ? TTR("Revoke Unique Name") : TTR("Access as Unique Name"));
}
}
if (selection.size() == 1) {
- bool is_external = (!selection[0]->get_scene_file_path().is_empty());
+ bool is_external = (!selection.front()->get()->get_scene_file_path().is_empty());
if (is_external) {
- bool is_inherited = selection[0]->get_scene_inherited_state() != nullptr;
- bool is_top_level = selection[0]->get_owner() == nullptr;
+ bool is_inherited = selection.front()->get()->get_scene_inherited_state() != nullptr;
+ bool is_top_level = selection.front()->get()->get_owner() == nullptr;
if (is_inherited && is_top_level) {
menu->add_separator();
if (profile_allow_editing) {
@@ -3454,8 +3632,8 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
menu->add_icon_item(get_editor_theme_icon(SNAME("Load")), TTR("Open in Editor"), TOOL_SCENE_OPEN_INHERITED);
} else if (!is_top_level) {
menu->add_separator();
- bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(selection[0]);
- bool placeholder = selection[0]->get_scene_instance_load_placeholder();
+ bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(selection.front()->get());
+ bool placeholder = selection.front()->get()->get_scene_instance_load_placeholder();
if (profile_allow_editing) {
menu->add_check_item(TTR("Editable Children"), TOOL_SCENE_EDITABLE_CHILDREN);
menu->set_item_shortcut(-1, ED_GET_SHORTCUT("scene_tree/toggle_editable_children"));
@@ -3481,7 +3659,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
#endif // MODULE_REGEX_ENABLED
menu->add_separator();
- if (full_selection.size() == 1 && !selection[0]->get_scene_file_path().is_empty()) {
+ if (full_selection.size() == 1 && !selection.front()->get()->get_scene_file_path().is_empty()) {
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ShowInFileSystem")), ED_GET_SHORTCUT("scene_tree/show_in_file_system"), TOOL_SHOW_IN_FILE_SYSTEM);
}
@@ -3489,7 +3667,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
if (profile_allow_editing) {
menu->add_separator();
- menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Remove")), ED_SHORTCUT("scene_tree/delete", TTR("Delete Node(s)"), Key::KEY_DELETE), TOOL_ERASE);
+ menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Remove")), ED_GET_SHORTCUT("scene_tree/delete"), TOOL_ERASE);
}
menu->reset_size();
menu->set_position(p_menu_pos);
@@ -3568,10 +3746,7 @@ void SceneTreeDock::_filter_option_selected(int p_option) {
void SceneTreeDock::_append_filter_options_to(PopupMenu *p_menu, bool p_include_separator) {
if (p_include_separator) {
- p_menu->add_separator();
-
- p_menu->set_item_text(-1, TTR("Filters"));
- p_menu->set_item_indent(-1, -2);
+ p_menu->add_separator(TTR("Filters"));
}
p_menu->add_item(TTR("Filter by Type"), FILTER_BY_TYPE);
@@ -3916,7 +4091,7 @@ void SceneTreeDock::_update_create_root_dialog() {
name = ScriptServer::get_global_class_native_base(name);
}
button->set_icon(EditorNode::get_singleton()->get_class_icon(name));
- button->connect("pressed", callable_mp(this, &SceneTreeDock::_favorite_root_selected).bind(l));
+ button->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_favorite_root_selected).bind(l));
}
}
}
@@ -4200,14 +4375,14 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
button_add = memnew(Button);
button_add->set_theme_type_variation("FlatMenuButton");
- button_add->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_NEW, false));
+ button_add->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_NEW, false));
button_add->set_tooltip_text(TTR("Add/Create a New Node."));
button_add->set_shortcut(ED_GET_SHORTCUT("scene_tree/add_child_node"));
filter_hbc->add_child(button_add);
button_instance = memnew(Button);
button_instance->set_theme_type_variation("FlatMenuButton");
- button_instance->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_INSTANTIATE, false));
+ button_instance->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_INSTANTIATE, false));
button_instance->set_tooltip_text(TTR("Instantiate a scene file as a Node. Creates an inherited scene if no root node exists."));
button_instance->set_shortcut(ED_GET_SHORTCUT("scene_tree/instantiate_scene"));
filter_hbc->add_child(button_instance);
@@ -4221,7 +4396,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
filter_hbc->add_child(filter);
filter->add_theme_constant_override("minimum_character_width", 0);
filter->connect("text_changed", callable_mp(this, &SceneTreeDock::_filter_changed));
- filter->connect("gui_input", callable_mp(this, &SceneTreeDock::_filter_gui_input));
+ filter->connect(SceneStringName(gui_input), callable_mp(this, &SceneTreeDock::_filter_gui_input));
filter->get_menu()->connect("id_pressed", callable_mp(this, &SceneTreeDock::_filter_option_selected));
_append_filter_options_to(filter->get_menu());
@@ -4232,7 +4407,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
button_create_script = memnew(Button);
button_create_script->set_theme_type_variation("FlatMenuButton");
- button_create_script->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_ATTACH_SCRIPT, false));
+ button_create_script->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_ATTACH_SCRIPT, false));
button_create_script->set_tooltip_text(TTR("Attach a new or existing script to the selected node."));
button_create_script->set_shortcut(ED_GET_SHORTCUT("scene_tree/attach_script"));
filter_hbc->add_child(button_create_script);
@@ -4240,7 +4415,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
button_detach_script = memnew(Button);
button_detach_script->set_theme_type_variation("FlatMenuButton");
- button_detach_script->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_DETACH_SCRIPT, false));
+ button_detach_script->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_DETACH_SCRIPT, false));
button_detach_script->set_tooltip_text(TTR("Detach the script from the selected node."));
button_detach_script->set_shortcut(ED_GET_SHORTCUT("scene_tree/detach_script"));
filter_hbc->add_child(button_detach_script);
@@ -4266,7 +4441,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
edit_remote->set_toggle_mode(true);
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."));
button_hb->add_child(edit_remote);
- edit_remote->connect("pressed", callable_mp(this, &SceneTreeDock::_remote_tree_selected));
+ edit_remote->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_remote_tree_selected));
edit_local = memnew(Button);
edit_local->set_theme_type_variation("FlatButton");
@@ -4275,7 +4450,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
edit_local->set_toggle_mode(true);
edit_local->set_pressed(true);
button_hb->add_child(edit_local);
- edit_local->connect("pressed", callable_mp(this, &SceneTreeDock::_local_tree_selected));
+ edit_local->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_local_tree_selected));
remote_tree = nullptr;
button_hb->hide();
@@ -4291,7 +4466,6 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
scene_tree->set_v_size_flags(SIZE_EXPAND | SIZE_FILL);
scene_tree->connect("rmb_pressed", callable_mp(this, &SceneTreeDock::_tree_rmb));
- scene_tree->connect("node_selected", callable_mp(this, &SceneTreeDock::_node_selected), CONNECT_DEFERRED);
scene_tree->connect("node_renamed", callable_mp(this, &SceneTreeDock::_node_renamed), CONNECT_DEFERRED);
scene_tree->connect("node_prerename", callable_mp(this, &SceneTreeDock::_node_prerenamed));
scene_tree->connect("open", callable_mp(this, &SceneTreeDock::_load_request));
@@ -4300,8 +4474,9 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
scene_tree->connect("files_dropped", callable_mp(this, &SceneTreeDock::_files_dropped));
scene_tree->connect("script_dropped", callable_mp(this, &SceneTreeDock::_script_dropped));
scene_tree->connect("nodes_dragged", callable_mp(this, &SceneTreeDock::_nodes_drag_begin));
+ scene_tree->connect(SceneStringName(mouse_exited), callable_mp(this, &SceneTreeDock::_reset_hovering_timer));
- scene_tree->get_scene_tree()->connect("gui_input", callable_mp(this, &SceneTreeDock::_scene_tree_gui_input));
+ scene_tree->get_scene_tree()->connect(SceneStringName(gui_input), callable_mp(this, &SceneTreeDock::_scene_tree_gui_input));
scene_tree->get_scene_tree()->connect("item_icon_double_clicked", callable_mp(this, &SceneTreeDock::_focus_node));
editor_selection->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed));
@@ -4309,6 +4484,11 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
scene_tree->set_as_scene_tree_dock();
scene_tree->set_editor_selection(editor_selection);
+ inspect_hovered_node_delay = memnew(Timer);
+ inspect_hovered_node_delay->connect("timeout", callable_mp(this, &SceneTreeDock::_inspect_hovered_node));
+ inspect_hovered_node_delay->set_one_shot(true);
+ add_child(inspect_hovered_node_delay);
+
create_dialog = memnew(CreateDialog);
create_dialog->set_base_type("Node");
add_child(create_dialog);