diff options
Diffstat (limited to 'editor')
| -rw-r--r-- | editor/code_editor.cpp | 4 | ||||
| -rw-r--r-- | editor/editor_help_search.cpp | 31 | ||||
| -rw-r--r-- | editor/editor_help_search.h | 1 | ||||
| -rw-r--r-- | editor/editor_node.cpp | 41 | ||||
| -rw-r--r-- | editor/editor_node.h | 3 | ||||
| -rw-r--r-- | editor/editor_themes.cpp | 4 | ||||
| -rw-r--r-- | editor/filesystem_dock.cpp | 42 | ||||
| -rw-r--r-- | editor/filesystem_dock.h | 6 | ||||
| -rw-r--r-- | editor/import/post_import_plugin_skeleton_renamer.cpp | 13 | ||||
| -rw-r--r-- | editor/import/resource_importer_scene.cpp | 6 | ||||
| -rw-r--r-- | editor/inspector_dock.cpp | 3 | ||||
| -rw-r--r-- | editor/plugins/abstract_polygon_2d_editor.cpp | 99 | ||||
| -rw-r--r-- | editor/plugins/mesh_instance_3d_editor_plugin.cpp | 78 | ||||
| -rw-r--r-- | editor/plugins/navigation_obstacle_3d_editor_plugin.cpp | 6 | ||||
| -rw-r--r-- | editor/plugins/polygon_2d_editor_plugin.cpp | 4 | ||||
| -rw-r--r-- | editor/plugins/script_editor_plugin.cpp | 8 | ||||
| -rw-r--r-- | editor/plugins/skeleton_3d_editor_plugin.cpp | 4 | ||||
| -rw-r--r-- | editor/scene_tree_dock.cpp | 11 |
18 files changed, 210 insertions, 154 deletions
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 7e6a49d6c0..1842e8c1c4 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1514,8 +1514,8 @@ void CodeTextEditor::toggle_inline_comment(const String &delimiter) { // Empty lines should not be counted. bool is_empty = text_editor->get_line(line).strip_edges().is_empty(); is_all_empty = is_all_empty && is_empty; - // `.left(1)` here because get_delimiter_start_key will return `##` instead of `#` when there is multiple comment delimiter in a line. - if (!is_empty && (delimiter_idx == -1 || text_editor->get_delimiter_start_key(delimiter_idx).left(1) != delimiter)) { + // get_delimiter_start_key will return `##` instead of `#` when there is multiple comment delimiter in a line. + if (!is_empty && (delimiter_idx == -1 || !text_editor->get_delimiter_start_key(delimiter_idx).begins_with(delimiter))) { is_commented = false; break; } diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index 1029cfcf0e..44698d93f6 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -37,18 +37,6 @@ #include "editor/editor_settings.h" #include "editor/editor_string_names.h" -void EditorHelpSearch::_update_icons() { - search_box->set_right_icon(results_tree->get_editor_theme_icon(SNAME("Search"))); - search_box->set_clear_button_enabled(true); - search_box->add_theme_icon_override("right_icon", results_tree->get_editor_theme_icon(SNAME("Search"))); - case_sensitive_button->set_icon(results_tree->get_editor_theme_icon(SNAME("MatchCase"))); - hierarchy_button->set_icon(results_tree->get_editor_theme_icon(SNAME("ClassList"))); - - if (is_visible()) { - _update_results(); - } -} - void EditorHelpSearch::_update_results() { String term = search_box->get_text(); @@ -114,16 +102,24 @@ void EditorHelpSearch::_notification(int p_what) { } } break; - case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { - _update_icons(); - } break; - case NOTIFICATION_READY: { connect("confirmed", callable_mp(this, &EditorHelpSearch::_confirmed)); } break; + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: case NOTIFICATION_THEME_CHANGED: { - _update_icons(); + const int icon_width = get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor)); + results_tree->add_theme_constant_override("icon_max_width", icon_width); + + search_box->set_right_icon(get_editor_theme_icon(SNAME("Search"))); + search_box->add_theme_icon_override("right_icon", get_editor_theme_icon(SNAME("Search"))); + + case_sensitive_button->set_icon(get_editor_theme_icon(SNAME("MatchCase"))); + hierarchy_button->set_icon(get_editor_theme_icon(SNAME("ClassList"))); + + if (is_visible()) { + _update_results(); + } } break; case NOTIFICATION_PROCESS: { @@ -204,6 +200,7 @@ EditorHelpSearch::EditorHelpSearch() { search_box = memnew(LineEdit); search_box->set_custom_minimum_size(Size2(200, 0) * EDSCALE); search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); + search_box->set_clear_button_enabled(true); search_box->connect("gui_input", callable_mp(this, &EditorHelpSearch::_search_box_gui_input)); search_box->connect("text_changed", callable_mp(this, &EditorHelpSearch::_search_box_text_changed)); register_text_enter(search_box); diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h index e8056ce6ac..30a783a628 100644 --- a/editor/editor_help_search.h +++ b/editor/editor_help_search.h @@ -67,7 +67,6 @@ class EditorHelpSearch : public ConfirmationDialog { class Runner; Ref<Runner> search; - void _update_icons(); void _update_results(); void _search_box_gui_input(const Ref<InputEvent> &p_event); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 8c3637663d..f73eb81473 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1279,11 +1279,9 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String return; } } - } else { - if (FileAccess::exists(path + ".import")) { - show_warning(TTR("This resource can't be saved because it was imported from another file. Make it unique first.")); - return; - } + } else if (FileAccess::exists(path + ".import")) { + show_warning(TTR("This resource can't be saved because it was imported from another file. Make it unique first.")); + return; } } @@ -1811,11 +1809,18 @@ void EditorNode::save_all_scenes() { _save_all_scenes(); } -void EditorNode::save_scene_list(Vector<String> p_scene_filenames) { +void EditorNode::save_scene_if_open(const String &p_scene_path) { + int idx = editor_data.get_edited_scene_from_path(p_scene_path); + if (idx >= 0) { + _save_scene(p_scene_path, idx); + } +} + +void EditorNode::save_scene_list(const HashSet<String> &p_scene_paths) { for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { Node *scene = editor_data.get_edited_scene_root(i); - if (scene && (p_scene_filenames.find(scene->get_scene_file_path()) >= 0)) { + if (scene && p_scene_paths.has(scene->get_scene_file_path())) { _save_scene(scene->get_scene_file_path(), i); } } @@ -2342,21 +2347,15 @@ void EditorNode::_edit_current(bool p_skip_foreign) { int subr_idx = current_res->get_path().find("::"); if (subr_idx != -1) { String base_path = current_res->get_path().substr(0, subr_idx); - if (!base_path.is_resource_file()) { - if (FileAccess::exists(base_path + ".import")) { + if (FileAccess::exists(base_path + ".import")) { + if (!base_path.is_resource_file()) { if (get_edited_scene() && get_edited_scene()->get_scene_file_path() == base_path) { info_is_warning = true; } - editable_info = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow."); - } else { - if ((!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base_path) && ResourceLoader::get_resource_type(base_path) == "PackedScene") { - editable_info = TTR("This resource belongs to a scene that was instantiated or inherited.\nChanges to it must be made inside the original scene."); - } - } - } else { - if (FileAccess::exists(base_path + ".import")) { - editable_info = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow."); } + editable_info = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow."); + } else if ((!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base_path) && ResourceLoader::get_resource_type(base_path) == "PackedScene") { + editable_info = TTR("This resource belongs to a scene that was instantiated or inherited.\nChanges to it must be made inside the original scene."); } } else if (current_res->get_path().is_resource_file()) { if (FileAccess::exists(current_res->get_path() + ".import")) { @@ -4062,11 +4061,9 @@ bool EditorNode::is_resource_read_only(Ref<Resource> p_resource, bool p_foreign_ } } } - } else { + } else if (FileAccess::exists(path + ".import")) { // The resource is not a subresource, but if it has an .import file, it's imported so treat it as read only. - if (FileAccess::exists(path + ".import")) { - return true; - } + return true; } return false; diff --git a/editor/editor_node.h b/editor/editor_node.h index 7d85055ac2..bc7da69e75 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -912,7 +912,8 @@ public: PopupMenu *get_export_as_menu(); void save_all_scenes(); - void save_scene_list(Vector<String> p_scene_filenames); + void save_scene_if_open(const String &p_scene_path); + void save_scene_list(const HashSet<String> &p_scene_paths); void save_before_run(); void try_autosave(); void restart_editor(); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 2a42224c87..227b52472f 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -1808,7 +1808,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { if (increase_scrollbar_touch_area) { theme->set_stylebox("scroll", "HScrollBar", make_line_stylebox(separator_color, 50)); } else { - theme->set_stylebox("scroll", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), EditorStringName(EditorIcons)), 5, 5, 5, 5, 1, 1, 1, 1)); + theme->set_stylebox("scroll", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), EditorStringName(EditorIcons)), 5, 5, 5, 5, -5, 1, -5, 1)); } theme->set_stylebox("scroll_focus", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), EditorStringName(EditorIcons)), 5, 5, 5, 5, 1, 1, 1, 1)); theme->set_stylebox("grabber", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollGrabber"), EditorStringName(EditorIcons)), 6, 6, 6, 6, 1, 1, 1, 1)); @@ -1826,7 +1826,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { if (increase_scrollbar_touch_area) { theme->set_stylebox("scroll", "VScrollBar", make_line_stylebox(separator_color, 50, 1, 1, true)); } else { - theme->set_stylebox("scroll", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), EditorStringName(EditorIcons)), 5, 5, 5, 5, 1, 1, 1, 1)); + theme->set_stylebox("scroll", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), EditorStringName(EditorIcons)), 5, 5, 5, 5, 1, -5, 1, -5)); } theme->set_stylebox("scroll_focus", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), EditorStringName(EditorIcons)), 5, 5, 5, 5, 1, 1, 1, 1)); theme->set_stylebox("grabber", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollGrabber"), EditorStringName(EditorIcons)), 6, 6, 6, 6, 1, 1, 1, 1)); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index a491a9b214..ea043b42d1 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -733,7 +733,11 @@ void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_fa _update_tree(get_uncollapsed_paths(), false, p_select_in_favorites, true); if (display_mode != DISPLAY_MODE_TREE_ONLY) { _update_file_list(false); - files->get_v_scroll_bar()->set_value(0); + + // Reset the scroll for a directory. + if (p_path.ends_with("/")) { + files->get_v_scroll_bar()->set_value(0); + } } String file_name = p_path.get_file(); @@ -1160,9 +1164,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { void FileSystemDock::_select_file(const String &p_path, bool p_select_in_favorites) { String fpath = p_path; if (fpath.ends_with("/")) { - if (fpath != "res://") { - fpath = fpath.substr(0, fpath.length() - 1); - } + // Ignore a directory. } else if (fpath != "Favorites") { if (FileAccess::exists(fpath + ".import")) { Ref<ConfigFile> config; @@ -1377,7 +1379,7 @@ void FileSystemDock::_get_all_items_in_dir(EditorFileSystemDirectory *p_efsd, Ve } } -void FileSystemDock::_find_file_owners(EditorFileSystemDirectory *p_efsd, const Vector<String> &p_renames, Vector<String> &r_file_owners) const { +void FileSystemDock::_find_file_owners(EditorFileSystemDirectory *p_efsd, const HashSet<String> &p_renames, HashSet<String> &r_file_owners) const { for (int i = 0; i < p_efsd->get_subdir_count(); i++) { _find_file_owners(p_efsd->get_subdir(i), p_renames, r_file_owners); } @@ -1385,7 +1387,7 @@ void FileSystemDock::_find_file_owners(EditorFileSystemDirectory *p_efsd, const Vector<String> deps = p_efsd->get_file_deps(i); for (int j = 0; j < deps.size(); j++) { if (p_renames.has(deps[j])) { - r_file_owners.push_back(p_efsd->get_file_path(i)); + r_file_owners.insert(p_efsd->get_file_path(i)); break; } } @@ -1554,7 +1556,9 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin void FileSystemDock::_update_resource_paths_after_move(const HashMap<String, String> &p_renames, const HashMap<String, ResourceUID::ID> &p_uids) const { // Update the paths in ResourceUID, so that UIDs remain valid. for (const KeyValue<String, ResourceUID::ID> &pair : p_uids) { - ResourceUID::get_singleton()->set_id(pair.value, p_renames[pair.key]); + if (p_renames.has(pair.key)) { + ResourceUID::get_singleton()->set_id(pair.value, p_renames[pair.key]); + } } // Rename all resources loaded, be it subresources or actual resources. @@ -1578,14 +1582,15 @@ void FileSystemDock::_update_resource_paths_after_move(const HashMap<String, Str } } -void FileSystemDock::_update_dependencies_after_move(const HashMap<String, String> &p_renames, const Vector<String> &p_file_owners) const { +void FileSystemDock::_update_dependencies_after_move(const HashMap<String, String> &p_renames, const HashSet<String> &p_file_owners) const { // The following code assumes that the following holds: // 1) EditorFileSystem contains the old paths/folder structure from before the rename/move. // 2) ResourceLoader can use the new paths without needing to call rescan. List<String> scenes_to_reload; - for (int i = 0; i < p_file_owners.size(); ++i) { + for (const String &E : p_file_owners) { // Because we haven't called a rescan yet the found remap might still be an old path itself. - const String file = p_renames.has(p_file_owners[i]) ? p_renames[p_file_owners[i]] : p_file_owners[i]; + const HashMap<String, String>::ConstIterator I = p_renames.find(E); + const String file = I ? I->value : E; print_verbose("Remapping dependencies for: " + file); const Error err = ResourceLoader::rename_dependencies(file, p_renames); if (err == OK) { @@ -1593,7 +1598,7 @@ void FileSystemDock::_update_dependencies_after_move(const HashMap<String, Strin scenes_to_reload.push_back(file); } } else { - EditorNode::get_singleton()->add_io_error(TTR("Unable to update dependencies for:") + "\n" + p_file_owners[i] + "\n"); + EditorNode::get_singleton()->add_io_error(TTR("Unable to update dependencies for:") + "\n" + E + "\n"); } } @@ -1687,7 +1692,7 @@ void FileSystemDock::_make_scene_confirm() { int idx = EditorNode::get_singleton()->new_scene(); EditorNode::get_editor_data().set_scene_path(idx, scene_path); EditorNode::get_singleton()->set_edited_scene(make_scene_dialog->create_scene_root()); - EditorNode::get_singleton()->save_scene_list({ scene_path }); + EditorNode::get_singleton()->save_scene_if_open(scene_path); } void FileSystemDock::_resource_removed(const Ref<Resource> &p_resource) { @@ -1790,7 +1795,7 @@ void FileSystemDock::_rename_operation_confirm() { } HashMap<String, ResourceUID::ID> uids; - Vector<String> file_owners; // The files that use these moved/renamed resource files. + HashSet<String> file_owners; // The files that use these moved/renamed resource files. _before_move(uids, file_owners); HashMap<String, String> file_renames; @@ -1921,7 +1926,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_cop } HashMap<String, ResourceUID::ID> uids; - Vector<String> file_owners; // The files that use these moved/renamed resource files. + HashSet<String> file_owners; // The files that use these moved/renamed resource files. _before_move(uids, file_owners); bool is_moved = false; @@ -1953,11 +1958,11 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_cop } } -void FileSystemDock::_before_move(HashMap<String, ResourceUID::ID> &r_uids, Vector<String> &r_file_owners) const { - Vector<String> renamed_files; +void FileSystemDock::_before_move(HashMap<String, ResourceUID::ID> &r_uids, HashSet<String> &r_file_owners) const { + HashSet<String> renamed_files; for (int i = 0; i < to_move.size(); i++) { if (to_move[i].is_file) { - renamed_files.push_back(to_move[i].path); + renamed_files.insert(to_move[i].path); ResourceUID::ID uid = ResourceLoader::get_resource_uid(to_move[i].path); if (uid != ResourceUID::INVALID_ID) { r_uids[to_move[i].path] = uid; @@ -1970,7 +1975,7 @@ void FileSystemDock::_before_move(HashMap<String, ResourceUID::ID> &r_uids, Vect current_folder = folders.front()->get(); for (int j = 0; j < current_folder->get_file_count(); j++) { const String file_path = current_folder->get_file_path(j); - renamed_files.push_back(file_path); + renamed_files.insert(file_path); ResourceUID::ID uid = ResourceLoader::get_resource_uid(file_path); if (uid != ResourceUID::INVALID_ID) { r_uids[file_path] = uid; @@ -2491,6 +2496,7 @@ Control *FileSystemDock::create_tooltip_for_path(const String &p_path) const { // No tooltip for directory. return nullptr; } + ERR_FAIL_COND_V(!FileAccess::exists(p_path), nullptr); const String type = ResourceLoader::get_resource_type(p_path); Control *tooltip = EditorResourceTooltipPlugin::make_default_tooltip(p_path); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 104def71c8..1cde735cb8 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -266,11 +266,11 @@ private: void _update_import_dock(); void _get_all_items_in_dir(EditorFileSystemDirectory *p_efsd, Vector<String> &r_files, Vector<String> &r_folders) const; - void _find_file_owners(EditorFileSystemDirectory *p_efsd, const Vector<String> &p_renames, Vector<String> &r_file_owners) const; + void _find_file_owners(EditorFileSystemDirectory *p_efsd, const HashSet<String> &p_renames, HashSet<String> &r_file_owners) const; void _try_move_item(const FileOrFolder &p_item, const String &p_new_path, HashMap<String, String> &p_file_renames, HashMap<String, String> &p_folder_renames); void _try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const; - void _before_move(HashMap<String, ResourceUID::ID> &r_uids, Vector<String> &r_file_owners) const; - void _update_dependencies_after_move(const HashMap<String, String> &p_renames, const Vector<String> &p_file_owners) const; + void _before_move(HashMap<String, ResourceUID::ID> &r_uids, HashSet<String> &r_file_owners) const; + void _update_dependencies_after_move(const HashMap<String, String> &p_renames, const HashSet<String> &p_file_owners) const; void _update_resource_paths_after_move(const HashMap<String, String> &p_renames, const HashMap<String, ResourceUID::ID> &p_uids) const; void _update_favorites_list_after_move(const HashMap<String, String> &p_files_renames, const HashMap<String, String> &p_folders_renames) const; void _update_project_settings_after_move(const HashMap<String, String> &p_renames, const HashMap<String, String> &p_folders_renames); diff --git a/editor/import/post_import_plugin_skeleton_renamer.cpp b/editor/import/post_import_plugin_skeleton_renamer.cpp index 6704347877..adeea51dae 100644 --- a/editor/import/post_import_plugin_skeleton_renamer.cpp +++ b/editor/import/post_import_plugin_skeleton_renamer.cpp @@ -31,6 +31,7 @@ #include "post_import_plugin_skeleton_renamer.h" #include "editor/import/scene_import_settings.h" +#include "scene/3d/bone_attachment_3d.h" #include "scene/3d/importer_mesh_instance_3d.h" #include "scene/3d/skeleton_3d.h" #include "scene/animation/animation_player.h" @@ -119,19 +120,17 @@ void PostImportPluginSkeletonRenamer::_internal_process(InternalImportCategory p // Rename bones in all Nodes by calling method. { - Array vargs; - vargs.push_back(p_base_scene); - vargs.push_back(skeleton); Dictionary rename_map_dict; for (HashMap<String, String>::Iterator E = p_rename_map.begin(); E; ++E) { rename_map_dict[E->key] = E->value; } - vargs.push_back(rename_map_dict); - TypedArray<Node> nodes = p_base_scene->find_children("*"); + TypedArray<Node> nodes = p_base_scene->find_children("*", "BoneAttachment3D"); while (nodes.size()) { - Node *nd = Object::cast_to<Node>(nodes.pop_back()); - nd->callv("_notify_skeleton_bones_renamed", vargs); + BoneAttachment3D *attachment = Object::cast_to<BoneAttachment3D>(nodes.pop_back()); + if (attachment) { + attachment->notify_skeleton_bones_renamed(p_base_scene, skeleton, rename_map_dict); + } } } } diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index f9c989dc20..e3c575c127 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -669,7 +669,11 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap<R fixed_name = _fixstr(name, "convcolonly"); } - ERR_FAIL_COND_V(fixed_name.is_empty(), nullptr); + if (fixed_name.is_empty()) { + p_node->set_owner(nullptr); + memdelete(p_node); + ERR_FAIL_V_MSG(nullptr, vformat("Skipped node `%s` because its name is empty after removing the suffix.", name)); + } ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node); if (mi) { diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 044ac52147..717aaf396f 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -443,6 +443,9 @@ void InspectorDock::_notification(int p_what) { forward_button->set_icon(get_editor_theme_icon(SNAME("Forward"))); } + const int icon_width = get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor)); + history_menu->get_popup()->add_theme_constant_override("icon_max_width", icon_width); + history_menu->set_icon(get_editor_theme_icon(SNAME("History"))); object_menu->set_icon(get_editor_theme_icon(SNAME("Tools"))); search->set_right_icon(get_editor_theme_icon(SNAME("Search"))); diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index bc8c8f6f79..a15875fd93 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -289,43 +289,40 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) return false; } - const PosVertex insert = closest_edge_point(gpoint); - - if (insert.valid()) { - Vector<Vector2> vertices = _get_polygon(insert.polygon); - - if (vertices.size() < (_is_line() ? 2 : 3)) { - vertices.push_back(cpoint); - undo_redo->create_action(TTR("Edit Polygon")); - selected_point = Vertex(insert.polygon, vertices.size()); - _action_set_polygon(insert.polygon, vertices); - _commit_action(); - return true; - } else { - edited_point = PosVertex(insert.polygon, insert.vertex + 1, xform.affine_inverse().xform(insert.pos)); - vertices.insert(edited_point.vertex, edited_point.pos); - pre_move_edit = vertices; - selected_point = Vertex(edited_point.polygon, edited_point.vertex); - edge_point = PosVertex(); - - undo_redo->create_action(TTR("Insert Point")); - _action_set_polygon(insert.polygon, vertices); - _commit_action(); - return true; - } + const PosVertex closest = closest_point(gpoint); + if (closest.valid()) { + pre_move_edit = _get_polygon(closest.polygon); + edited_point = PosVertex(closest, xform.affine_inverse().xform(closest.pos)); + selected_point = closest; + edge_point = PosVertex(); + canvas_item_editor->update_viewport(); + return true; } else { - //look for points to move - const PosVertex closest = closest_point(gpoint); - - if (closest.valid()) { - pre_move_edit = _get_polygon(closest.polygon); - edited_point = PosVertex(closest, xform.affine_inverse().xform(closest.pos)); - selected_point = closest; - edge_point = PosVertex(); - canvas_item_editor->update_viewport(); - return true; - } else { - selected_point = Vertex(); + selected_point = Vertex(); + + const PosVertex insert = closest_edge_point(gpoint); + if (insert.valid()) { + Vector<Vector2> vertices = _get_polygon(insert.polygon); + + if (vertices.size() < (_is_line() ? 2 : 3)) { + vertices.push_back(cpoint); + undo_redo->create_action(TTR("Edit Polygon")); + selected_point = Vertex(insert.polygon, vertices.size()); + _action_set_polygon(insert.polygon, vertices); + _commit_action(); + return true; + } else { + edited_point = PosVertex(insert.polygon, insert.vertex + 1, xform.affine_inverse().xform(insert.pos)); + vertices.insert(edited_point.vertex, edited_point.pos); + pre_move_edit = vertices; + selected_point = Vertex(edited_point.polygon, edited_point.vertex); + edge_point = PosVertex(); + + undo_redo->create_action(TTR("Insert Point")); + _action_set_polygon(insert.polygon, vertices); + _commit_action(); + return true; + } } } } else { @@ -437,24 +434,28 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) canvas_item_editor->update_viewport(); } else if (mode == MODE_EDIT || (_is_line() && mode == MODE_CREATE)) { - const PosVertex onEdgeVertex = closest_edge_point(gpoint); - - if (onEdgeVertex.valid()) { - hover_point = Vertex(); - edge_point = onEdgeVertex; + const PosVertex new_hover_point = closest_point(gpoint); + if (hover_point != new_hover_point) { + hover_point = new_hover_point; canvas_item_editor->update_viewport(); - } else { - if (edge_point.valid()) { - edge_point = PosVertex(); - canvas_item_editor->update_viewport(); - } + } - const PosVertex new_hover_point = closest_point(gpoint); - if (hover_point != new_hover_point) { - hover_point = new_hover_point; + bool edge_hover = false; + if (!hover_point.valid()) { + const PosVertex on_edge_vertex = closest_edge_point(gpoint); + + if (on_edge_vertex.valid()) { + hover_point = Vertex(); + edge_point = on_edge_vertex; canvas_item_editor->update_viewport(); + edge_hover = true; } } + + if (!edge_hover && edge_point.valid()) { + edge_point = PosVertex(); + canvas_item_editor->update_viewport(); + } } } diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp index eec375cbea..fc220c56a8 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -301,7 +301,40 @@ void MeshInstance3DEditor::_menu_option(int p_option) { ur->commit_action(); } break; case MENU_OPTION_CREATE_UV2: { - Ref<PrimitiveMesh> primitive_mesh = Object::cast_to<PrimitiveMesh>(*node->get_mesh()); + Ref<Mesh> mesh2 = node->get_mesh(); + if (!mesh.is_valid()) { + err_dialog->set_text(TTR("No mesh to unwrap.")); + err_dialog->popup_centered(); + return; + } + + // Test if we are allowed to unwrap this mesh resource. + String path = mesh2->get_path(); + int srpos = path.find("::"); + if (srpos != -1) { + String base = path.substr(0, srpos); + if (ResourceLoader::get_resource_type(base) == "PackedScene") { + if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) { + err_dialog->set_text(TTR("Mesh cannot unwrap UVs because it does not belong to the edited scene. Make it unique first.")); + err_dialog->popup_centered(); + return; + } + } else { + if (FileAccess::exists(path + ".import")) { + err_dialog->set_text(TTR("Mesh cannot unwrap UVs because it belongs to another resource which was imported from another file type. Make it unique first.")); + err_dialog->popup_centered(); + return; + } + } + } else { + if (FileAccess::exists(path + ".import")) { + err_dialog->set_text(TTR("Mesh cannot unwrap UVs because it was imported from another file type. Make it unique first.")); + err_dialog->popup_centered(); + return; + } + } + + Ref<PrimitiveMesh> primitive_mesh = mesh2; if (primitive_mesh.is_valid()) { EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Unwrap UV2")); @@ -309,39 +342,40 @@ void MeshInstance3DEditor::_menu_option(int p_option) { ur->add_undo_method(*primitive_mesh, "set_add_uv2", primitive_mesh->get_add_uv2()); ur->commit_action(); } else { - Ref<ArrayMesh> mesh2 = node->get_mesh(); - if (!mesh2.is_valid()) { + Ref<ArrayMesh> array_mesh = mesh2; + if (!array_mesh.is_valid()) { err_dialog->set_text(TTR("Contained Mesh is not of type ArrayMesh.")); err_dialog->popup_centered(); return; } - String path = mesh2->get_path(); - int srpos = path.find("::"); - if (srpos != -1) { - String base = path.substr(0, srpos); - if (ResourceLoader::get_resource_type(base) == "PackedScene") { - if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) { - err_dialog->set_text(TTR("Mesh cannot unwrap UVs because it does not belong to the edited scene. Make it unique first.")); + // Preemptively evaluate common fail cases for lightmap unwrapping. + { + if (array_mesh->get_blend_shape_count() > 0) { + err_dialog->set_text(TTR("Can't unwrap mesh with blend shapes.")); + err_dialog->popup_centered(); + return; + } + + for (int i = 0; i < array_mesh->get_surface_count(); i++) { + Mesh::PrimitiveType primitive = array_mesh->surface_get_primitive_type(i); + + if (primitive != Mesh::PRIMITIVE_TRIANGLES) { + err_dialog->set_text(TTR("Only triangles are supported for lightmap unwrap.")); err_dialog->popup_centered(); return; } - } else { - if (FileAccess::exists(path + ".import")) { - err_dialog->set_text(TTR("Mesh cannot unwrap UVs because it belongs to another resource which was imported from another file type. Make it unique first.")); + + uint64_t format = array_mesh->surface_get_format(i); + if (format & Mesh::ArrayFormat::ARRAY_FORMAT_NORMAL) { + err_dialog->set_text(TTR("Normals are required for lightmap unwrap.")); err_dialog->popup_centered(); return; } } - } else { - if (FileAccess::exists(path + ".import")) { - err_dialog->set_text(TTR("Mesh cannot unwrap UVs because it was imported from another file type. Make it unique first.")); - err_dialog->popup_centered(); - return; - } } - Ref<ArrayMesh> unwrapped_mesh = mesh2->duplicate(false); + Ref<ArrayMesh> unwrapped_mesh = array_mesh->duplicate(false); Error err = unwrapped_mesh->lightmap_unwrap(node->get_global_transform()); if (err != OK) { @@ -355,9 +389,9 @@ void MeshInstance3DEditor::_menu_option(int p_option) { ur->add_do_method(node, "set_mesh", unwrapped_mesh); ur->add_do_reference(node); - ur->add_do_reference(mesh2.ptr()); + ur->add_do_reference(array_mesh.ptr()); - ur->add_undo_method(node, "set_mesh", mesh2); + ur->add_undo_method(node, "set_mesh", array_mesh); ur->add_undo_reference(unwrapped_mesh.ptr()); ur->commit_action(); diff --git a/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp b/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp index 9747ef4d48..5118f1d458 100644 --- a/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp +++ b/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp @@ -503,7 +503,11 @@ void NavigationObstacle3DEditor::edit(Node *p_node) { wip.clear(); wip_active = false; edited_point = -1; - p_node->add_child(point_lines_meshinstance); + if (point_lines_meshinstance->get_parent()) { + point_lines_meshinstance->reparent(p_node, false); + } else { + p_node->add_child(point_lines_meshinstance); + } _polygon_draw(); } else { diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 00567587ce..8141d18341 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -1170,7 +1170,7 @@ void Polygon2DEditor::_uv_draw() { found_child = true; - Transform2D bone_xform = node->get_global_transform().affine_inverse() * (skeleton->get_global_transform() * bone->get_skeleton_rest()); + Transform2D bone_xform = node->get_global_transform().affine_inverse().translated(-node->get_offset()) * (skeleton->get_global_transform() * bone->get_skeleton_rest()); Transform2D endpoint_xform = bone_xform * n->get_transform(); Color color = current ? Color(1, 1, 1) : Color(0.5, 0.5, 0.5); @@ -1180,7 +1180,7 @@ void Polygon2DEditor::_uv_draw() { if (!found_child) { //draw normally - Transform2D bone_xform = node->get_global_transform().affine_inverse() * (skeleton->get_global_transform() * bone->get_skeleton_rest()); + Transform2D bone_xform = node->get_global_transform().affine_inverse().translated(-node->get_offset()) * (skeleton->get_global_transform() * bone->get_skeleton_rest()); Transform2D endpoint_xform = bone_xform * Transform2D(0, Vector2(bone->get_length(), 0)); Color color = current ? Color(1, 1, 1) : Color(0.5, 0.5, 0.5); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 16d281d037..22596c09d1 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -2520,9 +2520,7 @@ void ScriptEditor::save_current_script() { // If built-in script, save the scene instead. const String scene_path = resource->get_path().get_slice("::", 0); if (!scene_path.is_empty()) { - Vector<String> scene_to_save; - scene_to_save.push_back(scene_path); - EditorNode::get_singleton()->save_scene_list(scene_to_save); + EditorNode::get_singleton()->save_scene_if_open(scene_path); } } else { EditorNode::get_singleton()->save_resource(resource); @@ -2534,7 +2532,7 @@ void ScriptEditor::save_current_script() { } void ScriptEditor::save_all_scripts() { - Vector<String> scenes_to_save; + HashSet<String> scenes_to_save; for (int i = 0; i < tab_container->get_tab_count(); i++) { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i)); @@ -2583,7 +2581,7 @@ void ScriptEditor::save_all_scripts() { // For built-in scripts, save their scenes instead. const String scene_path = edited_res->get_path().get_slice("::", 0); if (!scene_path.is_empty() && !scenes_to_save.has(scene_path)) { - scenes_to_save.push_back(scene_path); + scenes_to_save.insert(scene_path); } } } diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 20b91d8bfd..eeefd1c90d 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -871,7 +871,9 @@ void Skeleton3DEditor::_notification(int p_what) { skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_update_properties)); skeleton->set_transform_gizmo_visible(true); #endif - handles_mesh_instance->get_parent()->remove_child(handles_mesh_instance); + if (handles_mesh_instance->get_parent()) { + handles_mesh_instance->get_parent()->remove_child(handles_mesh_instance); + } } edit_mode_toggled(false); } break; diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 7968fdef55..2b7e10de2c 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -378,6 +378,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { break; } if (editor_selection->get_selected_node_list().size() > 1) { + if (!_validate_no_foreign()) { + break; + } rename_dialog->popup_centered(); } } break; @@ -388,6 +391,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } Tree *tree = scene_tree->get_scene_tree(); if (tree->is_anything_selected()) { + if (!_validate_no_foreign()) { + break; + } tree->grab_focus(); tree->edit_selected(); } @@ -2167,8 +2173,13 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) { } undo_redo->commit_action(); + // Avoid changing the currently edited object. + Object *edited_object = InspectorDock::get_inspector_singleton()->get_edited_object(); + _push_item(p_script.ptr()); _update_script_button(); + + InspectorDock::get_inspector_singleton()->edit(edited_object); } void SceneTreeDock::_shader_created(Ref<Shader> p_shader) { |
