summaryrefslogtreecommitdiffstats
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/animation_track_editor.cpp27
-rw-r--r--editor/code_editor.cpp3
-rw-r--r--editor/code_editor.h1
-rw-r--r--editor/connections_dialog.cpp1
-rw-r--r--editor/connections_dialog.h3
-rw-r--r--editor/debugger/script_editor_debugger.cpp2
-rw-r--r--editor/editor_file_system.cpp8
-rw-r--r--editor/editor_help.cpp18
-rw-r--r--editor/editor_inspector.cpp29
-rw-r--r--editor/editor_inspector.h3
-rw-r--r--editor/editor_node.cpp63
-rw-r--r--editor/editor_node.h1
-rw-r--r--editor/editor_plugin.cpp4
-rw-r--r--editor/editor_plugin.h1
-rw-r--r--editor/editor_run.cpp6
-rw-r--r--editor/editor_settings.cpp4
-rw-r--r--editor/editor_themes.cpp4
-rw-r--r--editor/export/export_template_manager.cpp2
-rw-r--r--editor/filesystem_dock.cpp30
-rw-r--r--editor/filesystem_dock.h2
-rw-r--r--editor/find_in_files.cpp2
-rw-r--r--editor/gui/editor_toaster.cpp2
-rw-r--r--editor/gui/editor_zoom_widget.cpp45
-rw-r--r--editor/gui/editor_zoom_widget.h7
-rw-r--r--editor/import/collada.cpp2
-rw-r--r--editor/import/post_import_plugin_skeleton_rest_fixer.cpp1
-rw-r--r--editor/import/resource_importer_shader_file.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp14
-rw-r--r--editor/plugins/debugger_editor_plugin.cpp14
-rw-r--r--editor/plugins/debugger_editor_plugin.h1
-rw-r--r--editor/plugins/editor_preview_plugins.cpp11
-rw-r--r--editor/plugins/script_editor_plugin.cpp10
-rw-r--r--editor/plugins/script_text_editor.cpp17
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/theme_editor_plugin.cpp114
-rw-r--r--editor/plugins/theme_editor_plugin.h15
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp2
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp5
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp2
-rw-r--r--editor/project_manager.cpp2
-rw-r--r--editor/scene_tree_dock.cpp18
41 files changed, 388 insertions, 112 deletions
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 919e335d21..c555ca2109 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -2695,18 +2695,25 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
AnimationPlayer *ap = ape->get_player();
if (ap) {
NodePath npath = animation->track_get_path(track);
- Node *nd = ap->get_node(ap->get_root_node())->get_node(NodePath(npath.get_concatenated_names()));
- StringName prop = npath.get_concatenated_subnames();
- PropertyInfo prop_info;
- ClassDB::get_property_info(nd->get_class(), prop, &prop_info);
+ Node *a_ap_root_node = ap->get_node(ap->get_root_node());
+ Node *nd = nullptr;
+ // We must test that we have a valid a_ap_root_node before trying to access its content to init the nd Node.
+ if (a_ap_root_node) {
+ nd = a_ap_root_node->get_node(NodePath(npath.get_concatenated_names()));
+ }
+ if (nd) {
+ StringName prop = npath.get_concatenated_subnames();
+ PropertyInfo prop_info;
+ ClassDB::get_property_info(nd->get_class(), prop, &prop_info);
#ifdef DISABLE_DEPRECATED
- bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.find("radians_as_degrees") != -1;
+ bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.find("radians_as_degrees") != -1;
#else
- bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.find("radians") != -1;
+ bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.find("radians") != -1;
#endif // DISABLE_DEPRECATED
- if (is_angle) {
- menu->add_icon_item(get_editor_theme_icon(SNAME("InterpLinearAngle")), TTR("Linear Angle"), MENU_INTERPOLATION_LINEAR_ANGLE);
- menu->add_icon_item(get_editor_theme_icon(SNAME("InterpCubicAngle")), TTR("Cubic Angle"), MENU_INTERPOLATION_CUBIC_ANGLE);
+ if (is_angle) {
+ menu->add_icon_item(get_editor_theme_icon(SNAME("InterpLinearAngle")), TTR("Linear Angle"), MENU_INTERPOLATION_LINEAR_ANGLE);
+ menu->add_icon_item(get_editor_theme_icon(SNAME("InterpCubicAngle")), TTR("Cubic Angle"), MENU_INTERPOLATION_CUBIC_ANGLE);
+ }
}
}
}
@@ -3903,7 +3910,7 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari
ERR_FAIL_NULL(root);
ERR_FAIL_COND(history->get_path_size() == 0);
Object *obj = ObjectDB::get_instance(history->get_path_object(0));
- ERR_FAIL_COND(!Object::cast_to<Node>(obj));
+ ERR_FAIL_NULL(Object::cast_to<Node>(obj));
// Let's build a node path.
Node *node = Object::cast_to<Node>(obj);
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 64467bc254..cd6f672b4b 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -951,6 +951,8 @@ void CodeTextEditor::_complete_request() {
font_color = get_theme_color(e.theme_color_name, SNAME("Editor"));
} else if (e.insert_text.begins_with("\"") || e.insert_text.begins_with("\'")) {
font_color = completion_string_color;
+ } else if (e.insert_text.begins_with("##") || e.insert_text.begins_with("///")) {
+ font_color = completion_doc_comment_color;
} else if (e.insert_text.begins_with("#") || e.insert_text.begins_with("//")) {
font_color = completion_comment_color;
}
@@ -1026,6 +1028,7 @@ void CodeTextEditor::update_editor_settings() {
completion_font_color = EDITOR_GET("text_editor/theme/highlighting/completion_font_color");
completion_string_color = EDITOR_GET("text_editor/theme/highlighting/string_color");
completion_comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
+ completion_doc_comment_color = EDITOR_GET("text_editor/theme/highlighting/doc_comment_color");
// Appearance: Caret
text_editor->set_caret_type((TextEdit::CaretType)EDITOR_GET("text_editor/appearance/caret/type").operator int());
diff --git a/editor/code_editor.h b/editor/code_editor.h
index c18154a1ef..43173bd475 100644
--- a/editor/code_editor.h
+++ b/editor/code_editor.h
@@ -188,6 +188,7 @@ class CodeTextEditor : public VBoxContainer {
Color completion_font_color;
Color completion_string_color;
Color completion_comment_color;
+ Color completion_doc_comment_color;
CodeTextEditorCodeCompleteFunc code_complete_func;
void *code_complete_ud = nullptr;
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 662356378d..fcaec600b5 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -32,7 +32,6 @@
#include "core/config/project_settings.h"
#include "core/templates/hash_set.h"
-#include "editor/doc_tools.h"
#include "editor/editor_help.h"
#include "editor/editor_inspector.h"
#include "editor/editor_node.h"
diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h
index 7316a770ec..2fd4778389 100644
--- a/editor/connections_dialog.h
+++ b/editor/connections_dialog.h
@@ -187,8 +187,7 @@ public:
//////////////////////////////////////////
-// Custom Tree needed to use a RichTextLabel as tooltip control
-// when display signal documentation.
+// Custom `Tree` needed to use `EditorHelpTooltip` to display signal documentation.
class ConnectionsDockTree : public Tree {
virtual Control *make_custom_tooltip(const String &p_text) const;
};
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index 6cdcf1a6d0..ab8df824e8 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -1605,7 +1605,7 @@ void ScriptEditorDebugger::_breakpoints_item_rmb_selected(const Vector2 &p_pos,
breakpoints_menu->add_icon_item(get_editor_theme_icon(SNAME("Remove")), TTR("Delete All Breakpoints in:") + " " + file, ACTION_DELETE_BREAKPOINTS_IN_FILE);
breakpoints_menu->add_icon_item(get_editor_theme_icon(SNAME("Remove")), TTR("Delete All Breakpoints"), ACTION_DELETE_ALL_BREAKPOINTS);
- breakpoints_menu->set_position(breakpoints_tree->get_global_position() + p_pos);
+ breakpoints_menu->set_position(get_screen_position() + get_local_mouse_position());
breakpoints_menu->popup();
}
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 41616d50cd..db54179633 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -2510,17 +2510,13 @@ bool EditorFileSystem::_scan_extensions() {
bool needs_restart = false;
for (int i = 0; i < extensions_added.size(); i++) {
GDExtensionManager::LoadStatus st = GDExtensionManager::get_singleton()->load_extension(extensions_added[i]);
- if (st == GDExtensionManager::LOAD_STATUS_FAILED) {
- EditorNode::get_singleton()->add_io_error("Error loading extension: " + extensions_added[i]);
- } else if (st == GDExtensionManager::LOAD_STATUS_NEEDS_RESTART) {
+ if (st == GDExtensionManager::LOAD_STATUS_NEEDS_RESTART) {
needs_restart = true;
}
}
for (int i = 0; i < extensions_removed.size(); i++) {
GDExtensionManager::LoadStatus st = GDExtensionManager::get_singleton()->unload_extension(extensions_removed[i]);
- if (st == GDExtensionManager::LOAD_STATUS_FAILED) {
- EditorNode::get_singleton()->add_io_error("Error removing extension: " + extensions_added[i]);
- } else if (st == GDExtensionManager::LOAD_STATUS_NEEDS_RESTART) {
+ if (st == GDExtensionManager::LOAD_STATUS_NEEDS_RESTART) {
needs_restart = true;
}
}
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 6004591bb2..6e3b5b7b9e 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -2264,7 +2264,12 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, Control
p_rt->push_strikethrough();
pos = brk_end + 1;
tag_stack.push_front(tag);
-
+ } else if (tag == "lb") {
+ p_rt->add_text("[");
+ pos = brk_end + 1;
+ } else if (tag == "rb") {
+ p_rt->add_text("]");
+ pos = brk_end + 1;
} else if (tag == "url") {
int end = bbcode.find("[", brk_end);
if (end == -1) {
@@ -2850,7 +2855,7 @@ void EditorHelpTooltip::_notification(int p_what) {
// `p_text` is expected to be something like these:
// - `class|Control||`;
// - `property|Control|size|`;
-// - `signal|Control|gui_input|(event: InputEvent)`
+// - `signal|Control|gui_input|(event: InputEvent)`.
void EditorHelpTooltip::parse_tooltip(const String &p_text) {
tooltip_text = p_text;
@@ -2875,7 +2880,11 @@ void EditorHelpTooltip::parse_tooltip(const String &p_text) {
if (type == "property") {
description = get_property_description(class_name, property_name);
- formatted_text = TTR("Property:");
+ if (property_name.begins_with("metadata/")) {
+ formatted_text = TTR("Metadata:");
+ } else {
+ formatted_text = TTR("Property:");
+ }
} else if (type == "method") {
description = get_method_description(class_name, property_name);
formatted_text = TTR("Method:");
@@ -2890,7 +2899,8 @@ void EditorHelpTooltip::parse_tooltip(const String &p_text) {
}
}
- formatted_text += " [u][b]" + title + "[/b][/u]" + property_args + "\n";
+ // Metadata special handling replaces "Property:" with "Metadata": above.
+ formatted_text += " [u][b]" + title.trim_prefix("metadata/") + "[/b][/u]" + property_args.replace("[", "[lb]") + "\n";
formatted_text += description.is_empty() ? "[i]" + TTR("No description available.") + "[/i]" : description;
set_text(formatted_text);
}
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 395f4faa39..e1a7d8f111 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -906,12 +906,24 @@ void EditorProperty::_update_pin_flags() {
}
Control *EditorProperty::make_custom_tooltip(const String &p_text) const {
- EditorHelpTooltip *tooltip = memnew(EditorHelpTooltip(p_text));
+ EditorHelpBit *tooltip = nullptr;
+
+ if (has_doc_tooltip) {
+ tooltip = memnew(EditorHelpTooltip(p_text));
+ }
if (object->has_method("_get_property_warning")) {
String warn = object->call("_get_property_warning", property);
if (!warn.is_empty()) {
- tooltip->set_text(tooltip->get_rich_text()->get_text() + "\n[b][color=" + get_theme_color(SNAME("warning_color")).to_html(false) + "]" + warn + "[/color][/b]");
+ String prev_text;
+ if (tooltip == nullptr) {
+ tooltip = memnew(EditorHelpBit());
+ tooltip->set_text(p_text);
+ tooltip->get_rich_text()->set_custom_minimum_size(Size2(360 * EDSCALE, 0));
+ } else {
+ prev_text = tooltip->get_rich_text()->get_text() + "\n";
+ }
+ tooltip->set_text(prev_text + "[b][color=" + get_theme_color(SNAME("warning_color")).to_html(false) + "]" + warn + "[/color][/b]");
}
}
@@ -1148,8 +1160,7 @@ void EditorInspectorCategory::_notification(int p_what) {
}
Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) const {
- // Far from perfect solution, as there's nothing that prevents a category from having a name that starts with that.
- return p_text.begins_with("class|") ? memnew(EditorHelpTooltip(p_text)) : nullptr;
+ return doc_class_name.is_empty() ? nullptr : memnew(EditorHelpTooltip(p_text));
}
Size2 EditorInspectorCategory::get_minimum_size() const {
@@ -3316,6 +3327,7 @@ void EditorInspector::update_tree() {
} else {
ep->set_tooltip_text("theme_item|" + classname + "|" + theme_item_name + "|");
}
+ ep->has_doc_tooltip = true;
}
ep->set_doc_path(doc_path);
@@ -3391,11 +3403,16 @@ Object *EditorInspector::get_edited_object() {
return object;
}
+Object *EditorInspector::get_next_edited_object() {
+ return next_object;
+}
+
void EditorInspector::edit(Object *p_object) {
if (object == p_object) {
return;
}
+ next_object = p_object; // Some plugins need to know the next edited object when clearing the inspector.
if (object) {
_clear();
object->disconnect("property_list_changed", callable_mp(this, &EditorInspector::_changed_callback));
@@ -3412,6 +3429,10 @@ void EditorInspector::edit(Object *p_object) {
object->connect("property_list_changed", callable_mp(this, &EditorInspector::_changed_callback));
update_tree();
}
+
+ // Keep it available until the end so it works with both main and sub inspectors.
+ next_object = nullptr;
+
emit_signal(SNAME("edited_object_changed"));
}
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index b5f0cec80b..e36606c080 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -74,6 +74,7 @@ private:
StringName property;
String property_path;
String doc_path;
+ bool has_doc_tooltip = false;
int property_usage;
@@ -473,6 +474,7 @@ class EditorInspector : public ScrollContainer {
void _clear(bool p_hide_plugins = true);
Object *object = nullptr;
+ Object *next_object = nullptr;
//
@@ -576,6 +578,7 @@ public:
void update_property(const String &p_prop);
void edit(Object *p_object);
Object *get_edited_object();
+ Object *get_next_edited_object();
void set_keying(bool p_active);
void set_read_only(bool p_read_only);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 0037b356d0..665e609cb0 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -790,7 +790,7 @@ void EditorNode::_notification(int p_what) {
}
void EditorNode::_update_update_spinner() {
- update_spinner->set_visible(EDITOR_GET("interface/editor/show_update_spinner"));
+ update_spinner->set_visible(!RenderingServer::get_singleton()->canvas_item_get_debug_redraw() && EDITOR_GET("interface/editor/show_update_spinner"));
const bool update_continuously = EDITOR_GET("interface/editor/update_continuously");
PopupMenu *update_popup = update_spinner->get_popup();
@@ -851,6 +851,10 @@ void EditorNode::_plugin_over_edit(EditorPlugin *p_plugin, Object *p_object) {
}
}
+void EditorNode::_plugin_over_self_own(EditorPlugin *p_plugin) {
+ active_plugins[p_plugin->get_instance_id()].insert(p_plugin);
+}
+
void EditorNode::_resources_changed(const Vector<String> &p_resources) {
List<Ref<Resource>> changed;
@@ -2135,7 +2139,12 @@ void EditorNode::edit_item(Object *p_object, Object *p_editing_owner) {
for (EditorPlugin *plugin : active_plugins[owner_id]) {
if (!available_plugins.has(plugin)) {
to_remove.push_back(plugin);
- _plugin_over_edit(plugin, nullptr);
+ if (plugin->can_auto_hide()) {
+ _plugin_over_edit(plugin, nullptr);
+ } else {
+ // If plugin can't be hidden, make it own itself and become responsible for closing.
+ _plugin_over_self_own(plugin);
+ }
}
}
@@ -2151,6 +2160,12 @@ void EditorNode::edit_item(Object *p_object, Object *p_editing_owner) {
continue;
}
+ if (active_plugins.has(plugin->get_instance_id())) {
+ // Plugin is already active, but as self-owning, so it needs a separate check.
+ plugin->edit(p_object);
+ continue;
+ }
+
// If plugin is already associated with another owner, remove it from there first.
for (KeyValue<ObjectID, HashSet<EditorPlugin *>> &kv : active_plugins) {
if (kv.key != owner_id) {
@@ -2214,7 +2229,11 @@ void EditorNode::hide_unused_editors(const Object *p_editing_owner) {
if (p_editing_owner) {
const ObjectID id = p_editing_owner->get_instance_id();
for (EditorPlugin *plugin : active_plugins[id]) {
- _plugin_over_edit(plugin, nullptr);
+ if (plugin->can_auto_hide()) {
+ _plugin_over_edit(plugin, nullptr);
+ } else {
+ _plugin_over_self_own(plugin);
+ }
}
active_plugins.erase(id);
} else {
@@ -2222,10 +2241,23 @@ void EditorNode::hide_unused_editors(const Object *p_editing_owner) {
// This is to sweep properties that were removed from the inspector.
List<ObjectID> to_remove;
for (KeyValue<ObjectID, HashSet<EditorPlugin *>> &kv : active_plugins) {
- if (!ObjectDB::get_instance(kv.key)) {
+ const Object *context = ObjectDB::get_instance(kv.key);
+ if (context) {
+ // In case of self-owning plugins, they are disabled here if they can auto hide.
+ const EditorPlugin *self_owning = Object::cast_to<EditorPlugin>(context);
+ if (self_owning && self_owning->can_auto_hide()) {
+ context = nullptr;
+ }
+ }
+
+ if (!context) {
to_remove.push_back(kv.key);
for (EditorPlugin *plugin : kv.value) {
- _plugin_over_edit(plugin, nullptr);
+ if (plugin->can_auto_hide()) {
+ _plugin_over_edit(plugin, nullptr);
+ } else {
+ _plugin_over_self_own(plugin);
+ }
}
}
}
@@ -3700,16 +3732,6 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
Error err;
Ref<PackedScene> sdata = ResourceLoader::load(lpath, "", ResourceFormatLoader::CACHE_MODE_REPLACE, &err);
- if (!sdata.is_valid()) {
- _dialog_display_load_error(lpath, err);
- opening_prev = false;
-
- if (prev != -1) {
- _set_current_scene(prev);
- editor_data.remove_scene(idx);
- }
- return ERR_FILE_NOT_FOUND;
- }
if (!p_ignore_broken_deps && dependency_errors.has(lpath)) {
current_menu_option = -1;
@@ -3727,6 +3749,17 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
return ERR_FILE_MISSING_DEPENDENCIES;
}
+ if (!sdata.is_valid()) {
+ _dialog_display_load_error(lpath, err);
+ opening_prev = false;
+
+ if (prev != -1) {
+ _set_current_scene(prev);
+ editor_data.remove_scene(idx);
+ }
+ return ERR_FILE_NOT_FOUND;
+ }
+
dependency_errors.erase(lpath); // At least not self path.
for (KeyValue<String, HashSet<String>> &E : dependency_errors) {
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 72134e283b..4e36c19e96 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -550,6 +550,7 @@ private:
void _remove_plugin_from_enabled(const String &p_name);
void _plugin_over_edit(EditorPlugin *p_plugin, Object *p_object);
+ void _plugin_over_self_own(EditorPlugin *p_plugin);
void _fs_changed();
void _resources_reimported(const Vector<String> &p_resources);
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 2726a781b4..b43e7eba9c 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -335,6 +335,10 @@ bool EditorPlugin::handles(Object *p_object) const {
return success;
}
+bool EditorPlugin::can_auto_hide() const {
+ return true;
+}
+
Dictionary EditorPlugin::get_state() const {
Dictionary state;
GDVIRTUAL_CALL(_get_state, state);
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 62ed432ecc..8870ef425e 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -178,6 +178,7 @@ public:
virtual void selected_notify() {} //notify that it was raised by the user, not the editor
virtual void edit(Object *p_object);
virtual bool handles(Object *p_object) const;
+ virtual bool can_auto_hide() const;
virtual Dictionary get_state() const; //save editor state so it can't be reloaded when reloading scene
virtual void set_state(const Dictionary &p_state); //restore editor state (likely was saved with the scene)
virtual void clear(); // clear any temporary data in the editor, reset it (likely new scene or load another scene)
diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp
index 42cd858581..00db344b6a 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -110,6 +110,8 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
bool debug_paths = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_paths", false);
bool debug_navigation = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_navigation", false);
bool debug_avoidance = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_avoidance", false);
+ bool debug_canvas_redraw = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_canvas_redraw", false);
+
if (debug_collisions) {
args.push_back("--debug-collisions");
}
@@ -126,6 +128,10 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
args.push_back("--debug-avoidance");
}
+ if (debug_canvas_redraw) {
+ args.push_back("--debug-canvas-item-redraw");
+ }
+
if (p_write_movie != "") {
args.push_back("--write-movie");
args.push_back(p_write_movie);
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 89a94fe0da..1eaeee97a5 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -519,6 +519,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "filesystem/import/blender/rpc_server_uptime", 5, "0,300,1,or_greater,suffix:s", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/import/fbx/fbx2gltf_path", "", "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ // Tools (denoise)
+ EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/tools/oidn/oidn_denoise_path", "", "", PROPERTY_USAGE_DEFAULT)
+
/* Docks */
// SceneTree
@@ -821,6 +824,7 @@ void EditorSettings::_load_godot2_text_editor_theme() {
_initial_set("text_editor/theme/highlighting/engine_type_color", Color(0.51, 0.83, 1.0));
_initial_set("text_editor/theme/highlighting/user_type_color", Color(0.42, 0.67, 0.93));
_initial_set("text_editor/theme/highlighting/comment_color", Color(0.4, 0.4, 0.4));
+ _initial_set("text_editor/theme/highlighting/doc_comment_color", Color(0.5, 0.6, 0.7));
_initial_set("text_editor/theme/highlighting/string_color", Color(0.94, 0.43, 0.75));
_initial_set("text_editor/theme/highlighting/background_color", Color(0.13, 0.12, 0.15));
_initial_set("text_editor/theme/highlighting/completion_background_color", Color(0.17, 0.16, 0.2));
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 0e7525875d..f5be91c6de 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -2215,7 +2215,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// adaptive script theme constants
// for comments and elements with lower relevance
- const Color dim_color = Color(font_color.r, font_color.g, font_color.b, 0.5);
+ const Color dim_color = Color(font_color, 0.5);
const float mono_value = mono_color.r;
const Color alpha1 = Color(mono_value, mono_value, mono_value, 0.07);
@@ -2229,6 +2229,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color engine_type_color = dark_theme ? Color(0.56, 1, 0.86) : Color(0.11, 0.55, 0.4);
const Color user_type_color = dark_theme ? Color(0.78, 1, 0.93) : Color(0.18, 0.45, 0.4);
const Color comment_color = dark_theme ? dim_color : Color(0.08, 0.08, 0.08, 0.5);
+ const Color doc_comment_color = dark_theme ? Color(0.6, 0.7, 0.8, 0.8) : Color(0.15, 0.15, 0.4, 0.7);
const Color string_color = dark_theme ? Color(1, 0.93, 0.63) : Color(0.6, 0.42, 0);
// Use the brightest background color on a light theme (which generally uses a negative contrast rate).
@@ -2272,6 +2273,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
setting->set_initial_value("text_editor/theme/highlighting/engine_type_color", engine_type_color, true);
setting->set_initial_value("text_editor/theme/highlighting/user_type_color", user_type_color, true);
setting->set_initial_value("text_editor/theme/highlighting/comment_color", comment_color, true);
+ setting->set_initial_value("text_editor/theme/highlighting/doc_comment_color", doc_comment_color, true);
setting->set_initial_value("text_editor/theme/highlighting/string_color", string_color, true);
setting->set_initial_value("text_editor/theme/highlighting/background_color", te_background_color, true);
setting->set_initial_value("text_editor/theme/highlighting/completion_background_color", completion_background_color, true);
diff --git a/editor/export/export_template_manager.cpp b/editor/export/export_template_manager.cpp
index 3a034c8dcc..26ed7c46fb 100644
--- a/editor/export/export_template_manager.cpp
+++ b/editor/export/export_template_manager.cpp
@@ -686,7 +686,7 @@ Error ExportTemplateManager::install_android_template_from_file(const String &p_
zlib_filefunc_def io = zipio_create_io(&io_fa);
unzFile pkg = unzOpen2(p_file.utf8().get_data(), &io);
- ERR_FAIL_COND_V_MSG(!pkg, ERR_CANT_OPEN, "Android sources not in ZIP format.");
+ ERR_FAIL_NULL_V_MSG(pkg, ERR_CANT_OPEN, "Android sources not in ZIP format.");
int ret = unzGoToFirstFile(pkg);
int total_files = 0;
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index be06a3932c..fb4f5efc25 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1729,12 +1729,12 @@ void FileSystemDock::_folder_removed(String p_folder) {
void FileSystemDock::_rename_operation_confirm() {
String new_name;
- TreeItem *s = tree->get_selected();
- int col_index = tree->get_selected_column();
+ TreeItem *ti = tree->get_edited();
+ int col_index = tree->get_edited_column();
- if (tree->has_focus()) {
- new_name = s->get_text(col_index).strip_edges();
- } else if (files->has_focus()) {
+ if (ti) {
+ new_name = ti->get_text(col_index).strip_edges();
+ } else {
new_name = files->get_edit_text().strip_edges();
}
String old_name = to_rename.is_file ? to_rename.path.get_file() : to_rename.path.left(-1).get_file();
@@ -1757,10 +1757,10 @@ void FileSystemDock::_rename_operation_confirm() {
}
// Restore original name.
- if (rename_error && tree->has_focus()) {
- s->set_text(col_index, old_name);
- return;
- } else if (rename_error && files->has_focus()) {
+ if (rename_error) {
+ if (ti) {
+ ti->set_text(col_index, old_name);
+ }
return;
}
@@ -1783,7 +1783,7 @@ void FileSystemDock::_rename_operation_confirm() {
if (da->file_exists(new_path) || da->dir_exists(new_path)) {
#endif
EditorNode::get_singleton()->show_warning(TTR("A file or folder with this name already exists."));
- s->set_text(col_index, old_name);
+ ti->set_text(col_index, old_name);
return;
}
@@ -1803,7 +1803,7 @@ void FileSystemDock::_rename_operation_confirm() {
EditorSceneTabs::get_singleton()->set_current_tab(current_tab);
- if (tree->has_focus()) {
+ if (ti) {
current_path = new_path;
current_path_line_edit->set_text(current_path);
}
@@ -2004,13 +2004,13 @@ void FileSystemDock::_before_move(HashMap<String, ResourceUID::ID> &r_uids, Vect
EditorNode::get_singleton()->save_scene_list(r_file_owners);
}
-Vector<String> FileSystemDock::_tree_get_selected(bool remove_self_inclusion) const {
+Vector<String> FileSystemDock::_tree_get_selected(bool remove_self_inclusion, bool p_include_unselected_cursor) const {
// Build a list of selected items with the active one at the first position.
Vector<String> selected_strings;
TreeItem *favorites_item = tree->get_root()->get_first_child();
TreeItem *cursor_item = tree->get_selected();
- if (cursor_item && cursor_item->is_selected(0) && cursor_item != favorites_item) {
+ if (cursor_item && (p_include_unselected_cursor || cursor_item->is_selected(0)) && cursor_item != favorites_item) {
selected_strings.push_back(cursor_item->get_metadata(0));
}
@@ -2059,6 +2059,10 @@ void FileSystemDock::_tree_rmb_option(int p_option) {
tree->get_selected()->set_collapsed_recursive(p_option == FOLDER_COLLAPSE_ALL);
}
} break;
+ case FILE_RENAME: {
+ selected_strings = _tree_get_selected(false, true);
+ [[fallthrough]];
+ }
default: {
_file_option(p_option, selected_strings);
} break;
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 1e04b6a4ff..104def71c8 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -351,7 +351,7 @@ private:
void _update_display_mode(bool p_force = false);
- Vector<String> _tree_get_selected(bool remove_self_inclusion = true) const;
+ Vector<String> _tree_get_selected(bool remove_self_inclusion = true, bool p_include_unselected_cursor = false) const;
bool _is_file_type_disabled_by_feature_profile(const StringName &p_class);
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index 5506f4a6bc..a14df01858 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -604,6 +604,8 @@ FindInFilesPanel::FindInFilesPanel() {
_results_display->set_select_mode(Tree::SELECT_ROW);
_results_display->set_allow_rmb_select(true);
_results_display->set_allow_reselect(true);
+ _results_display->add_theme_constant_override("inner_item_margin_left", 0);
+ _results_display->add_theme_constant_override("inner_item_margin_right", 0);
_results_display->create_item(); // Root
vbc->add_child(_results_display);
diff --git a/editor/gui/editor_toaster.cpp b/editor/gui/editor_toaster.cpp
index 0d468bc0a3..1abb591508 100644
--- a/editor/gui/editor_toaster.cpp
+++ b/editor/gui/editor_toaster.cpp
@@ -149,7 +149,7 @@ void EditorToaster::_notification(int p_what) {
void EditorToaster::_error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, bool p_editor_notify, ErrorHandlerType p_type) {
// This may be called from a thread. Since we will deal with non-thread-safe elements,
// we have to put it in the queue for safety.
- callable_mp_static(&EditorToaster::_error_handler_impl).bind(p_file, p_line, p_error, p_errorexp, p_editor_notify, p_type).call_deferred();
+ callable_mp_static(&EditorToaster::_error_handler_impl).bind(String::utf8(p_file), p_line, String::utf8(p_error), String::utf8(p_errorexp), p_editor_notify, p_type).call_deferred();
}
void EditorToaster::_error_handler_impl(const String &p_file, int p_line, const String &p_error, const String &p_errorexp, bool p_editor_notify, int p_type) {
diff --git a/editor/gui/editor_zoom_widget.cpp b/editor/gui/editor_zoom_widget.cpp
index e292dc99ac..5c936a75f2 100644
--- a/editor/gui/editor_zoom_widget.cpp
+++ b/editor/gui/editor_zoom_widget.cpp
@@ -70,12 +70,36 @@ float EditorZoomWidget::get_zoom() {
}
void EditorZoomWidget::set_zoom(float p_zoom) {
- if (p_zoom > 0 && p_zoom != zoom) {
- zoom = p_zoom;
+ float new_zoom = CLAMP(p_zoom, min_zoom, max_zoom);
+ if (zoom != new_zoom) {
+ zoom = new_zoom;
_update_zoom_label();
}
}
+float EditorZoomWidget::get_min_zoom() {
+ return min_zoom;
+}
+
+float EditorZoomWidget::get_max_zoom() {
+ return max_zoom;
+}
+
+void EditorZoomWidget::setup_zoom_limits(float p_min, float p_max) {
+ ERR_FAIL_COND(p_min < 0 || p_min > p_max);
+
+ min_zoom = p_min;
+ max_zoom = p_max;
+
+ if (zoom > max_zoom) {
+ set_zoom(max_zoom);
+ emit_signal(SNAME("zoom_changed"), zoom);
+ } else if (zoom < min_zoom) {
+ set_zoom(min_zoom);
+ emit_signal(SNAME("zoom_changed"), zoom);
+ }
+}
+
void EditorZoomWidget::set_zoom_by_increments(int p_increment_count, bool p_integer_only) {
// Remove editor scale from the index computation.
const float zoom_noscale = zoom / MAX(1, EDSCALE);
@@ -97,7 +121,7 @@ void EditorZoomWidget::set_zoom_by_increments(int p_increment_count, bool p_inte
}
} else {
if (p_increment_count >= 1) {
- // Zooming. Convert the current zoom into a denominator.
+ // Zooming in. Convert the current zoom into a denominator.
float new_zoom = 1.0 / Math::ceil(1.0 / zoom_noscale - p_increment_count);
if (Math::is_equal_approx(zoom_noscale, new_zoom)) {
// New zoom is identical to the old zoom, so try again.
@@ -106,7 +130,7 @@ void EditorZoomWidget::set_zoom_by_increments(int p_increment_count, bool p_inte
}
set_zoom(new_zoom * MAX(1, EDSCALE));
} else {
- // Dezooming. Convert the current zoom into a denominator.
+ // Zooming out. Convert the current zoom into a denominator.
float new_zoom = 1.0 / Math::floor(1.0 / zoom_noscale - p_increment_count);
if (Math::is_equal_approx(zoom_noscale, new_zoom)) {
// New zoom is identical to the old zoom, so try again.
@@ -118,9 +142,9 @@ void EditorZoomWidget::set_zoom_by_increments(int p_increment_count, bool p_inte
}
} else {
// Base increment factor defined as the twelveth root of two.
- // This allow a smooth geometric evolution of the zoom, with the advantage of
+ // This allows for a smooth geometric evolution of the zoom, with the advantage of
// visiting all integer power of two scale factors.
- // note: this is analogous to the 'semitones' interval in the music world
+ // Note: this is analogous to the 'semitone' interval in the music world
// In order to avoid numerical imprecisions, we compute and edit a zoom index
// with the following relation: zoom = 2 ^ (index / 12)
@@ -179,10 +203,11 @@ EditorZoomWidget::EditorZoomWidget() {
zoom_reset = memnew(Button);
zoom_reset->set_flat(true);
- zoom_reset->add_theme_style_override("normal", memnew(StyleBoxEmpty));
- zoom_reset->add_theme_style_override("hover", memnew(StyleBoxEmpty));
- zoom_reset->add_theme_style_override("focus", memnew(StyleBoxEmpty));
- zoom_reset->add_theme_style_override("pressed", memnew(StyleBoxEmpty));
+ Ref<StyleBoxEmpty> empty_stylebox = memnew(StyleBoxEmpty);
+ zoom_reset->add_theme_style_override("normal", empty_stylebox);
+ zoom_reset->add_theme_style_override("hover", empty_stylebox);
+ zoom_reset->add_theme_style_override("focus", empty_stylebox);
+ zoom_reset->add_theme_style_override("pressed", empty_stylebox);
add_child(zoom_reset);
zoom_reset->add_theme_constant_override("outline_size", Math::ceil(2 * EDSCALE));
zoom_reset->add_theme_color_override("font_outline_color", Color(0, 0, 0));
diff --git a/editor/gui/editor_zoom_widget.h b/editor/gui/editor_zoom_widget.h
index be54043d93..6b2fe4d3e9 100644
--- a/editor/gui/editor_zoom_widget.h
+++ b/editor/gui/editor_zoom_widget.h
@@ -42,6 +42,8 @@ class EditorZoomWidget : public HBoxContainer {
Button *zoom_plus = nullptr;
float zoom = 1.0;
+ float min_zoom = 1.0 / 128;
+ float max_zoom = 128.0;
void _update_zoom_label();
void _button_zoom_minus();
void _button_zoom_reset();
@@ -57,6 +59,11 @@ public:
float get_zoom();
void set_zoom(float p_zoom);
void set_zoom_by_increments(int p_increment_count, bool p_integer_only = false);
+
+ float get_min_zoom();
+ float get_max_zoom();
+ // It's best to setup simultaneously, so min < max can be checked easily.
+ void setup_zoom_limits(float p_min, float p_max);
// Sets the shortcut context for the zoom buttons. By default their context is this EditorZoomWidget control.
void set_shortcut_context(Node *p_node) const;
};
diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp
index d27b0aea40..be63973ea7 100644
--- a/editor/import/collada.cpp
+++ b/editor/import/collada.cpp
@@ -2197,7 +2197,7 @@ bool Collada::_move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, L
ERR_FAIL_COND_V(!state.scene_map.has(nodeid), false); //weird, it should have it...
NodeJoint *nj = dynamic_cast<NodeJoint *>(state.scene_map[nodeid]);
ERR_FAIL_NULL_V(nj, false);
- ERR_FAIL_COND_V(!nj->owner, false); //weird, node should have a skeleton owner
+ ERR_FAIL_NULL_V(nj->owner, false); // Weird, node should have a skeleton owner.
NodeSkeleton *sk = nj->owner;
diff --git a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp
index cd31499b80..3390bf4ed4 100644
--- a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp
+++ b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp
@@ -242,6 +242,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
if (rot_track == -1) {
int track = anim->add_track(Animation::TYPE_ROTATION_3D);
anim->track_set_path(track, insert_path);
+ anim->track_set_imported(track, true);
anim->rotation_track_insert_key(track, 0, src_skeleton->get_bone_rest(src_idx).basis.get_rotation_quaternion());
}
}
diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp
index 1275e5b85a..bde2e3d0bf 100644
--- a/editor/import/resource_importer_shader_file.cpp
+++ b/editor/import/resource_importer_shader_file.cpp
@@ -96,7 +96,7 @@ Error ResourceImporterShaderFile::import(const String &p_source_file, const Stri
Error err;
Ref<FileAccess> file = FileAccess::open(p_source_file, FileAccess::READ, &err);
ERR_FAIL_COND_V(err != OK, ERR_CANT_OPEN);
- ERR_FAIL_COND_V(!file.operator->(), ERR_CANT_OPEN);
+ ERR_FAIL_COND_V(!file.is_valid(), ERR_CANT_OPEN);
String file_txt = file->get_as_utf8_string();
Ref<RDShaderFile> shader_file;
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 4bfa6adaae..55d45fdd2e 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -60,11 +60,6 @@
#include "scene/resources/packed_scene.h"
#include "scene/resources/style_box_texture.h"
-// Min and Max are power of two in order to play nicely with successive increment.
-// That way, we can naturally reach a 100% zoom from boundaries.
-constexpr real_t MIN_ZOOM = 1. / 128;
-constexpr real_t MAX_ZOOM = 128;
-
#define RULER_WIDTH (15 * EDSCALE)
constexpr real_t SCALE_HANDLE_DISTANCE = 25;
constexpr real_t MOVE_HANDLE_DISTANCE = 25;
@@ -4115,10 +4110,9 @@ void CanvasItemEditor::_update_scroll(real_t) {
}
void CanvasItemEditor::_zoom_on_position(real_t p_zoom, Point2 p_position) {
- p_zoom = CLAMP(p_zoom, MIN_ZOOM, MAX_ZOOM);
+ p_zoom = CLAMP(p_zoom, zoom_widget->get_min_zoom(), zoom_widget->get_max_zoom());
if (p_zoom == zoom) {
- zoom_widget->set_zoom(p_zoom);
return;
}
@@ -4128,12 +4122,12 @@ void CanvasItemEditor::_zoom_on_position(real_t p_zoom, Point2 p_position) {
view_offset += p_position / prev_zoom - p_position / zoom;
// We want to align in-scene pixels to screen pixels, this prevents blurry rendering
- // in small details (texts, lines).
+ // of small details (texts, lines).
// This correction adds a jitter movement when zooming, so we correct only when the
// zoom factor is an integer. (in the other cases, all pixels won't be aligned anyway)
const real_t closest_zoom_factor = Math::round(zoom);
if (Math::is_zero_approx(zoom - closest_zoom_factor)) {
- // make sure scene pixel at view_offset is aligned on a screen pixel
+ // Make sure scene pixel at view_offset is aligned on a screen pixel.
Vector2 view_offset_int = view_offset.floor();
Vector2 view_offset_frac = view_offset - view_offset_int;
view_offset = view_offset_int + (view_offset_frac * closest_zoom_factor).round() / closest_zoom_factor;
@@ -5147,9 +5141,9 @@ CanvasItemEditor::CanvasItemEditor() {
button_center_view->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(VIEW_CENTER_TO_SELECTION));
zoom_widget = memnew(EditorZoomWidget);
- controls_hb->add_child(zoom_widget);
zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE);
zoom_widget->set_shortcut_context(this);
+ controls_hb->add_child(zoom_widget);
zoom_widget->connect("zoom_changed", callable_mp(this, &CanvasItemEditor::_update_zoom));
panner.instantiate();
diff --git a/editor/plugins/debugger_editor_plugin.cpp b/editor/plugins/debugger_editor_plugin.cpp
index 15829a55de..b636ec4f5c 100644
--- a/editor/plugins/debugger_editor_plugin.cpp
+++ b/editor/plugins/debugger_editor_plugin.cpp
@@ -79,6 +79,10 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(PopupMenu *p_debug_menu) {
debug_menu->set_item_tooltip(-1,
TTR("When this option is enabled, avoidance objects shapes, radius and velocities will be visible in the running project."));
debug_menu->add_separator();
+ debug_menu->add_check_shortcut(ED_SHORTCUT("editor/visible_canvas_redraw", TTR("Debug CanvasItem Redraws")), RUN_DEBUG_CANVAS_REDRAW);
+ debug_menu->set_item_tooltip(-1,
+ TTR("When this option is enabled, redraw requests of 2D objects will become visible (as a short flash) in the running project.\nThis is useful to troubleshoot low processor mode."));
+ debug_menu->add_separator();
debug_menu->add_check_shortcut(ED_SHORTCUT("editor/sync_scene_changes", TTR("Synchronize Scene Changes")), RUN_LIVE_DEBUG);
debug_menu->set_item_tooltip(-1,
TTR("When this option is enabled, any changes made to the scene in the editor will be replicated in the running project.\nWhen used remotely on a device, this is more efficient when the network filesystem option is enabled."));
@@ -175,6 +179,12 @@ void DebuggerEditorPlugin::_menu_option(int p_option) {
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_debug_avoidance", !ischecked);
} break;
+ case RUN_DEBUG_CANVAS_REDRAW: {
+ bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_DEBUG_CANVAS_REDRAW));
+ debug_menu->set_item_checked(debug_menu->get_item_index(RUN_DEBUG_CANVAS_REDRAW), !ischecked);
+ EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_debug_canvas_redraw", !ischecked);
+
+ } break;
case RUN_RELOAD_SCRIPTS: {
bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_RELOAD_SCRIPTS));
debug_menu->set_item_checked(debug_menu->get_item_index(RUN_RELOAD_SCRIPTS), !ischecked);
@@ -213,6 +223,7 @@ void DebuggerEditorPlugin::_update_debug_options() {
bool check_debug_paths = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_paths", false);
bool check_debug_navigation = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_navigation", false);
bool check_debug_avoidance = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_avoidance", false);
+ bool check_debug_canvas_redraw = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_canvas_redraw", false);
bool check_live_debug = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_live_debug", true);
bool check_reload_scripts = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_reload_scripts", true);
bool check_server_keep_open = EditorSettings::get_singleton()->get_project_metadata("debug_options", "server_keep_open", false);
@@ -236,6 +247,9 @@ void DebuggerEditorPlugin::_update_debug_options() {
if (check_debug_avoidance) {
_menu_option(RUN_DEBUG_AVOIDANCE);
}
+ if (check_debug_canvas_redraw) {
+ _menu_option(RUN_DEBUG_CANVAS_REDRAW);
+ }
if (check_live_debug) {
_menu_option(RUN_LIVE_DEBUG);
}
diff --git a/editor/plugins/debugger_editor_plugin.h b/editor/plugins/debugger_editor_plugin.h
index eb8da7ca8e..8d65dbd2e4 100644
--- a/editor/plugins/debugger_editor_plugin.h
+++ b/editor/plugins/debugger_editor_plugin.h
@@ -52,6 +52,7 @@ private:
RUN_DEBUG_PATHS,
RUN_DEBUG_NAVIGATION,
RUN_DEBUG_AVOIDANCE,
+ RUN_DEBUG_CANVAS_REDRAW,
RUN_DEPLOY_REMOTE_DEBUG,
RUN_RELOAD_SCRIPTS,
SERVER_KEEP_OPEN,
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 1872857130..afc72cdde6 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -496,6 +496,7 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const Ref<Resource> &p_from,
Color text_color = EDITOR_GET("text_editor/theme/highlighting/text_color");
Color symbol_color = EDITOR_GET("text_editor/theme/highlighting/symbol_color");
Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
+ Color doc_comment_color = EDITOR_GET("text_editor/theme/highlighting/doc_comment_color");
if (bg_color.a == 0) {
bg_color = Color(0, 0, 0, 0);
@@ -513,6 +514,7 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const Ref<Resource> &p_from,
bool in_control_flow_keyword = false;
bool in_keyword = false;
bool in_comment = false;
+ bool in_doc_comment = false;
for (int i = 0; i < code.length(); i++) {
char32_t c = code[i];
if (c > 32) {
@@ -520,11 +522,17 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const Ref<Resource> &p_from,
Color color = text_color;
if (c == '#') {
- in_comment = true;
+ if (i < code.length() - 1 && code[i + 1] == '#') {
+ in_doc_comment = true;
+ } else {
+ in_comment = true;
+ }
}
if (in_comment) {
color = comment_color;
+ } else if (in_doc_comment) {
+ color = doc_comment_color;
} else {
if (is_symbol(c)) {
//make symbol a little visible
@@ -569,6 +577,7 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const Ref<Resource> &p_from,
if (c == '\n') {
in_comment = false;
+ in_doc_comment = false;
col = x0;
line++;
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index ec927f6c5d..79e260ef35 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -191,6 +191,16 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
highlighter->add_color_region(beg, end, comment_color, end.is_empty());
}
+ /* Doc comments */
+ const Color doc_comment_color = EDITOR_GET("text_editor/theme/highlighting/doc_comment_color");
+ List<String> doc_comments;
+ scr->get_language()->get_doc_comment_delimiters(&doc_comments);
+ for (const String &doc_comment : doc_comments) {
+ String beg = doc_comment.get_slice(" ", 0);
+ String end = doc_comment.get_slice_count(" ") > 1 ? doc_comment.get_slice(" ", 1) : String();
+ highlighter->add_color_region(beg, end, doc_comment_color, end.is_empty());
+ }
+
/* Strings */
const Color string_color = EDITOR_GET("text_editor/theme/highlighting/string_color");
List<String> strings;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 5322f3c813..5b67c6d509 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -234,9 +234,10 @@ void ScriptTextEditor::_set_theme_for_script() {
}
}
+ text_edit->clear_comment_delimiters();
+
List<String> comments;
script->get_language()->get_comment_delimiters(&comments);
- text_edit->clear_comment_delimiters();
for (const String &comment : comments) {
String beg = comment.get_slice(" ", 0);
String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String();
@@ -246,6 +247,18 @@ void ScriptTextEditor::_set_theme_for_script() {
text_edit->add_auto_brace_completion_pair(beg, end);
}
}
+
+ List<String> doc_comments;
+ script->get_language()->get_doc_comment_delimiters(&doc_comments);
+ for (const String &doc_comment : doc_comments) {
+ String beg = doc_comment.get_slice(" ", 0);
+ String end = doc_comment.get_slice_count(" ") > 1 ? doc_comment.get_slice(" ", 1) : String();
+ text_edit->add_comment_delimiter(beg, end, end.is_empty());
+
+ if (!end.is_empty() && !text_edit->has_auto_brace_completion_open_key(beg)) {
+ text_edit->add_auto_brace_completion_pair(beg, end);
+ }
+ }
}
void ScriptTextEditor::_show_errors_panel(bool p_show) {
@@ -779,7 +792,7 @@ void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_fo
return;
}
- ERR_FAIL_COND(!get_tree());
+ ERR_FAIL_NULL(get_tree());
HashSet<Ref<Script>> scripts;
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index e6bb5532a3..20b91d8bfd 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -363,7 +363,7 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) {
void Skeleton3DEditor::create_physical_skeleton() {
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
- ERR_FAIL_COND(!get_tree());
+ ERR_FAIL_NULL(get_tree());
Node *owner = get_tree()->get_edited_scene_root();
const int bone_count = skeleton->get_bone_count();
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 821d8151a4..9ba5f2faf1 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -31,12 +31,14 @@
#include "theme_editor_plugin.h"
#include "core/os/keyboard.h"
+#include "editor/editor_help.h"
#include "editor/editor_node.h"
#include "editor/editor_resource_picker.h"
#include "editor/editor_scale.h"
#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/gui/editor_file_dialog.h"
+#include "editor/inspector_dock.h"
#include "editor/progress_dialog.h"
#include "scene/gui/check_button.h"
#include "scene/gui/color_picker.h"
@@ -2259,6 +2261,10 @@ ThemeTypeDialog::ThemeTypeDialog() {
///////////////////////
+Control *ThemeItemLabel::make_custom_tooltip(const String &p_text) const {
+ return memnew(EditorHelpTooltip(p_text));
+}
+
VBoxContainer *ThemeTypeEditor::_create_item_list(Theme::DataType p_data_type) {
VBoxContainer *items_tab = memnew(VBoxContainer);
items_tab->set_custom_minimum_size(Size2(0, 160) * EDSCALE);
@@ -2413,11 +2419,13 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_
item_name_container->set_stretch_ratio(2.0);
item_control->add_child(item_name_container);
- Label *item_name = memnew(Label);
+ Label *item_name = memnew(ThemeItemLabel);
item_name->set_h_size_flags(SIZE_EXPAND_FILL);
item_name->set_clip_text(true);
item_name->set_text(p_item_name);
- item_name->set_tooltip_text(p_item_name);
+ // `|` separators used in `EditorHelpTooltip` for formatting.
+ item_name->set_tooltip_text("theme_item|" + edited_type + "|" + p_item_name + "|");
+ item_name->set_mouse_filter(Control::MOUSE_FILTER_STOP);
item_name_container->add_child(item_name);
if (p_editable) {
@@ -2477,7 +2485,6 @@ void ThemeTypeEditor::_add_focusable(Control *p_control) {
void ThemeTypeEditor::_update_type_items() {
bool show_default = show_default_items_button->is_pressed();
- List<StringName> names;
focusables.clear();
@@ -3528,6 +3535,16 @@ void ThemeEditor::_theme_edit_button_cbk() {
theme_edit_dialog->popup_centered(Size2(850, 700) * EDSCALE);
}
+void ThemeEditor::_theme_close_button_cbk() {
+ plugin->make_visible(false); // Enables auto hide.
+ if (theme.is_valid() && InspectorDock::get_inspector_singleton()->get_edited_object() == theme.ptr()) {
+ EditorNode::get_singleton()->push_item(nullptr);
+ } else {
+ theme = Ref<Theme>();
+ EditorNode::get_singleton()->hide_unused_editors(plugin);
+ }
+}
+
void ThemeEditor::_add_preview_button_cbk() {
preview_scene_dialog->popup_file_dialog();
}
@@ -3645,6 +3662,12 @@ ThemeEditor::ThemeEditor() {
theme_save_as_button->connect("pressed", callable_mp(this, &ThemeEditor::_theme_save_button_cbk).bind(true));
top_menu->add_child(theme_save_as_button);
+ Button *theme_close_button = memnew(Button);
+ theme_close_button->set_text(TTR("Close"));
+ theme_close_button->set_flat(true);
+ theme_close_button->connect("pressed", callable_mp(this, &ThemeEditor::_theme_close_button_cbk));
+ top_menu->add_child(theme_close_button);
+
top_menu->add_child(memnew(VSeparator));
Button *theme_edit_button = memnew(Button);
@@ -3711,20 +3734,12 @@ ThemeEditor::ThemeEditor() {
///////////////////////
-void ThemeEditorPlugin::edit(Object *p_node) {
- if (Object::cast_to<Theme>(p_node)) {
- theme_editor->edit(Object::cast_to<Theme>(p_node));
- } else {
- // We intentionally keep a reference to the last used theme to work around
- // the the editor being hidden while base resources are edited. Uncomment
- // the following line again and remove this comment once that bug has been
- // fixed (scheduled for Godot 4.1 in PR 73098):
- // theme_editor->edit(Ref<Theme>());
- }
+void ThemeEditorPlugin::edit(Object *p_object) {
+ theme_editor->edit(Ref<Theme>(p_object));
}
-bool ThemeEditorPlugin::handles(Object *p_node) const {
- return Object::cast_to<Theme>(p_node) != nullptr;
+bool ThemeEditorPlugin::handles(Object *p_object) const {
+ return Object::cast_to<Theme>(p_object) != nullptr;
}
void ThemeEditorPlugin::make_visible(bool p_visible) {
@@ -3740,8 +3755,77 @@ void ThemeEditorPlugin::make_visible(bool p_visible) {
}
}
+bool ThemeEditorPlugin::can_auto_hide() const {
+ Ref<Theme> edited_theme = theme_editor->theme;
+ if (edited_theme.is_null()) {
+ return true;
+ }
+
+ Ref<Resource> edited_resource = Ref<Resource>(InspectorDock::get_inspector_singleton()->get_next_edited_object());
+ if (edited_resource.is_null()) {
+ return true;
+ }
+
+ // Don't hide if edited resource used by this theme.
+ Ref<StyleBox> sbox = edited_resource;
+ if (sbox.is_valid()) {
+ List<StringName> type_list;
+ edited_theme->get_stylebox_type_list(&type_list);
+
+ for (const StringName &E : type_list) {
+ List<StringName> list;
+ edited_theme->get_stylebox_list(E, &list);
+
+ for (const StringName &F : list) {
+ if (edited_theme->get_stylebox(F, E) == sbox) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ Ref<Texture2D> tex = edited_resource;
+ if (tex.is_valid()) {
+ List<StringName> type_list;
+ edited_theme->get_icon_type_list(&type_list);
+
+ for (const StringName &E : type_list) {
+ List<StringName> list;
+ edited_theme->get_icon_list(E, &list);
+
+ for (const StringName &F : list) {
+ if (edited_theme->get_icon(F, E) == tex) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ Ref<Font> fnt = edited_resource;
+ if (fnt.is_valid()) {
+ List<StringName> type_list;
+ edited_theme->get_font_type_list(&type_list);
+
+ for (const StringName &E : type_list) {
+ List<StringName> list;
+ edited_theme->get_font_list(E, &list);
+
+ for (const StringName &F : list) {
+ if (edited_theme->get_font(F, E) == fnt) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ return true;
+}
+
ThemeEditorPlugin::ThemeEditorPlugin() {
theme_editor = memnew(ThemeEditor);
+ theme_editor->plugin = this;
theme_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Theme"), theme_editor);
diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h
index 077ce8e8f7..33accf587a 100644
--- a/editor/plugins/theme_editor_plugin.h
+++ b/editor/plugins/theme_editor_plugin.h
@@ -47,6 +47,7 @@ class OptionButton;
class PanelContainer;
class TabBar;
class TabContainer;
+class ThemeEditorPlugin;
class TextureRect;
class ThemeItemImportTree : public VBoxContainer {
@@ -320,6 +321,11 @@ public:
ThemeTypeDialog();
};
+// Custom `Label` needed to use `EditorHelpTooltip` to display theme item documentation.
+class ThemeItemLabel : public Label {
+ virtual Control *make_custom_tooltip(const String &p_text) const;
+};
+
class ThemeTypeEditor : public MarginContainer {
GDCLASS(ThemeTypeEditor, MarginContainer);
@@ -419,6 +425,9 @@ public:
class ThemeEditor : public VBoxContainer {
GDCLASS(ThemeEditor, VBoxContainer);
+ friend class ThemeEditorPlugin;
+ ThemeEditorPlugin *plugin = nullptr;
+
Ref<Theme> theme;
TabBar *preview_tabs = nullptr;
@@ -433,6 +442,7 @@ class ThemeEditor : public VBoxContainer {
void _theme_save_button_cbk(bool p_save_as);
void _theme_edit_button_cbk();
+ void _theme_close_button_cbk();
void _add_preview_button_cbk();
void _preview_scene_dialog_cbk(const String &p_path);
@@ -462,9 +472,10 @@ class ThemeEditorPlugin : public EditorPlugin {
public:
virtual String get_name() const override { return "Theme"; }
bool has_main_screen() const override { return false; }
- virtual void edit(Object *p_node) override;
- virtual bool handles(Object *p_node) const override;
+ virtual void edit(Object *p_object) override;
+ virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
+ virtual bool can_auto_hide() const override;
ThemeEditorPlugin();
};
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index b55be8b3f8..039213e545 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -90,8 +90,6 @@ Size2i TileAtlasView::_compute_alternative_tiles_control_size() {
}
void TileAtlasView::_update_zoom_and_panning(bool p_zoom_on_mouse_pos) {
- // Don't allow zoom to go below 1% or above 10000%
- zoom_widget->set_zoom(CLAMP(zoom_widget->get_zoom(), 0.01f, 100.f));
float zoom = zoom_widget->get_zoom();
// Compute the minimum sizes.
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index d634d957b3..ad4844fe3e 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -361,8 +361,8 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
}
undo_redo->add_do_method(base_control, "queue_redraw");
undo_redo->add_do_method(this, "emit_signal", "polygons_changed");
- for (const PackedVector2Array &polygon : polygons) {
- undo_redo->add_undo_method(this, "set_polygon", polygon);
+ for (unsigned int i = 0; i < polygons.size(); i++) {
+ undo_redo->add_undo_method(this, "set_polygon", i, polygons[i]);
}
undo_redo->add_undo_method(base_control, "queue_redraw");
undo_redo->add_undo_method(this, "emit_signal", "polygons_changed");
@@ -931,6 +931,7 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() {
snap_subdivision->connect("value_changed", callable_mp(this, &GenericTilePolygonEditor::_store_snap_options).unbind(1));
editor_zoom_widget = memnew(EditorZoomWidget);
+ editor_zoom_widget->setup_zoom_limits(0.125, 128.0);
editor_zoom_widget->set_position(Vector2(5, 5));
editor_zoom_widget->connect("zoom_changed", callable_mp(this, &GenericTilePolygonEditor::_zoom_changed).unbind(1));
editor_zoom_widget->set_shortcut_context(this);
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index afc929b547..6bac62d861 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -44,7 +44,7 @@
#include "scene/gui/separator.h"
#define CHECK_PLUGIN_INITIALIZED() \
- ERR_FAIL_COND_MSG(!EditorVCSInterface::get_singleton(), "No VCS plugin is initialized. Select a Version Control Plugin from Project menu.");
+ ERR_FAIL_NULL_MSG(EditorVCSInterface::get_singleton(), "No VCS plugin is initialized. Select a Version Control Plugin from Project menu.");
VersionControlEditorPlugin *VersionControlEditorPlugin::singleton = nullptr;
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index e7fe9a353c..b04773d371 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -397,7 +397,7 @@ void ProjectDialog::_nonempty_confirmation_ok_pressed() {
}
void ProjectDialog::_renderer_selected() {
- ERR_FAIL_COND(!renderer_button_group->get_pressed_button());
+ ERR_FAIL_NULL(renderer_button_group->get_pressed_button());
String renderer_type = renderer_button_group->get_pressed_button()->get_meta(SNAME("rendering_method"));
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index e7727aec4b..a38487635f 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -651,8 +651,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *top_node = selection[i];
Node *bottom_node = selection[selection.size() - 1 - i];
- ERR_FAIL_COND(!top_node->get_parent());
- ERR_FAIL_COND(!bottom_node->get_parent());
+ ERR_FAIL_NULL(top_node->get_parent());
+ ERR_FAIL_NULL(bottom_node->get_parent());
int bottom_node_pos = bottom_node->get_index(false);
int top_node_pos_next = top_node->get_index(false) + (MOVING_DOWN ? 1 : -1);
@@ -1934,6 +1934,8 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
p_nodes.sort_custom<Node::Comparator>(); //Makes result reliable.
+ const int first_idx = p_position_in_parent == -1 ? p_new_parent->get_child_count(false) : p_position_in_parent;
+ int nodes_before = first_idx;
bool no_change = true;
for (int ni = 0; ni < p_nodes.size(); ni++) {
if (p_nodes[ni] == p_new_parent) {
@@ -1942,7 +1944,17 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
// `move_child` + `get_index` doesn't really work for internal nodes.
ERR_FAIL_COND_MSG(p_nodes[ni]->get_internal_mode() != INTERNAL_MODE_DISABLED, "Trying to move internal node, this is not supported.");
- if (p_nodes[ni]->get_parent() != p_new_parent || p_position_in_parent + ni != p_nodes[ni]->get_index(false)) {
+ if (p_nodes[ni]->get_index(false) < first_idx) {
+ nodes_before--;
+ }
+
+ if (p_nodes[ni]->get_parent() != p_new_parent) {
+ no_change = false;
+ }
+ }
+
+ for (int ni = 0; ni < p_nodes.size() && no_change; ni++) {
+ if (p_nodes[ni]->get_index(false) != nodes_before + ni) {
no_change = false;
}
}