summaryrefslogtreecommitdiffstats
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/code_editor.cpp4
-rw-r--r--editor/editor_help_search.cpp31
-rw-r--r--editor/editor_help_search.h1
-rw-r--r--editor/editor_node.cpp41
-rw-r--r--editor/editor_node.h3
-rw-r--r--editor/editor_themes.cpp4
-rw-r--r--editor/filesystem_dock.cpp42
-rw-r--r--editor/filesystem_dock.h6
-rw-r--r--editor/import/post_import_plugin_skeleton_renamer.cpp13
-rw-r--r--editor/import/resource_importer_scene.cpp6
-rw-r--r--editor/inspector_dock.cpp3
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp99
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.cpp78
-rw-r--r--editor/plugins/navigation_obstacle_3d_editor_plugin.cpp6
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/script_editor_plugin.cpp8
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp4
-rw-r--r--editor/scene_tree_dock.cpp11
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) {