diff options
Diffstat (limited to 'editor/scene_tree_dock.cpp')
-rw-r--r-- | editor/scene_tree_dock.cpp | 839 |
1 files changed, 509 insertions, 330 deletions
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 349e05b47b..4bc0905163 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -45,6 +45,7 @@ #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h" +#include "editor/shader_create_dialog.h" #include "scene/main/window.h" #include "scene/resources/packed_scene.h" #include "servers/display_server.h" @@ -58,10 +59,10 @@ void SceneTreeDock::_nodes_drag_begin() { } void SceneTreeDock::_quick_open() { - instance_scenes(quick_open->get_selected_files(), scene_tree->get_selected()); + instantiate_scenes(quick_open->get_selected_files(), scene_tree->get_selected()); } -void SceneTreeDock::_input(Ref<InputEvent> p_event) { +void SceneTreeDock::input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); Ref<InputEventMouseButton> mb = p_event; @@ -71,7 +72,7 @@ void SceneTreeDock::_input(Ref<InputEvent> p_event) { } } -void SceneTreeDock::_unhandled_key_input(Ref<InputEvent> p_event) { +void SceneTreeDock::unhandled_key_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); if (get_focus_owner() && get_focus_owner()->is_text_field()) { @@ -82,14 +83,16 @@ void SceneTreeDock::_unhandled_key_input(Ref<InputEvent> p_event) { return; } - if (ED_IS_SHORTCUT("scene_tree/batch_rename", p_event)) { - _tool_selected(TOOL_BATCH_RENAME); - } else if (ED_IS_SHORTCUT("scene_tree/rename", p_event)) { + if (ED_IS_SHORTCUT("scene_tree/rename", p_event)) { _tool_selected(TOOL_RENAME); +#ifdef MODULE_REGEX_ENABLED + } else if (ED_IS_SHORTCUT("scene_tree/batch_rename", p_event)) { + _tool_selected(TOOL_BATCH_RENAME); +#endif // MODULE_REGEX_ENABLED } else if (ED_IS_SHORTCUT("scene_tree/add_child_node", p_event)) { _tool_selected(TOOL_NEW); } else if (ED_IS_SHORTCUT("scene_tree/instance_scene", p_event)) { - _tool_selected(TOOL_INSTANCE); + _tool_selected(TOOL_INSTANTIATE); } else if (ED_IS_SHORTCUT("scene_tree/expand_collapse_all", p_event)) { _tool_selected(TOOL_EXPAND_COLLAPSE); } else if (ED_IS_SHORTCUT("scene_tree/cut_node", p_event)) { @@ -128,13 +131,13 @@ void SceneTreeDock::_unhandled_key_input(Ref<InputEvent> p_event) { accept_event(); } -void SceneTreeDock::instance(const String &p_file) { +void SceneTreeDock::instantiate(const String &p_file) { Vector<String> scenes; scenes.push_back(p_file); - instance_scenes(scenes, scene_tree->get_selected()); + instantiate_scenes(scenes, scene_tree->get_selected()); } -void SceneTreeDock::instance_scenes(const Vector<String> &p_files, Node *p_parent) { +void SceneTreeDock::instantiate_scenes(const Vector<String> &p_files, Node *p_parent) { Node *parent = p_parent; if (!parent) { @@ -147,18 +150,18 @@ void SceneTreeDock::instance_scenes(const Vector<String> &p_files, Node *p_paren if (!parent) { if (p_files.size() == 1) { - accept->set_text(TTR("No parent to instance a child at.")); + accept->set_text(TTR("No parent to instantiate a child at.")); } else { - accept->set_text(TTR("No parent to instance the scenes at.")); + accept->set_text(TTR("No parent to instantiate the scenes at.")); } accept->popup_centered(); return; }; - _perform_instance_scenes(p_files, parent, -1); + _perform_instantiate_scenes(p_files, parent, -1); } -void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node *parent, int p_pos) { +void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, Node *parent, int p_pos) { ERR_FAIL_COND(!parent); Vector<Node *> instances; @@ -175,8 +178,8 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node break; } - Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); - if (!instanced_scene) { + Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); + if (!instantiated_scene) { current_option = -1; accept->set_text(vformat(TTR("Error instancing scene from %s"), p_files[i])); accept->popup_centered(); @@ -185,7 +188,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node } if (edited_scene->get_filename() != "") { - if (_cyclical_dependency_exists(edited_scene->get_filename(), instanced_scene)) { + if (_cyclical_dependency_exists(edited_scene->get_filename(), instantiated_scene)) { accept->set_text(vformat(TTR("Cannot instance the scene '%s' because the current scene exists within one of its nodes."), p_files[i])); accept->popup_centered(); error = true; @@ -193,9 +196,9 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node } } - instanced_scene->set_filename(ProjectSettings::get_singleton()->localize_path(p_files[i])); + instantiated_scene->set_filename(ProjectSettings::get_singleton()->localize_path(p_files[i])); - instances.push_back(instanced_scene); + instances.push_back(instantiated_scene); } if (error) { @@ -208,19 +211,19 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node editor_data->get_undo_redo().create_action(TTR("Instance Scene(s)")); for (int i = 0; i < instances.size(); i++) { - Node *instanced_scene = instances[i]; + Node *instantiated_scene = instances[i]; - editor_data->get_undo_redo().add_do_method(parent, "add_child", instanced_scene); + editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene); if (p_pos >= 0) { - editor_data->get_undo_redo().add_do_method(parent, "move_child", instanced_scene, p_pos + i); + editor_data->get_undo_redo().add_do_method(parent, "move_child", instantiated_scene, p_pos + i); } - editor_data->get_undo_redo().add_do_method(instanced_scene, "set_owner", edited_scene); + editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", edited_scene); editor_data->get_undo_redo().add_do_method(editor_selection, "clear"); - editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", instanced_scene); - editor_data->get_undo_redo().add_do_reference(instanced_scene); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instanced_scene); + editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", instantiated_scene); + editor_data->get_undo_redo().add_do_reference(instantiated_scene); + editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene); - String new_name = parent->validate_child_name(instanced_scene); + String new_name = parent->validate_child_name(instantiated_scene); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), p_files[i], new_name); editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(new_name))); @@ -229,7 +232,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node editor_data->get_undo_redo().commit_action(); editor->push_item(instances[instances.size() - 1]); for (int i = 0; i < instances.size(); i++) { - emit_signal("node_created", instances[i]); + emit_signal(SNAME("node_created"), instances[i]); } } @@ -241,8 +244,8 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) return; } - Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); - if (!instanced_scene) { + Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); + if (!instantiated_scene) { accept->set_text(vformat(TTR("Error instancing scene from %s"), p_file)); accept->popup_centered(); return; @@ -254,29 +257,29 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) Node *parent = base->get_parent(); int pos = base->get_index(); undo_redo->add_do_method(parent, "remove_child", base); - undo_redo->add_undo_method(parent, "remove_child", instanced_scene); - undo_redo->add_do_method(parent, "add_child", instanced_scene); + undo_redo->add_undo_method(parent, "remove_child", instantiated_scene); + undo_redo->add_do_method(parent, "add_child", instantiated_scene); undo_redo->add_undo_method(parent, "add_child", base); - undo_redo->add_do_method(parent, "move_child", instanced_scene, pos); + undo_redo->add_do_method(parent, "move_child", instantiated_scene, pos); undo_redo->add_undo_method(parent, "move_child", base, pos); List<Node *> owned; base->get_owned_by(base->get_owner(), &owned); Array owners; - for (List<Node *>::Element *F = owned.front(); F; F = F->next()) { - owners.push_back(F->get()); + for (Node *F : owned) { + owners.push_back(F); } - undo_redo->add_do_method(instanced_scene, "set_owner", edited_scene); + undo_redo->add_do_method(instantiated_scene, "set_owner", edited_scene); undo_redo->add_undo_method(this, "_set_owners", edited_scene, owners); undo_redo->add_do_method(editor_selection, "clear"); undo_redo->add_undo_method(editor_selection, "clear"); - undo_redo->add_do_method(editor_selection, "add_node", instanced_scene); + undo_redo->add_do_method(editor_selection, "add_node", instantiated_scene); undo_redo->add_undo_method(editor_selection, "add_node", base); - undo_redo->add_do_property(scene_tree, "set_selected", instanced_scene); + undo_redo->add_do_property(scene_tree, "set_selected", instantiated_scene); undo_redo->add_undo_property(scene_tree, "set_selected", base); - undo_redo->add_do_reference(instanced_scene); + undo_redo->add_do_reference(instantiated_scene); undo_redo->add_undo_reference(base); undo_redo->commit_action(); } @@ -313,7 +316,7 @@ bool SceneTreeDock::_track_inherit(const String &p_target_scene_path, Node *p_de String path = ss->get_path(); Ref<PackedScene> data = ResourceLoader::load(path); if (data.is_valid()) { - p = data->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); + p = data->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); if (!p) { continue; } @@ -335,6 +338,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { current_option = p_tool; switch (p_tool) { +#ifdef MODULE_REGEX_ENABLED case TOOL_BATCH_RENAME: { if (!profile_allow_editing) { break; @@ -343,6 +347,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { rename_dialog->popup_centered(); } } break; +#endif // MODULE_REGEX_ENABLED case TOOL_RENAME: { if (!profile_allow_editing) { break; @@ -359,7 +364,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { break; } - if (reset_create_dialog) { + if (reset_create_dialog && !p_confirm_override) { create_dialog->set_base_type("Node"); reset_create_dialog = false; } @@ -385,10 +390,10 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { create_dialog->popup_create(true); if (!p_confirm_override) { - emit_signal("add_node_used"); + emit_signal(SNAME("add_node_used")); } } break; - case TOOL_INSTANCE: { + case TOOL_INSTANTIATE: { if (!profile_allow_editing) { break; } @@ -400,9 +405,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } quick_open->popup_dialog("PackedScene", true); - quick_open->set_title(TTR("Instance Child Scene")); + quick_open->set_title(TTR("Instantiate Child Scene")); if (!p_confirm_override) { - emit_signal("add_node_used"); + emit_signal(SNAME("add_node_used")); } } break; case TOOL_EXPAND_COLLAPSE: { @@ -441,8 +446,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { selection.sort_custom<Node::Comparator>(); - for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - Node *node = E->get(); + for (Node *node : selection) { Map<const Node *, Node *> duplimap; Node *dup = node->duplicate_from_editor(duplimap); @@ -462,8 +466,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { bool has_cycle = false; if (edited_scene->get_filename() != String()) { - for (List<Node *>::Element *E = node_clipboard.front(); E; E = E->next()) { - if (edited_scene->get_filename() == E->get()->get_filename()) { + for (Node *E : node_clipboard) { + if (edited_scene->get_filename() == E->get_filename()) { has_cycle = true; break; } @@ -496,16 +500,15 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (target_scene != clipboard_source_scene) { if (!clipboard_resource_remap.has(target_scene)) { Map<RES, RES> remap; - for (List<Node *>::Element *E = node_clipboard.front(); E; E = E->next()) { - _create_remap_for_node(E->get(), remap); + for (Node *E : node_clipboard) { + _create_remap_for_node(E, remap); } clipboard_resource_remap[target_scene] = remap; } resource_remap = clipboard_resource_remap[target_scene]; } - for (List<Node *>::Element *E = node_clipboard.front(); E; E = E->next()) { - Node *node = E->get(); + for (Node *node : node_clipboard) { Map<const Node *, Node *> duplimap; Node *dup = node->duplicate_from_editor(duplimap, resource_remap); @@ -544,6 +547,11 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { break; } + if (reset_create_dialog) { + create_dialog->set_base_type("Node"); + reset_create_dialog = false; + } + Node *selected = scene_tree->get_selected(); if (!selected && !editor_selection->get_selected_node_list().is_empty()) { selected = editor_selection->get_selected_node_list().front()->get(); @@ -622,8 +630,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { int lowest_id = common_parent->get_child_count() - 1; int highest_id = 0; - for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - int index = E->get()->get_index(); + for (Node *E : selection) { + int index = E->get_index(); if (index > highest_id) { highest_id = index; @@ -632,7 +640,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { lowest_id = index; } - if (E->get()->get_parent() != common_parent) { + if (E->get_parent() != common_parent) { common_parent = nullptr; } } @@ -699,8 +707,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { Node *add_below_node = selection.back()->get(); - for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - Node *node = E->get(); + for (Node *node : selection) { Node *parent = node->get_parent(); List<Node *> owned; @@ -719,11 +726,11 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { editor_data->get_undo_redo().add_do_method(add_below_node, "add_sibling", dup); - for (List<Node *>::Element *F = owned.front(); F; F = F->next()) { - if (!duplimap.has(F->get())) { + for (Node *F : owned) { + if (!duplimap.has(F)) { continue; } - Node *d = duplimap[F->get()]; + Node *d = duplimap[F]; editor_data->get_undo_redo().add_do_method(d, "set_owner", node->get_owner()); } editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", dup); @@ -766,8 +773,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { List<Node *> nodes = editor_selection->get_selected_node_list(); Set<Node *> nodeset; - for (List<Node *>::Element *E = nodes.front(); E; E = E->next()) { - nodeset.insert(E->get()); + for (Node *E : nodes) { + nodeset.insert(E); } reparent_dialog->set_current(nodeset); reparent_dialog->popup_centered_clamped(Size2(350, 700) * EDSCALE); @@ -881,7 +888,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (node == editor_data->get_edited_scene_root()) { msg = vformat(TTR("Delete the root node \"%s\"?"), node->get_name()); } else if (node->get_filename() == "" && node->get_child_count() > 0) { - // Display this message only for non-instanced scenes + // Display this message only for non-instantiated scenes msg = vformat(TTR("Delete node \"%s\" and its children?"), node->get_name()); } else { msg = vformat(TTR("Delete node \"%s\"?"), node->get_name()); @@ -922,13 +929,13 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { Node *tocopy = selection.front()->get(); if (tocopy == scene) { - accept->set_text(TTR("Can't save the root node branch as an instanced 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.")); + 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.")); accept->popup_centered(); break; } if (tocopy != editor_data->get_edited_scene_root() && tocopy->get_filename() != "") { - accept->set_text(TTR("Can't save the branch of an already instanced scene.\nTo create a variation of a scene, you can make an inherited scene based on the instanced scene using Scene > New Inherited Scene... instead.")); + 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.")); accept->popup_centered(); break; } @@ -1057,7 +1064,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (e) { Node *node = e->get(); if (node) { - scene_tree->emit_signal("open", node->get_filename()); + scene_tree->emit_signal(SNAME("open"), node->get_filename()); } } } break; @@ -1090,7 +1097,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (e) { Node *node = e->get(); if (node && node->get_scene_inherited_state().is_valid()) { - scene_tree->emit_signal("open", node->get_scene_inherited_state()->get_path()); + scene_tree->emit_signal(SNAME("open"), node->get_scene_inherited_state()->get_path()); } } } break; @@ -1103,14 +1110,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (TOOL_CREATE_FAVORITE == p_tool) { String name = selected_favorite_root.get_slicec(' ', 0); if (ScriptServer::is_global_class(name)) { - new_node = Object::cast_to<Node>(ClassDB::instance(ScriptServer::get_global_class_native_base(name))); + new_node = Object::cast_to<Node>(ClassDB::instantiate(ScriptServer::get_global_class_native_base(name))); Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(name), "Script"); if (new_node && script.is_valid()) { new_node->set_script(script); new_node->set_name(name); } } else { - new_node = Object::cast_to<Node>(ClassDB::instance(selected_favorite_root)); + new_node = Object::cast_to<Node>(ClassDB::instantiate(selected_favorite_root)); } if (!new_node) { @@ -1134,17 +1141,13 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } } - editor_data->get_undo_redo().create_action(TTR("New Scene Root")); - editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", new_node); - editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree"); - editor_data->get_undo_redo().add_do_reference(new_node); - editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)nullptr); - editor_data->get_undo_redo().commit_action(); + add_root_node(new_node); editor->edit_node(new_node); editor_selection->clear(); editor_selection->add_node(new_node); + scene_tree->get_scene_tree()->grab_focus(); } break; default: { @@ -1162,6 +1165,28 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } } +void SceneTreeDock::_property_selected(int p_idx) { + ERR_FAIL_NULL(property_drop_node); + _perform_property_drop(property_drop_node, menu_properties->get_item_metadata(p_idx), ResourceLoader::load(resource_drop_path)); + property_drop_node = nullptr; +} + +void SceneTreeDock::_perform_property_drop(Node *p_node, String p_property, RES p_res) { + editor_data->get_undo_redo().create_action(vformat(TTR("Set %s"), p_property)); + editor_data->get_undo_redo().add_do_property(p_node, p_property, p_res); + editor_data->get_undo_redo().add_undo_property(p_node, p_property, p_node->get(p_property)); + editor_data->get_undo_redo().commit_action(); +} + +void SceneTreeDock::add_root_node(Node *p_node) { + editor_data->get_undo_redo().create_action(TTR("New Scene Root")); + editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", p_node); + editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree"); + editor_data->get_undo_redo().add_do_reference(p_node); + editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)nullptr); + editor_data->get_undo_redo().commit_action(); +} + void SceneTreeDock::_node_collapsed(Object *p_obj) { TreeItem *ti = Object::cast_to<TreeItem>(p_obj); if (!ti) { @@ -1194,28 +1219,27 @@ void SceneTreeDock::_notification(int p_what) { spatial_editor_plugin->get_spatial_editor()->connect("item_lock_status_changed", Callable(scene_tree, "_update_tree")); spatial_editor_plugin->get_spatial_editor()->connect("item_group_status_changed", Callable(scene_tree, "_update_tree")); - button_add->set_icon(get_theme_icon("Add", "EditorIcons")); - button_instance->set_icon(get_theme_icon("Instance", "EditorIcons")); - button_create_script->set_icon(get_theme_icon("ScriptCreate", "EditorIcons")); - button_detach_script->set_icon(get_theme_icon("ScriptRemove", "EditorIcons")); + button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + button_instance->set_icon(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons"))); + button_create_script->set_icon(get_theme_icon(SNAME("ScriptCreate"), SNAME("EditorIcons"))); + button_detach_script->set_icon(get_theme_icon(SNAME("ScriptRemove"), SNAME("EditorIcons"))); - filter->set_right_icon(get_theme_icon("Search", "EditorIcons")); + filter->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); filter->set_clear_button_enabled(true); - EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed)); - scene_tree->get_scene_tree()->connect("item_collapsed", callable_mp(this, &SceneTreeDock::_node_collapsed)); - // create_root_dialog HBoxContainer *top_row = memnew(HBoxContainer); top_row->set_name("NodeShortcutsTopRow"); top_row->set_h_size_flags(SIZE_EXPAND_FILL); - top_row->add_child(memnew(Label(TTR("Create Root Node:")))); + Label *l = memnew(Label(TTR("Create Root Node:"))); + l->set_theme_type_variation("HeaderSmall"); + top_row->add_child(l); top_row->add_spacer(); Button *node_shortcuts_toggle = memnew(Button); node_shortcuts_toggle->set_flat(true); node_shortcuts_toggle->set_name("NodeShortcutsToggle"); - node_shortcuts_toggle->set_icon(get_theme_icon("Favorites", "EditorIcons")); + node_shortcuts_toggle->set_icon(get_theme_icon(SNAME("Favorites"), SNAME("EditorIcons"))); node_shortcuts_toggle->set_toggle_mode(true); node_shortcuts_toggle->set_tooltip(TTR("Switch to Favorite Nodes")); node_shortcuts_toggle->set_pressed(EDITOR_GET("_use_favorites_root_selection")); @@ -1235,19 +1259,19 @@ void SceneTreeDock::_notification(int p_what) { button_2d = memnew(Button); beginner_node_shortcuts->add_child(button_2d); button_2d->set_text(TTR("2D Scene")); - button_2d->set_icon(get_theme_icon("Node2D", "EditorIcons")); + button_2d->set_icon(get_theme_icon(SNAME("Node2D"), SNAME("EditorIcons"))); button_2d->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected), make_binds(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_theme_icon("Node3D", "EditorIcons")); + button_3d->set_icon(get_theme_icon(SNAME("Node3D"), SNAME("EditorIcons"))); button_3d->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected), make_binds(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_theme_icon("Control", "EditorIcons")); + button_ui->set_icon(get_theme_icon(SNAME("Control"), SNAME("EditorIcons"))); button_ui->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected), make_binds(TOOL_CREATE_USER_INTERFACE, false)); VBoxContainer *favorite_node_shortcuts = memnew(VBoxContainer); @@ -1257,7 +1281,7 @@ void SceneTreeDock::_notification(int p_what) { button_custom = memnew(Button); node_shortcuts->add_child(button_custom); button_custom->set_text(TTR("Other Node")); - button_custom->set_icon(get_theme_icon("Add", "EditorIcons")); + button_custom->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); button_custom->connect("pressed", callable_bind(callable_mp(this, &SceneTreeDock::_tool_selected), TOOL_NEW, false)); node_shortcuts->add_spacer(); @@ -1273,16 +1297,16 @@ void SceneTreeDock::_notification(int p_what) { clear_inherit_confirm->disconnect("confirmed", callable_mp(this, &SceneTreeDock::_tool_selected)); } break; case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { - button_add->set_icon(get_theme_icon("Add", "EditorIcons")); - button_instance->set_icon(get_theme_icon("Instance", "EditorIcons")); - button_create_script->set_icon(get_theme_icon("ScriptCreate", "EditorIcons")); - button_detach_script->set_icon(get_theme_icon("ScriptRemove", "EditorIcons")); - button_2d->set_icon(get_theme_icon("Node2D", "EditorIcons")); - button_3d->set_icon(get_theme_icon("Node3D", "EditorIcons")); - button_ui->set_icon(get_theme_icon("Control", "EditorIcons")); - button_custom->set_icon(get_theme_icon("Add", "EditorIcons")); - - filter->set_right_icon(get_theme_icon("Search", "EditorIcons")); + button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + button_instance->set_icon(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons"))); + button_create_script->set_icon(get_theme_icon(SNAME("ScriptCreate"), SNAME("EditorIcons"))); + button_detach_script->set_icon(get_theme_icon(SNAME("ScriptRemove"), SNAME("EditorIcons"))); + button_2d->set_icon(get_theme_icon(SNAME("Node2D"), SNAME("EditorIcons"))); + button_3d->set_icon(get_theme_icon(SNAME("Node3D"), SNAME("EditorIcons"))); + button_ui->set_icon(get_theme_icon(SNAME("Control"), SNAME("EditorIcons"))); + button_custom->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + + filter->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); filter->set_clear_button_enabled(true); } break; case NOTIFICATION_PROCESS: { @@ -1363,30 +1387,25 @@ void SceneTreeDock::_set_owners(Node *p_owner, const Array &p_nodes) { } } -void SceneTreeDock::_fill_path_renames(Vector<StringName> base_path, Vector<StringName> new_base_path, Node *p_node, List<Pair<NodePath, NodePath>> *p_renames) { +void SceneTreeDock::_fill_path_renames(Vector<StringName> base_path, Vector<StringName> new_base_path, Node *p_node, Map<Node *, NodePath> *p_renames) { base_path.push_back(p_node->get_name()); if (new_base_path.size()) { new_base_path.push_back(p_node->get_name()); } - NodePath from(base_path, true); - NodePath to; + NodePath new_path; if (new_base_path.size()) { - to = NodePath(new_base_path, true); + new_path = NodePath(new_base_path, true); } - Pair<NodePath, NodePath> npp; - npp.first = from; - npp.second = to; - - p_renames->push_back(npp); + p_renames->insert(p_node, new_path); for (int i = 0; i < p_node->get_child_count(); i++) { _fill_path_renames(base_path, new_base_path, p_node->get_child(i), p_renames); } } -void SceneTreeDock::fill_path_renames(Node *p_node, Node *p_new_parent, List<Pair<NodePath, NodePath>> *p_renames) { +void SceneTreeDock::fill_path_renames(Node *p_node, Node *p_new_parent, Map<Node *, NodePath> *p_renames) { Vector<StringName> base_path; Node *n = p_node->get_parent(); while (n) { @@ -1409,75 +1428,126 @@ void SceneTreeDock::fill_path_renames(Node *p_node, Node *p_new_parent, List<Pai _fill_path_renames(base_path, new_base_path, p_node, p_renames); } -void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodePath>> *p_renames, Map<Ref<Animation>, Set<int>> *r_rem_anims) { - Map<Ref<Animation>, Set<int>> rem_anims; +bool SceneTreeDock::_update_node_path(Node *p_root_node, NodePath &r_node_path, Map<Node *, NodePath> *p_renames) const { + Node *target_node = p_root_node->get_node_or_null(r_node_path); + 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)) + "'"); - if (!r_rem_anims) { - r_rem_anims = &rem_anims; - } + // Try to find the target node in modified node paths. + Map<Node *, NodePath>::Element *found_node_path = p_renames->find(target_node); + if (found_node_path) { + Map<Node *, NodePath>::Element *found_root_path = p_renames->find(p_root_node); + NodePath root_path_new = found_root_path ? found_root_path->get() : p_root_node->get_path(); + r_node_path = root_path_new.rel_path_to(found_node_path->get()); - if (!p_base) { - p_base = edited_scene; + return true; } - if (!p_base) { - return; + // Update the path if the base node has changed and has not been deleted. + Map<Node *, NodePath>::Element *found_root_path = p_renames->find(p_root_node); + if (found_root_path) { + NodePath root_path_new = found_root_path->get(); + if (!root_path_new.is_empty()) { + NodePath old_abs_path = NodePath(String(p_root_node->get_path()).plus_file(r_node_path)); + old_abs_path.simplify(); + r_node_path = root_path_new.rel_path_to(old_abs_path); + } + + return true; } - // Renaming node paths used in script instances - if (p_base->get_script_instance()) { - ScriptInstance *si = p_base->get_script_instance(); - - if (si) { - List<PropertyInfo> properties; - si->get_property_list(&properties); - NodePath root_path = p_base->get_path(); - - for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { - String propertyname = E->get().name; - Variant p = p_base->get(propertyname); - if (p.get_type() == Variant::NODE_PATH) { - NodePath root_path_new = root_path; - for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) { - if (root_path == F->get().first) { - root_path_new = F->get().second; - break; - } + return false; +} + +bool SceneTreeDock::_check_node_path_recursive(Node *p_root_node, Variant &r_variant, Map<Node *, NodePath> *p_renames) const { + switch (r_variant.get_type()) { + case Variant::NODE_PATH: { + NodePath node_path = r_variant; + if (!node_path.is_empty() && _update_node_path(p_root_node, node_path, p_renames)) { + r_variant = node_path; + return true; + } + } break; + + case Variant::ARRAY: { + Array a = r_variant; + bool updated = false; + for (int i = 0; i < a.size(); i++) { + Variant value = a[i]; + if (_check_node_path_recursive(p_root_node, value, p_renames)) { + if (!updated) { + a = a.duplicate(); // Need to duplicate for undo-redo to work. + updated = true; } + a[i] = value; + } + } + if (updated) { + r_variant = a; + return true; + } + } break; - // Goes through all paths to check if its matching - for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) { - NodePath rel_path_old = root_path.rel_path_to(F->get().first); + case Variant::DICTIONARY: { + Dictionary d = r_variant; + bool updated = false; + for (int i = 0; i < d.size(); i++) { + Variant value = d.get_value_at_index(i); + if (_check_node_path_recursive(p_root_node, value, p_renames)) { + if (!updated) { + d = d.duplicate(); // Need to duplicate for undo-redo to work. + updated = true; + } + d[d.get_key_at_index(i)] = value; + } + } + if (updated) { + r_variant = d; + return true; + } + } break; - // if old path detected, then it needs to be replaced with the new one - if (p == rel_path_old) { - NodePath rel_path_new = F->get().second; + default: { + } + } - // if not empty, get new relative path - if (!rel_path_new.is_empty()) { - rel_path_new = root_path_new.rel_path_to(F->get().second); - } + return false; +} - editor_data->get_undo_redo().add_do_property(p_base, propertyname, rel_path_new); - editor_data->get_undo_redo().add_undo_property(p_base, propertyname, rel_path_old); +void SceneTreeDock::perform_node_renames(Node *p_base, Map<Node *, NodePath> *p_renames, Map<Ref<Animation>, Set<int>> *r_rem_anims) { + Map<Ref<Animation>, Set<int>> rem_anims; + if (!r_rem_anims) { + r_rem_anims = &rem_anims; + } - p_base->set(propertyname, rel_path_new); - break; - } + if (!p_base) { + p_base = edited_scene; + } + + if (!p_base) { + return; + } - // update the node itself if it has a valid node path and has not been deleted - if (root_path == F->get().first && p != NodePath() && F->get().second != NodePath()) { - NodePath abs_path = NodePath(String(root_path).plus_file(p)).simplified(); - NodePath rel_path_new = F->get().second.rel_path_to(abs_path); + // No renaming if base node is deleted. + Map<Node *, NodePath>::Element *found_base_path = p_renames->find(p_base); + if (found_base_path && found_base_path->get().is_empty()) { + return; + } - editor_data->get_undo_redo().add_do_property(p_base, propertyname, rel_path_new); - editor_data->get_undo_redo().add_undo_property(p_base, propertyname, p); + // Renaming node paths used in node properties. + List<PropertyInfo> properties; + p_base->get_property_list(&properties); - p_base->set(propertyname, rel_path_new); - } - } - } - } + for (const PropertyInfo &E : properties) { + if (!(E.usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR))) { + continue; + } + String propertyname = E.name; + Variant old_variant = p_base->get(propertyname); + Variant updated_variant = old_variant; + if (_check_node_path_recursive(p_base, updated_variant, p_renames)) { + editor_data->get_undo_redo().add_do_property(p_base, propertyname, updated_variant); + editor_data->get_undo_redo().add_undo_property(p_base, propertyname, old_variant); + p_base->set(propertyname, updated_variant); } } @@ -1490,21 +1560,11 @@ void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodeP Node *root = ap->get_node(ap->get_root()); if (root) { - NodePath root_path = root->get_path(); - NodePath new_root_path = root_path; - - for (List<Pair<NodePath, NodePath>>::Element *E = p_renames->front(); E; E = E->next()) { - if (E->get().first == root_path) { - new_root_path = E->get().second; - break; - } - } - - if (new_root_path != NodePath()) { - //will not be erased - - for (List<StringName>::Element *E = anims.front(); E; E = E->next()) { - Ref<Animation> anim = ap->get_animation(E->get()); + Map<Node *, NodePath>::Element *found_root_path = p_renames->find(root); + NodePath new_root_path = found_root_path ? found_root_path->get() : root->get_path(); + if (!new_root_path.is_empty()) { // No renaming if root node is deleted. + for (const StringName &E : anims) { + Ref<Animation> anim = ap->get_animation(E); if (!r_rem_anims->has(anim)) { r_rem_anims->insert(anim, Set<int>()); Set<int> &ran = r_rem_anims->find(anim)->get(); @@ -1526,47 +1586,44 @@ void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodeP continue; } - NodePath old_np = n->get_path(); - if (!ran.has(i)) { continue; //channel was removed } - for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) { - if (F->get().first == old_np) { - if (F->get().second == NodePath()) { - //will be erased - - int idx = 0; - Set<int>::Element *EI = ran.front(); - ERR_FAIL_COND(!EI); //bug - while (EI->get() != i) { - idx++; - EI = EI->next(); - ERR_FAIL_COND(!EI); //another bug - } - - editor_data->get_undo_redo().add_do_method(anim.ptr(), "remove_track", idx); - editor_data->get_undo_redo().add_undo_method(anim.ptr(), "add_track", anim->track_get_type(i), idx); - editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_path", idx, track_np); - editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_interpolation_type", idx, anim->track_get_interpolation_type(i)); - for (int j = 0; j < anim->track_get_key_count(i); j++) { - editor_data->get_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)); - } - - ran.erase(i); //byebye channel - - } else { - //will be renamed - NodePath rel_path = new_root_path.rel_path_to(F->get().second); - - NodePath new_path = NodePath(rel_path.get_names(), track_np.get_subnames(), false); - if (new_path == track_np) { - continue; //bleh - } - editor_data->get_undo_redo().add_do_method(anim.ptr(), "track_set_path", i, new_path); - editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_path", i, track_np); + Map<Node *, NodePath>::Element *found_path = p_renames->find(n); + if (found_path) { + if (found_path->get() == NodePath()) { + //will be erased + + int idx = 0; + Set<int>::Element *EI = ran.front(); + ERR_FAIL_COND(!EI); //bug + while (EI->get() != i) { + idx++; + EI = EI->next(); + ERR_FAIL_COND(!EI); //another bug + } + + editor_data->get_undo_redo().add_do_method(anim.ptr(), "remove_track", idx); + editor_data->get_undo_redo().add_undo_method(anim.ptr(), "add_track", anim->track_get_type(i), idx); + editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_path", idx, track_np); + editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_interpolation_type", idx, anim->track_get_interpolation_type(i)); + for (int j = 0; j < anim->track_get_key_count(i); j++) { + editor_data->get_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)); } + + ran.erase(i); //byebye channel + + } else { + //will be renamed + NodePath rel_path = new_root_path.rel_path_to(found_path->get()); + + NodePath new_path = NodePath(rel_path.get_names(), track_np.get_subnames(), false); + if (new_path == track_np) { + continue; //bleh + } + editor_data->get_undo_redo().add_do_method(anim.ptr(), "track_set_path", i, new_path); + editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_path", i, track_np); } } } @@ -1581,7 +1638,7 @@ void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodeP } void SceneTreeDock::_node_prerenamed(Node *p_node, const String &p_new_name) { - List<Pair<NodePath, NodePath>> path_renames; + Map<Node *, NodePath> path_renames; Vector<StringName> base_path; Node *n = p_node->get_parent(); @@ -1596,10 +1653,8 @@ void SceneTreeDock::_node_prerenamed(Node *p_node, const String &p_new_name) { new_base_path.push_back(p_new_name); - Pair<NodePath, NodePath> npp; - npp.first = NodePath(base_path, true); - npp.second = NodePath(new_base_path, true); - path_renames.push_back(npp); + NodePath new_path(new_base_path, true); + path_renames[p_node] = new_path; for (int i = 0; i < p_node->get_child_count(); i++) { _fill_path_renames(base_path, new_base_path, p_node->get_child(i), &path_renames); @@ -1611,8 +1666,8 @@ void SceneTreeDock::_node_prerenamed(Node *p_node, const String &p_new_name) { bool SceneTreeDock::_validate_no_foreign() { List<Node *> selection = editor_selection->get_selected_node_list(); - for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - if (E->get() != edited_scene && E->get()->get_owner() != edited_scene) { + for (Node *E : selection) { + if (E != edited_scene && E->get_owner() != edited_scene) { accept->set_text(TTR("Can't operate on nodes from a foreign scene!")); accept->popup_centered(); return false; @@ -1621,11 +1676,11 @@ bool SceneTreeDock::_validate_no_foreign() { // 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->get()) { + if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene == E) { 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->get())) >= 0) { + 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; @@ -1638,9 +1693,9 @@ bool SceneTreeDock::_validate_no_foreign() { bool SceneTreeDock::_validate_no_instance() { List<Node *> selection = editor_selection->get_selected_node_list(); - for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - if (E->get() != edited_scene && E->get()->get_filename() != "") { - accept->set_text(TTR("This operation can't be done on instanced scenes.")); + for (Node *E : selection) { + if (E != edited_scene && E->get_filename() != "") { + accept->set_text(TTR("This operation can't be done on instantiated scenes.")); accept->popup_centered(); return false; } @@ -1661,8 +1716,8 @@ void SceneTreeDock::_node_reparent(NodePath p_path, bool p_keep_global_xform) { Vector<Node *> nodes; - for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - nodes.push_back(E->get()); + for (Node *E : selection) { + nodes.push_back(E); } _do_reparent(new_parent, -1, nodes, p_keep_global_xform); @@ -1704,7 +1759,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V editor_data->get_undo_redo().create_action(TTR("Reparent Node")); - List<Pair<NodePath, NodePath>> path_renames; + Map<Node *, NodePath> path_renames; Vector<StringName> former_names; int inc = 0; @@ -1719,8 +1774,8 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V List<Node *> owned; node->get_owned_by(node->get_owner(), &owned); Array owners; - for (List<Node *>::Element *E = owned.front(); E; E = E->next()) { - owners.push_back(E->get()); + for (Node *E : owned) { + owners.push_back(E); } if (new_parent == node->get_parent() && node->get_index() < p_position_in_parent + ni) { @@ -1741,21 +1796,24 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V // Name was modified, fix the path renames. if (old_name.casecmp_to(new_name) != 0) { // Fix the to name to have the new name. - NodePath old_new_name = path_renames[ni].second; - NodePath new_path; + Map<Node *, NodePath>::Element *found_path = path_renames.find(node); + if (found_path) { + NodePath old_new_name = found_path->get(); - Vector<StringName> unfixed_new_names = old_new_name.get_names(); - Vector<StringName> fixed_new_names; + Vector<StringName> unfixed_new_names = old_new_name.get_names(); + Vector<StringName> fixed_new_names; - // Get last name and replace with fixed new name. - for (int a = 0; a < (unfixed_new_names.size() - 1); a++) { - fixed_new_names.push_back(unfixed_new_names[a]); - } - fixed_new_names.push_back(new_name); - - NodePath fixed_node_path = NodePath(fixed_new_names, true); + // Get last name and replace with fixed new name. + for (int a = 0; a < (unfixed_new_names.size() - 1); a++) { + fixed_new_names.push_back(unfixed_new_names[a]); + } + fixed_new_names.push_back(new_name); - path_renames[ni].second = fixed_node_path; + NodePath fixed_node_path = NodePath(fixed_new_names, true); + path_renames[node] = fixed_node_path; + } else { + ERR_PRINT("Internal error. Can't find renamed path for node '" + node->get_path() + "'"); + } } editor_data->get_undo_redo().add_do_method(ed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(new_parent), new_name, p_position_in_parent + inc); @@ -1792,8 +1850,8 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V List<Node *> owned; node->get_owned_by(node->get_owner(), &owned); Array owners; - for (List<Node *>::Element *E = owned.front(); E; E = E->next()) { - owners.push_back(E->get()); + for (Node *E : owned) { + owners.push_back(E); } int child_pos = node->get_index(); @@ -1873,10 +1931,10 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) { } editor_data->get_undo_redo().create_action(TTR("Attach Script")); - for (List<Node *>::Element *E = selected.front(); E; E = E->next()) { - Ref<Script> existing = E->get()->get_script(); - editor_data->get_undo_redo().add_do_method(E->get(), "set_script", p_script); - editor_data->get_undo_redo().add_undo_method(E->get(), "set_script", existing); + for (Node *E : selected) { + Ref<Script> existing = E->get_script(); + editor_data->get_undo_redo().add_do_method(E, "set_script", p_script); + editor_data->get_undo_redo().add_undo_method(E, "set_script", existing); editor_data->get_undo_redo().add_do_method(this, "_update_script_button"); editor_data->get_undo_redo().add_undo_method(this, "_update_script_button"); } @@ -1887,12 +1945,31 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) { _update_script_button(); } +void SceneTreeDock::_shader_created(Ref<Shader> p_shader) { + if (selected_shader_material.is_null()) { + return; + } + + Ref<Shader> existing = selected_shader_material->get_shader(); + + editor_data->get_undo_redo().create_action(TTR("Set Shader")); + editor_data->get_undo_redo().add_do_method(selected_shader_material.ptr(), "set_shader", p_shader); + editor_data->get_undo_redo().add_undo_method(selected_shader_material.ptr(), "set_shader", existing); + editor_data->get_undo_redo().commit_action(); +} + void SceneTreeDock::_script_creation_closed() { script_create_dialog->disconnect("script_created", callable_mp(this, &SceneTreeDock::_script_created)); script_create_dialog->disconnect("confirmed", callable_mp(this, &SceneTreeDock::_script_creation_closed)); script_create_dialog->disconnect("cancelled", callable_mp(this, &SceneTreeDock::_script_creation_closed)); } +void SceneTreeDock::_shader_creation_closed() { + shader_create_dialog->disconnect("shader_created", callable_mp(this, &SceneTreeDock::_shader_created)); + shader_create_dialog->disconnect("confirmed", callable_mp(this, &SceneTreeDock::_shader_creation_closed)); + shader_create_dialog->disconnect("cancelled", callable_mp(this, &SceneTreeDock::_shader_creation_closed)); +} + void SceneTreeDock::_toggle_editable_children_from_selection() { List<Node *> selection = editor_selection->get_selected_node_list(); List<Node *>::Element *e = selection.front(); @@ -1951,8 +2028,8 @@ void SceneTreeDock::_delete_confirm(bool p_cut) { bool entire_scene = false; - for (List<Node *>::Element *E = remove_list.front(); E; E = E->next()) { - if (E->get() == edited_scene) { + for (Node *E : remove_list) { + if (E == edited_scene) { entire_scene = true; } } @@ -1966,11 +2043,10 @@ void SceneTreeDock::_delete_confirm(bool p_cut) { } else { remove_list.sort_custom<Node::Comparator>(); //sort nodes to keep positions - List<Pair<NodePath, NodePath>> path_renames; + Map<Node *, NodePath> path_renames; //delete from animation - for (List<Node *>::Element *E = remove_list.front(); E; E = E->next()) { - Node *n = E->get(); + for (Node *n : remove_list) { if (!n->is_inside_tree() || !n->get_parent()) { continue; } @@ -1980,8 +2056,7 @@ void SceneTreeDock::_delete_confirm(bool p_cut) { perform_node_renames(nullptr, &path_renames); //delete for read - for (List<Node *>::Element *E = remove_list.front(); E; E = E->next()) { - Node *n = E->get(); + for (Node *n : remove_list) { if (!n->is_inside_tree() || !n->get_parent()) { continue; } @@ -1989,8 +2064,8 @@ void SceneTreeDock::_delete_confirm(bool p_cut) { List<Node *> owned; n->get_owned_by(n->get_owner(), &owned); Array owners; - for (List<Node *>::Element *F = owned.front(); F; F = F->next()) { - owners.push_back(F->get()); + for (Node *F : owned) { + owners.push_back(F); } editor_data->get_undo_redo().add_do_method(n->get_parent(), "remove_child", n); @@ -2114,7 +2189,7 @@ void SceneTreeDock::_do_create(Node *p_parent) { ct->set_size(ms); } - emit_signal("node_created", c); + emit_signal(SNAME("node_created"), c); } void SceneTreeDock::_create() { @@ -2143,8 +2218,7 @@ void SceneTreeDock::_create() { UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Change type of node(s)")); - for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - Node *n = E->get(); + for (Node *n : selection) { ERR_FAIL_COND(!n); Variant c = create_dialog->instance_selected(); @@ -2201,8 +2275,8 @@ void SceneTreeDock::_create() { _do_create(parent); Vector<Node *> nodes; - for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - nodes.push_back(E->get()); + for (Node *E : selection) { + nodes.push_back(E); } // This works because editor_selection was cleared and populated with last created node in _do_create() @@ -2210,7 +2284,7 @@ void SceneTreeDock::_create() { _do_reparent(last_created, -1, nodes, true); } - scene_tree->get_scene_tree()->call_deferred("grab_focus"); + scene_tree->get_scene_tree()->grab_focus(); } void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_properties, bool p_remove_old) { @@ -2218,17 +2292,17 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_prop Node *newnode = p_by_node; if (p_keep_properties) { - Node *default_oldnode = Object::cast_to<Node>(ClassDB::instance(n->get_class())); + Node *default_oldnode = Object::cast_to<Node>(ClassDB::instantiate(n->get_class())); List<PropertyInfo> pinfo; n->get_property_list(&pinfo); - for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { - if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { + for (const PropertyInfo &E : pinfo) { + if (!(E.usage & PROPERTY_USAGE_STORAGE)) { continue; } - if (E->get().name == "__meta__") { - Dictionary metadata = n->get(E->get().name); + if (E.name == "__meta__") { + Dictionary metadata = n->get(E.name); if (metadata.has("_editor_description_")) { newnode->set_meta("_editor_description_", metadata["_editor_description_"]); } @@ -2245,8 +2319,8 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_prop continue; } - if (default_oldnode->get(E->get().name) != n->get(E->get().name)) { - newnode->set(E->get().name, n->get(E->get().name)); + if (default_oldnode->get(E.name) != n->get(E.name)) { + newnode->set(E.name, n->get(E.name)); } } @@ -2259,12 +2333,11 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_prop List<MethodInfo> sl; n->get_signal_list(&sl); - for (List<MethodInfo>::Element *E = sl.front(); E; E = E->next()) { + for (const MethodInfo &E : sl) { List<Object::Connection> cl; - n->get_signal_connection_list(E->get().name, &cl); + n->get_signal_connection_list(E.name, &cl); - for (List<Object::Connection>::Element *F = cl.front(); F; F = F->next()) { - Object::Connection &c = F->get(); + for (const Object::Connection &c : cl) { if (!(c.flags & Object::CONNECT_PERSIST)) { continue; } @@ -2457,9 +2530,51 @@ void SceneTreeDock::_files_dropped(Vector<String> p_files, NodePath p_to, int p_ Node *node = get_node(p_to); ERR_FAIL_COND(!node); - int to_pos = -1; - _normalize_drop(node, to_pos, p_type); - _perform_instance_scenes(p_files, node, to_pos); + 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 { + String res_path = p_files[0]; + StringName res_type = EditorFileSystem::get_singleton()->get_file_type(res_path); + List<String> valid_properties; + + List<PropertyInfo> pinfo; + node->get_property_list(&pinfo); + + for (const PropertyInfo &p : pinfo) { + if (!(p.usage & PROPERTY_USAGE_EDITOR) || !(p.usage & PROPERTY_USAGE_STORAGE) || p.hint != PROPERTY_HINT_RESOURCE_TYPE) { + continue; + } + Vector<String> valid_types = p.hint_string.split(","); + + for (const String &prop_type : valid_types) { + 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)) { + valid_properties.push_back(p.name); + break; + } + } + } + + if (valid_properties.size() > 1) { + property_drop_node = node; + resource_drop_path = res_path; + + bool capitalize = bool(EDITOR_GET("interface/inspector/capitalize_properties")); + menu_properties->clear(); + for (const String &p : valid_properties) { + menu_properties->add_item(capitalize ? p.capitalize() : p); + menu_properties->set_item_metadata(menu_properties->get_item_count() - 1, p); + } + + menu_properties->set_size(Size2(1, 1)); + 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)); + } + } } void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) { @@ -2489,8 +2604,8 @@ void SceneTreeDock::_nodes_dragged(Array p_nodes, NodePath p_to, int p_type) { } Vector<Node *> nodes; - for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - nodes.push_back(E->get()); + for (Node *E : selection) { + nodes.push_back(E); } int to_pos = -1; @@ -2506,15 +2621,15 @@ void SceneTreeDock::_add_children_to_popup(Object *p_obj, int p_depth) { List<PropertyInfo> pinfo; p_obj->get_property_list(&pinfo); - for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { - if (!(E->get().usage & PROPERTY_USAGE_EDITOR)) { + for (const PropertyInfo &E : pinfo) { + if (!(E.usage & PROPERTY_USAGE_EDITOR)) { continue; } - if (E->get().hint != PROPERTY_HINT_RESOURCE_TYPE) { + if (E.hint != PROPERTY_HINT_RESOURCE_TYPE) { continue; } - Variant value = p_obj->get(E->get().name); + Variant value = p_obj->get(E.name); if (value.get_type() != Variant::OBJECT) { continue; } @@ -2529,7 +2644,7 @@ void SceneTreeDock::_add_children_to_popup(Object *p_obj, int p_depth) { menu->add_submenu_item(TTR("Sub-Resources"), "Sub-Resources"); } int index = menu_subresources->get_item_count(); - menu_subresources->add_icon_item(icon, E->get().name.capitalize(), EDIT_SUBRESOURCE_BASE + subresources.size()); + menu_subresources->add_icon_item(icon, E.name.capitalize(), EDIT_SUBRESOURCE_BASE + subresources.size()); menu_subresources->set_item_h_offset(index, p_depth * 10 * EDSCALE); subresources.push_back(obj->get_instance_id()); @@ -2541,8 +2656,8 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { if (!EditorNode::get_singleton()->get_edited_scene()) { menu->clear(); if (profile_allow_editing) { - menu->add_icon_shortcut(get_theme_icon("Add", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW); - menu->add_icon_shortcut(get_theme_icon("Instance", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANCE); + menu->add_icon_shortcut(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW); + menu->add_icon_shortcut(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANTIATE); } menu->set_size(Size2(1, 1)); @@ -2574,10 +2689,10 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_separator(); } - menu->add_icon_shortcut(get_theme_icon("Add", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW); - menu->add_icon_shortcut(get_theme_icon("Instance", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANCE); + menu->add_icon_shortcut(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW); + menu->add_icon_shortcut(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANTIATE); } - menu->add_icon_shortcut(get_theme_icon("Collapse", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/expand_collapse_all"), TOOL_EXPAND_COLLAPSE); + menu->add_icon_shortcut(get_theme_icon(SNAME("Collapse"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/expand_collapse_all"), TOOL_EXPAND_COLLAPSE); menu->add_separator(); existing_script = selected->get_script(); @@ -2601,18 +2716,18 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { if (full_selection.size() == 1) { add_separator = true; - menu->add_icon_shortcut(get_theme_icon("ScriptCreate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT); + menu->add_icon_shortcut(get_theme_icon(SNAME("ScriptCreate"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT); if (existing_script.is_valid()) { - menu->add_icon_shortcut(get_theme_icon("ScriptExtend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/extend_script"), TOOL_EXTEND_SCRIPT); + menu->add_icon_shortcut(get_theme_icon(SNAME("ScriptExtend"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/extend_script"), TOOL_EXTEND_SCRIPT); } } if (existing_script.is_valid() && existing_script_removable) { add_separator = true; - menu->add_icon_shortcut(get_theme_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/detach_script"), TOOL_DETACH_SCRIPT); + menu->add_icon_shortcut(get_theme_icon(SNAME("ScriptRemove"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/detach_script"), TOOL_DETACH_SCRIPT); } else if (full_selection.size() > 1) { bool script_exists = false; - for (List<Node *>::Element *E = full_selection.front(); E; E = E->next()) { - if (!E->get()->get_script().is_null()) { + for (Node *E : full_selection) { + if (!E->get_script().is_null()) { script_exists = true; break; } @@ -2620,7 +2735,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { if (script_exists) { add_separator = true; - menu->add_icon_shortcut(get_theme_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/detach_script"), TOOL_DETACH_SCRIPT); + menu->add_icon_shortcut(get_theme_icon(SNAME("ScriptRemove"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/detach_script"), TOOL_DETACH_SCRIPT); } } @@ -2631,41 +2746,41 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { if (profile_allow_editing) { if (full_selection.size() == 1) { - menu->add_icon_shortcut(get_theme_icon("Rename", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/rename"), TOOL_RENAME); + menu->add_icon_shortcut(get_theme_icon(SNAME("Rename"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/rename"), TOOL_RENAME); } bool can_replace = true; - for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - if (E->get() != edited_scene && (E->get()->get_owner() != edited_scene || E->get()->get_filename() != "")) { + for (Node *E : selection) { + if (E != edited_scene && (E->get_owner() != edited_scene || E->get_filename() != "")) { can_replace = false; break; } } if (can_replace) { - menu->add_icon_shortcut(get_theme_icon("Reload", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/change_node_type"), TOOL_REPLACE); + menu->add_icon_shortcut(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/change_node_type"), TOOL_REPLACE); } if (scene_tree->get_selected() != edited_scene) { menu->add_separator(); - menu->add_icon_shortcut(get_theme_icon("MoveUp", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/move_up"), TOOL_MOVE_UP); - menu->add_icon_shortcut(get_theme_icon("MoveDown", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/move_down"), TOOL_MOVE_DOWN); - menu->add_icon_shortcut(get_theme_icon("Duplicate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/duplicate"), TOOL_DUPLICATE); - menu->add_icon_shortcut(get_theme_icon("Reparent", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/reparent"), TOOL_REPARENT); - menu->add_icon_shortcut(get_theme_icon("ReparentToNewNode", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/reparent_to_new_node"), TOOL_REPARENT_TO_NEW_NODE); + menu->add_icon_shortcut(get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/move_up"), TOOL_MOVE_UP); + menu->add_icon_shortcut(get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/move_down"), TOOL_MOVE_DOWN); + menu->add_icon_shortcut(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/duplicate"), TOOL_DUPLICATE); + menu->add_icon_shortcut(get_theme_icon(SNAME("Reparent"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/reparent"), TOOL_REPARENT); + menu->add_icon_shortcut(get_theme_icon(SNAME("ReparentToNewNode"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/reparent_to_new_node"), TOOL_REPARENT_TO_NEW_NODE); if (selection.size() == 1) { - menu->add_icon_shortcut(get_theme_icon("NewRoot", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/make_root"), TOOL_MAKE_ROOT); + menu->add_icon_shortcut(get_theme_icon(SNAME("NewRoot"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/make_root"), TOOL_MAKE_ROOT); } } } if (selection.size() == 1) { if (profile_allow_editing) { menu->add_separator(); - menu->add_icon_shortcut(get_theme_icon("CreateNewSceneFrom", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/save_branch_as_scene"), TOOL_NEW_SCENE_FROM); + menu->add_icon_shortcut(get_theme_icon(SNAME("CreateNewSceneFrom"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/save_branch_as_scene"), TOOL_NEW_SCENE_FROM); } if (full_selection.size() == 1) { menu->add_separator(); - menu->add_icon_shortcut(get_theme_icon("CopyNodePath", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/copy_node_path"), TOOL_COPY_NODE_PATH); + menu->add_icon_shortcut(get_theme_icon(SNAME("CopyNodePath"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/copy_node_path"), TOOL_COPY_NODE_PATH); } bool is_external = (selection[0]->get_filename() != ""); @@ -2677,7 +2792,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { if (profile_allow_editing) { menu->add_item(TTR("Clear Inheritance"), TOOL_SCENE_CLEAR_INHERITANCE); } - menu->add_icon_item(get_theme_icon("Load", "EditorIcons"), TTR("Open in Editor"), TOOL_SCENE_OPEN_INHERITED); + menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), 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]); @@ -2687,7 +2802,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_check_item(TTR("Load As Placeholder"), TOOL_SCENE_USE_PLACEHOLDER); menu->add_item(TTR("Make Local"), TOOL_SCENE_MAKE_LOCAL); } - menu->add_icon_item(get_theme_icon("Load", "EditorIcons"), TTR("Open in Editor"), TOOL_SCENE_OPEN); + menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Open in Editor"), TOOL_SCENE_OPEN); if (profile_allow_editing) { menu->set_item_checked(menu->get_item_idx_from_text(TTR("Editable Children")), editable); menu->set_item_checked(menu->get_item_idx_from_text(TTR("Load As Placeholder")), placeholder); @@ -2696,17 +2811,19 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { } } +#ifdef MODULE_REGEX_ENABLED if (profile_allow_editing && selection.size() > 1) { //this is not a commonly used action, it makes no sense for it to be where it was nor always present. menu->add_separator(); - menu->add_icon_shortcut(get_theme_icon("Rename", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/batch_rename"), TOOL_BATCH_RENAME); + menu->add_icon_shortcut(get_theme_icon(SNAME("Rename"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/batch_rename"), TOOL_BATCH_RENAME); } +#endif // MODULE_REGEX_ENABLED menu->add_separator(); - menu->add_icon_item(get_theme_icon("Help", "EditorIcons"), TTR("Open Documentation"), TOOL_OPEN_DOCUMENTATION); + menu->add_icon_item(get_theme_icon(SNAME("Help"), SNAME("EditorIcons")), TTR("Open Documentation"), TOOL_OPEN_DOCUMENTATION); if (profile_allow_editing) { menu->add_separator(); - menu->add_icon_shortcut(get_theme_icon("Remove", "EditorIcons"), ED_SHORTCUT("scene_tree/delete", TTR("Delete Node(s)"), KEY_DELETE), TOOL_ERASE); + menu->add_icon_shortcut(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), ED_SHORTCUT("scene_tree/delete", TTR("Delete Node(s)"), KEY_DELETE), TOOL_ERASE); } menu->set_size(Size2(1, 1)); menu->set_position(p_menu_pos); @@ -2726,6 +2843,11 @@ void SceneTreeDock::set_filter(const String &p_filter) { scene_tree->set_filter(p_filter); } +void SceneTreeDock::save_branch_to_file(String p_directory) { + new_scene_from_dialog->set_current_dir(p_directory); + _tool_selected(TOOL_NEW_SCENE_FROM); +} + void SceneTreeDock::_focus_node() { Node *node = scene_tree->get_selected(); ERR_FAIL_COND(!node); @@ -2806,6 +2928,42 @@ void SceneTreeDock::open_script_dialog(Node *p_for_node, bool p_extend) { } } +void SceneTreeDock::attach_shader_to_selected() { + if (selected_shader_material.is_null()) { + return; + } + + String path = selected_shader_material->get_path(); + if (path == "") { + String root_path; + if (editor_data->get_edited_scene_root()) { + root_path = editor_data->get_edited_scene_root()->get_filename(); + } + String shader_name; + if (selected_shader_material->get_name().is_empty()) { + shader_name = root_path.get_file(); + } else { + shader_name = selected_shader_material->get_name(); + } + if (root_path == "") { + path = String("res://").plus_file(shader_name); + } else { + path = root_path.get_base_dir().plus_file(shader_name); + } + } + + shader_create_dialog->connect("shader_created", callable_mp(this, &SceneTreeDock::_shader_created)); + shader_create_dialog->connect("confirmed", callable_mp(this, &SceneTreeDock::_shader_creation_closed)); + shader_create_dialog->connect("cancelled", callable_mp(this, &SceneTreeDock::_shader_creation_closed)); + shader_create_dialog->config(path); + shader_create_dialog->popup_centered(); +} + +void SceneTreeDock::open_shader_dialog(Ref<ShaderMaterial> &p_for_material) { + selected_shader_material = p_for_material; + attach_shader_to_selected(); +} + void SceneTreeDock::open_add_child_dialog() { create_dialog->set_base_type("CanvasItem"); _tool_selected(TOOL_NEW, true); @@ -2813,7 +2971,7 @@ void SceneTreeDock::open_add_child_dialog() { } void SceneTreeDock::open_instance_child_dialog() { - _tool_selected(TOOL_INSTANCE, true); + _tool_selected(TOOL_INSTANTIATE, true); } void SceneTreeDock::add_remote_tree_editor(Control *p_remote) { @@ -2848,7 +3006,7 @@ void SceneTreeDock::_remote_tree_selected() { edit_remote->set_pressed(true); edit_local->set_pressed(false); - emit_signal("remote_tree_selected"); + emit_signal(SNAME("remote_tree_selected")); } void SceneTreeDock::_local_tree_selected() { @@ -2949,8 +3107,8 @@ void SceneTreeDock::_feature_profile_changed() { } void SceneTreeDock::_clear_clipboard() { - for (List<Node *>::Element *E = node_clipboard.front(); E; E = E->next()) { - memdelete(E->get()); + for (Node *E : node_clipboard) { + memdelete(E); } node_clipboard.clear(); clipboard_resource_remap.clear(); @@ -2959,16 +3117,26 @@ void SceneTreeDock::_clear_clipboard() { void SceneTreeDock::_create_remap_for_node(Node *p_node, Map<RES, RES> &r_remap) { List<PropertyInfo> props; p_node->get_property_list(&props); + bool is_instantiated = EditorPropertyRevert::may_node_be_in_instance(p_node); - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { + for (const PropertyInfo &E : props) { + if (!(E.usage & PROPERTY_USAGE_STORAGE)) { continue; } - Variant v = p_node->get(E->get().name); + Variant v = p_node->get(E.name); if (v.is_ref()) { RES res = v; if (res.is_valid()) { + if (is_instantiated) { + Variant orig; + if (EditorPropertyRevert::get_instantiated_node_original_property(p_node, E.name, orig)) { + if (!EditorPropertyRevert::is_node_property_different(p_node, v, orig)) { + continue; + } + } + } + if ((res->get_path() == "" || res->get_path().find("::") > -1) && !r_remap.has(res)) { _create_remap_for_resource(res, r_remap); } @@ -2987,12 +3155,12 @@ void SceneTreeDock::_create_remap_for_resource(RES p_resource, Map<RES, RES> &r_ List<PropertyInfo> props; p_resource->get_property_list(&props); - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { + for (const PropertyInfo &E : props) { + if (!(E.usage & PROPERTY_USAGE_STORAGE)) { continue; } - Variant v = p_resource->get(E->get().name); + Variant v = p_resource->get(E.name); if (v.is_ref()) { RES res = v; if (res.is_valid()) { @@ -3006,11 +3174,10 @@ void SceneTreeDock::_create_remap_for_resource(RES p_resource, Map<RES, RES> &r_ void SceneTreeDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_owners"), &SceneTreeDock::_set_owners); - ClassDB::bind_method(D_METHOD("_unhandled_key_input"), &SceneTreeDock::_unhandled_key_input); - ClassDB::bind_method(D_METHOD("_input"), &SceneTreeDock::_input); + ClassDB::bind_method(D_METHOD("_update_script_button"), &SceneTreeDock::_update_script_button); - ClassDB::bind_method(D_METHOD("instance"), &SceneTreeDock::instance); + ClassDB::bind_method(D_METHOD("instantiate"), &SceneTreeDock::instantiate); ClassDB::bind_method(D_METHOD("get_tree_editor"), &SceneTreeDock::get_tree_editor); ClassDB::bind_method(D_METHOD("replace_node"), &SceneTreeDock::replace_node); @@ -3044,7 +3211,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel ED_SHORTCUT("scene_tree/rename", TTR("Rename"), KEY_F2); ED_SHORTCUT("scene_tree/batch_rename", TTR("Batch Rename"), KEY_MASK_SHIFT | KEY_F2); ED_SHORTCUT("scene_tree/add_child_node", TTR("Add Child Node"), KEY_MASK_CMD | KEY_A); - ED_SHORTCUT("scene_tree/instance_scene", TTR("Instance Child Scene"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_A); + ED_SHORTCUT("scene_tree/instance_scene", TTR("Instantiate Child Scene"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_A); ED_SHORTCUT("scene_tree/expand_collapse_all", TTR("Expand/Collapse All")); ED_SHORTCUT("scene_tree/cut_node", TTR("Cut"), KEY_MASK_CMD | KEY_X); ED_SHORTCUT("scene_tree/copy_node", TTR("Copy"), KEY_MASK_CMD | KEY_C); @@ -3073,8 +3240,8 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel button_instance = memnew(Button); button_instance->set_flat(true); - button_instance->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected), make_binds(TOOL_INSTANCE, false)); - button_instance->set_tooltip(TTR("Instance a scene file as a Node. Creates an inherited scene if no root node exists.")); + button_instance->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected), make_binds(TOOL_INSTANTIATE, false)); + button_instance->set_tooltip(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/instance_scene")); filter_hbc->add_child(button_instance); @@ -3147,6 +3314,9 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel scene_tree->connect("nodes_dragged", callable_mp(this, &SceneTreeDock::_nodes_drag_begin)); scene_tree->get_scene_tree()->connect("item_double_clicked", callable_mp(this, &SceneTreeDock::_focus_node)); + scene_tree->get_scene_tree()->connect("item_collapsed", callable_mp(this, &SceneTreeDock::_node_collapsed)); + + editor_selection->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed)); scene_tree->set_undo_redo(&editor_data->get_undo_redo()); scene_tree->set_editor_selection(editor_selection); @@ -3157,13 +3327,18 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel create_dialog->connect("create", callable_mp(this, &SceneTreeDock::_create)); create_dialog->connect("favorites_updated", callable_mp(this, &SceneTreeDock::_update_create_root_dialog)); +#ifdef MODULE_REGEX_ENABLED rename_dialog = memnew(RenameDialog(scene_tree, &editor_data->get_undo_redo())); add_child(rename_dialog); +#endif // MODULE_REGEX_ENABLED script_create_dialog = memnew(ScriptCreateDialog); script_create_dialog->set_inheritance_base_type("Node"); add_child(script_create_dialog); + shader_create_dialog = memnew(ShaderCreateDialog); + add_child(shader_create_dialog); + reparent_dialog = memnew(ReparentDialog); add_child(reparent_dialog); reparent_dialog->connect("reparent", callable_mp(this, &SceneTreeDock::_node_reparent)); @@ -3205,6 +3380,10 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel first_enter = true; restore_script_editor_on_drag = false; + menu_properties = memnew(PopupMenu); + add_child(menu_properties); + menu_properties->connect("id_pressed", callable_mp(this, &SceneTreeDock::_property_selected)); + clear_inherit_confirm = memnew(ConfirmationDialog); clear_inherit_confirm->set_text(TTR("Clear Inheritance? (No Undo!)")); clear_inherit_confirm->get_ok_button()->set_text(TTR("Clear")); |