diff options
Diffstat (limited to 'editor/scene_tree_dock.cpp')
-rw-r--r-- | editor/scene_tree_dock.cpp | 182 |
1 files changed, 145 insertions, 37 deletions
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 6f0a8bc909..9209c26876 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -56,6 +56,7 @@ #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/property_utils.h" #include "scene/resources/packed_scene.h" @@ -254,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; @@ -302,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(); @@ -330,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."); @@ -1470,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); @@ -1491,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); @@ -1512,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; @@ -2907,6 +2977,13 @@ void SceneTreeDock::_replace_node(Node *p_node, Node *p_by_node, bool p_keep_pro } } + // 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; @@ -2917,6 +2994,12 @@ void SceneTreeDock::_replace_node(Node *p_node, Node *p_by_node, bool p_keep_pro } 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++) { Node *c = newnode->get_child(i); @@ -3021,7 +3104,23 @@ 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); @@ -3183,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; @@ -3225,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()) { + 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) { @@ -3558,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); @@ -3982,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)); } } } @@ -4266,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); @@ -4287,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()); @@ -4298,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); @@ -4306,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); @@ -4332,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"); @@ -4341,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(); @@ -4357,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)); @@ -4366,9 +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("mouse_exited", callable_mp(this, &SceneTreeDock::_reset_hovering_timer)); + 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)); |