summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/animation_bezier_editor.cpp4
-rw-r--r--editor/animation_track_editor.cpp27
-rw-r--r--editor/animation_track_editor.h10
-rw-r--r--editor/connections_dialog.cpp31
-rw-r--r--editor/connections_dialog.h1
-rw-r--r--editor/doc_tools.cpp28
-rw-r--r--editor/editor_command_palette.cpp2
-rw-r--r--editor/editor_feature_profile.cpp2
-rw-r--r--editor/editor_file_dialog.h4
-rw-r--r--editor/editor_file_system.cpp5
-rw-r--r--editor/editor_file_system.h1
-rw-r--r--editor/editor_fonts.cpp10
-rw-r--r--editor/editor_help_search.cpp5
-rw-r--r--editor/editor_inspector.cpp91
-rw-r--r--editor/editor_inspector.h7
-rw-r--r--editor/editor_node.cpp282
-rw-r--r--editor/editor_node.h44
-rw-r--r--editor/editor_plugin_settings.cpp2
-rw-r--r--editor/editor_properties.cpp8
-rw-r--r--editor/editor_properties_array_dict.cpp26
-rw-r--r--editor/editor_quick_open.cpp21
-rw-r--r--editor/editor_quick_open.h1
-rw-r--r--editor/editor_resource_picker.cpp148
-rw-r--r--editor/editor_resource_picker.h1
-rw-r--r--editor/editor_settings_dialog.cpp58
-rw-r--r--editor/editor_themes.cpp374
-rw-r--r--editor/editor_themes.h11
-rw-r--r--editor/editor_undo_redo_manager.cpp4
-rw-r--r--editor/export/editor_export_platform.cpp2
-rw-r--r--editor/export/project_export.cpp8
-rw-r--r--editor/filesystem_dock.cpp17
-rw-r--r--editor/icons/MemberAnnotation.svg2
-rw-r--r--editor/icons/MethodOverride.svg1
-rw-r--r--editor/icons/MethodOverrideAndSlot.svg1
-rw-r--r--editor/icons/VisualScriptComment.svg1
-rw-r--r--editor/icons/VisualScriptExpression.svg1
-rw-r--r--editor/import/dynamic_font_import_settings.cpp8
-rw-r--r--editor/import/resource_importer_scene.cpp36
-rw-r--r--editor/import/resource_importer_scene.h13
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp55
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h5
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp15
-rw-r--r--editor/plugins/animation_tree_editor_plugin.h1
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp9
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h2
-rw-r--r--editor/plugins/font_config_plugin.cpp10
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp12
-rw-r--r--editor/plugins/node_3d_editor_plugin.h2
-rw-r--r--editor/plugins/script_editor_plugin.cpp76
-rw-r--r--editor/plugins/script_editor_plugin.h4
-rw-r--r--editor/plugins/script_text_editor.cpp121
-rw-r--r--editor/plugins/shader_editor_plugin.cpp8
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp31
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h2
-rw-r--r--editor/plugins/texture_3d_editor_plugin.cpp6
-rw-r--r--editor/plugins/texture_3d_editor_plugin.h2
-rw-r--r--editor/plugins/texture_layered_editor_plugin.cpp6
-rw-r--r--editor/plugins/texture_layered_editor_plugin.h1
-rw-r--r--editor/plugins/theme_editor_plugin.cpp32
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp5
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp2
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp2
-rw-r--r--editor/project_converter_3_to_4.cpp106
-rw-r--r--editor/project_converter_3_to_4.h1
-rw-r--r--editor/project_manager.cpp115
-rw-r--r--editor/project_manager.h1
-rw-r--r--editor/scene_create_dialog.cpp2
-rw-r--r--editor/scene_tree_dock.cpp89
-rw-r--r--editor/scene_tree_dock.h7
-rw-r--r--editor/scene_tree_editor.cpp19
-rw-r--r--editor/scene_tree_editor.h4
-rw-r--r--editor/shader_globals_editor.cpp2
72 files changed, 1226 insertions, 827 deletions
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index 219f3fdbe1..3b87b3e65e 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -667,8 +667,8 @@ void AnimationBezierTrackEdit::set_timeline(AnimationTimelineEdit *p_timeline) {
void AnimationBezierTrackEdit::set_editor(AnimationTrackEditor *p_editor) {
editor = p_editor;
- connect("clear_selection", Callable(editor, "_clear_selection").bind(false));
- connect("select_key", Callable(editor, "_key_selected"), CONNECT_DEFERRED);
+ connect("clear_selection", callable_mp(editor, &AnimationTrackEditor::_clear_selection).bind(false));
+ connect("select_key", callable_mp(editor, &AnimationTrackEditor::_key_selected), CONNECT_DEFERRED);
}
void AnimationBezierTrackEdit::_play_position_draw() {
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 70b5501692..9529460ab1 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -1445,7 +1445,9 @@ void AnimationTimelineEdit::_anim_loop_pressed() {
default:
break;
}
+ undo_redo->add_do_method(this, "update_values");
undo_redo->add_undo_method(animation.ptr(), "set_loop_mode", animation->get_loop_mode());
+ undo_redo->add_undo_method(this, "update_values");
undo_redo->commit_action();
} else {
String base_path = animation->get_path();
@@ -1913,6 +1915,8 @@ void AnimationTimelineEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::FLOAT, "position"), PropertyInfo(Variant::BOOL, "drag"), PropertyInfo(Variant::BOOL, "timeline_only")));
ADD_SIGNAL(MethodInfo("track_added", PropertyInfo(Variant::INT, "track")));
ADD_SIGNAL(MethodInfo("length_changed", PropertyInfo(Variant::FLOAT, "size")));
+
+ ClassDB::bind_method(D_METHOD("update_values"), &AnimationTimelineEdit::update_values);
}
AnimationTimelineEdit::AnimationTimelineEdit() {
@@ -3420,9 +3424,6 @@ void AnimationTrackEditGroup::_zoom_changed() {
queue_redraw();
}
-void AnimationTrackEditGroup::_bind_methods() {
-}
-
AnimationTrackEditGroup::AnimationTrackEditGroup() {
set_mouse_filter(MOUSE_FILTER_PASS);
}
@@ -6050,10 +6051,9 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
real_t to_diff = fmod(b - a, Math_TAU);
to_v = a + fmod(2.0 * to_diff, Math_TAU) - to_diff;
}
- Variant delta_v;
- Variant::sub(to_v, from_v, delta_v);
+ Variant delta_v = Animation::subtract_variant(to_v, from_v);
double duration = to_t - from_t;
- double fixed_duration = duration - 0.01; // Prevent to overwrap keys...
+ double fixed_duration = duration - UNIT_EPSILON; // Prevent to overwrap keys...
for (double delta_t = dur_step; delta_t < fixed_duration; delta_t += dur_step) {
Pair<real_t, Variant> keydata;
keydata.first = from_t + delta_t;
@@ -6458,16 +6458,11 @@ void AnimationTrackEditor::_select_all_tracks_for_copy() {
}
void AnimationTrackEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_animation_update"), &AnimationTrackEditor::_animation_update);
- ClassDB::bind_method(D_METHOD("_track_grab_focus"), &AnimationTrackEditor::_track_grab_focus);
- ClassDB::bind_method(D_METHOD("_update_tracks"), &AnimationTrackEditor::_update_tracks);
- ClassDB::bind_method(D_METHOD("_redraw_tracks"), &AnimationTrackEditor::_redraw_tracks);
- ClassDB::bind_method(D_METHOD("_clear_selection_for_anim"), &AnimationTrackEditor::_clear_selection_for_anim);
- ClassDB::bind_method(D_METHOD("_select_at_anim"), &AnimationTrackEditor::_select_at_anim);
-
- ClassDB::bind_method(D_METHOD("_key_selected"), &AnimationTrackEditor::_key_selected); // Still used by some connect_compat.
- ClassDB::bind_method(D_METHOD("_key_deselected"), &AnimationTrackEditor::_key_deselected); // Still used by some connect_compat.
- ClassDB::bind_method(D_METHOD("_clear_selection"), &AnimationTrackEditor::_clear_selection); // Still used by some connect_compat.
+ ClassDB::bind_method("_animation_update", &AnimationTrackEditor::_animation_update);
+ ClassDB::bind_method("_track_grab_focus", &AnimationTrackEditor::_track_grab_focus);
+ ClassDB::bind_method("_clear_selection_for_anim", &AnimationTrackEditor::_clear_selection_for_anim);
+ ClassDB::bind_method("_select_at_anim", &AnimationTrackEditor::_select_at_anim);
+ ClassDB::bind_method("_clear_selection", &AnimationTrackEditor::_clear_selection);
ClassDB::bind_method(D_METHOD("_bezier_track_set_key_handle_mode", "animation", "track_idx", "key_idx", "key_handle_mode", "key_handle_set_mode"), &AnimationTrackEditor::_bezier_track_set_key_handle_mode, DEFVAL(Animation::HANDLE_SET_MODE_NONE));
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index ac69b88e99..5c51921d93 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -280,7 +280,6 @@ class AnimationTrackEditGroup : public Control {
void _zoom_changed();
protected:
- static void _bind_methods();
void _notification(int p_what);
public:
@@ -407,7 +406,6 @@ class AnimationTrackEditor : public VBoxContainer {
void _insert_key_from_track(float p_ofs, int p_track);
void _add_method_key(const String &p_method);
- void _clear_selection(bool p_update = false);
void _clear_selection_for_anim(const Ref<Animation> &p_anim);
void _select_at_anim(const Ref<Animation> &p_anim, int p_track, float p_pos);
@@ -425,9 +423,6 @@ class AnimationTrackEditor : public VBoxContainer {
RBMap<SelectedKey, KeyInfo> selection;
- void _key_selected(int p_key, bool p_single, int p_track);
- void _key_deselected(int p_key, int p_track);
-
bool moving_selection = false;
float moving_selection_offset = 0.0f;
void _move_selection_begin();
@@ -531,6 +526,11 @@ protected:
void _notification(int p_what);
public:
+ // Public for use with callable_mp.
+ void _clear_selection(bool p_update = false);
+ void _key_selected(int p_key, bool p_single, int p_track);
+ void _key_deselected(int p_key, int p_track);
+
enum {
EDIT_COPY_TRACKS,
EDIT_COPY_TRACKS_CONFIRM,
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 861d05f17a..ddeb8643b8 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -238,6 +238,12 @@ void ConnectDialog::_notification(int p_what) {
String type_name = Variant::get_type_name((Variant::Type)type_list->get_item_id(i));
type_list->set_item_icon(i, get_theme_icon(type_name, SNAME("EditorIcons")));
}
+
+ Ref<StyleBox> style = get_theme_stylebox("normal", "LineEdit")->duplicate();
+ if (style.is_valid()) {
+ style->set_default_margin(SIDE_TOP, style->get_default_margin(SIDE_TOP) + 1.0);
+ from_signal->add_theme_style_override("normal", style);
+ }
} break;
}
}
@@ -361,6 +367,10 @@ void ConnectDialog::popup_dialog(const String &p_for_signal) {
error_label->set_visible(!_find_first_script(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root()));
}
+ if (first_popup) {
+ first_popup = false;
+ _advanced_pressed();
+ }
popup_centered();
}
@@ -383,6 +393,7 @@ void ConnectDialog::_advanced_pressed() {
}
_update_ok_enabled();
+ EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "use_advanced_connections", advanced->is_pressed());
popup_centered();
}
@@ -465,30 +476,32 @@ ConnectDialog::ConnectDialog() {
vbc_right->add_margin_child(TTR("Unbind Signal Arguments:"), unbind_count);
- HBoxContainer *dstm_hb = memnew(HBoxContainer);
- vbc_left->add_margin_child(TTR("Receiver Method:"), dstm_hb);
-
dst_method = memnew(LineEdit);
dst_method->set_h_size_flags(Control::SIZE_EXPAND_FILL);
dst_method->connect("text_submitted", callable_mp(this, &ConnectDialog::_text_submitted));
- dstm_hb->add_child(dst_method);
+ vbc_left->add_margin_child(TTR("Receiver Method:"), dst_method);
advanced = memnew(CheckButton);
- dstm_hb->add_child(advanced);
+ vbc_left->add_child(advanced);
advanced->set_text(TTR("Advanced"));
+ advanced->set_h_size_flags(Control::SIZE_SHRINK_BEGIN | Control::SIZE_EXPAND);
+ advanced->set_pressed(EditorSettings::get_singleton()->get_project_metadata("editor_metadata", "use_advanced_connections", false));
advanced->connect("pressed", callable_mp(this, &ConnectDialog::_advanced_pressed));
+ HBoxContainer *hbox = memnew(HBoxContainer);
+ vbc_right->add_child(hbox);
+
deferred = memnew(CheckBox);
deferred->set_h_size_flags(0);
deferred->set_text(TTR("Deferred"));
deferred->set_tooltip_text(TTR("Defers the signal, storing it in a queue and only firing it at idle time."));
- vbc_right->add_child(deferred);
+ hbox->add_child(deferred);
one_shot = memnew(CheckBox);
one_shot->set_h_size_flags(0);
- one_shot->set_text(TTR("Oneshot"));
+ one_shot->set_text(TTR("One Shot"));
one_shot->set_tooltip_text(TTR("Disconnects the signal after its first emission."));
- vbc_right->add_child(one_shot);
+ hbox->add_child(one_shot);
cdbinds = memnew(ConnectDialogBinds);
@@ -810,7 +823,7 @@ void ConnectionsDock::_go_to_script(TreeItem &p_item) {
}
if (script.is_valid() && ScriptEditor::get_singleton()->script_goto_method(script, cd.method)) {
- EditorNode::get_singleton()->call("_editor_select", EditorNode::EDITOR_SCRIPT);
+ EditorNode::get_singleton()->editor_select(EditorNode::EDITOR_SCRIPT);
}
}
diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h
index e37246e7a0..db2f855617 100644
--- a/editor/connections_dialog.h
+++ b/editor/connections_dialog.h
@@ -112,6 +112,7 @@ private:
LineEdit *dst_method = nullptr;
ConnectDialogBinds *cdbinds = nullptr;
bool edit_mode = false;
+ bool first_popup = true;
NodePath dst_path;
VBoxContainer *vbc_right = nullptr;
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index 9f655ab00a..7d6eb186dc 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -1162,13 +1162,11 @@ Error DocTools::_load(Ref<XMLParser> parser) {
}
if (parser->has_attribute("is_deprecated")) {
- String result = parser->get_attribute_value("is_deprecated");
- c.is_deprecated = (result == "true" || result == "True" || result == "TRUE" || result == "1");
+ c.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
}
if (parser->has_attribute("is_experimental")) {
- String result = parser->get_attribute_value("is_experimental");
- c.is_experimental = (result == "true" || result == "True" || result == "TRUE" || result == "1");
+ c.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
}
while (parser->read() == OK) {
@@ -1315,12 +1313,10 @@ Error DocTools::_load(Ref<XMLParser> parser) {
constant2.is_bitfield = parser->get_attribute_value("is_bitfield").to_lower() == "true";
}
if (parser->has_attribute("is_deprecated")) {
- String result = parser->get_attribute_value("is_deprecated");
- constant2.is_deprecated = (result == "true" || result == "True" || result == "TRUE" || result == "1");
+ constant2.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
}
if (parser->has_attribute("is_experimental")) {
- String result = parser->get_attribute_value("is_experimental");
- constant2.is_experimental = (result == "true" || result == "True" || result == "TRUE" || result == "1");
+ constant2.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
}
if (!parser->is_empty()) {
parser->read();
@@ -1376,10 +1372,10 @@ static void _write_method_doc(Ref<FileAccess> f, const String &p_name, Vector<Do
String additional_attributes;
if (m.is_deprecated) {
- additional_attributes += " is_deprecated=\"True\"";
+ additional_attributes += " is_deprecated=\"true\"";
}
if (m.is_experimental) {
- additional_attributes += " is_experimental=\"True\"";
+ additional_attributes += " is_experimental=\"true\"";
}
_write_string(f, 2, "<" + p_name + " name=\"" + m.name.xml_escape() + "\"" + qualifiers + additional_attributes + ">");
@@ -1446,10 +1442,10 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
if (!c.inherits.is_empty()) {
header += " inherits=\"" + c.inherits + "\"";
if (c.is_deprecated) {
- header += " is_deprecated=\"True\"";
+ header += " is_deprecated=\"true\"";
}
if (c.is_experimental) {
- header += " is_experimental=\"True\"";
+ header += " is_experimental=\"true\"";
}
}
header += String(" version=\"") + VERSION_BRANCH + "\"";
@@ -1495,10 +1491,10 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
additional_attributes += " default=\"" + c.properties[i].default_value.xml_escape(true) + "\"";
}
if (c.properties[i].is_deprecated) {
- additional_attributes += " is_deprecated=\"True\"";
+ additional_attributes += " is_deprecated=\"true\"";
}
if (c.properties[i].is_experimental) {
- additional_attributes += " is_experimental=\"True\"";
+ additional_attributes += " is_experimental=\"true\"";
}
const DocData::PropertyDoc &p = c.properties[i];
@@ -1523,10 +1519,10 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
String additional_attributes;
if (c.constants[i].is_deprecated) {
- additional_attributes += " is_deprecated=\"True\"";
+ additional_attributes += " is_deprecated=\"true\"";
}
if (c.constants[i].is_experimental) {
- additional_attributes += " is_experimental=\"True\"";
+ additional_attributes += " is_experimental=\"true\"";
}
if (k.is_value_valid) {
diff --git a/editor/editor_command_palette.cpp b/editor/editor_command_palette.cpp
index ba1f2fd6af..a0913265eb 100644
--- a/editor/editor_command_palette.cpp
+++ b/editor/editor_command_palette.cpp
@@ -130,7 +130,7 @@ void EditorCommandPalette::_update_command_search(const String &search_text) {
ti->set_metadata(0, entries[i].key_name);
ti->set_text_alignment(1, HORIZONTAL_ALIGNMENT_RIGHT);
ti->set_text(1, shortcut_text);
- Color c = Color(1, 1, 1, 0.5);
+ Color c = get_theme_color(SNAME("font_color"), SNAME("Editor")) * Color(1, 1, 1, 0.5);
ti->set_custom_color(1, c);
}
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index 708173ea26..9549ffb09b 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -763,7 +763,7 @@ void EditorFeatureProfileManager::_update_selected_profile() {
TreeItem *root = class_list->create_item();
TreeItem *features = class_list->create_item(root);
- TreeItem *last_feature;
+ TreeItem *last_feature = nullptr;
features->set_text(0, TTR("Main Features:"));
for (int i = 0; i < EditorFeatureProfile::FEATURE_MAX; i++) {
TreeItem *feature;
diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h
index 6d11cb10ed..2e7302aaf9 100644
--- a/editor/editor_file_dialog.h
+++ b/editor/editor_file_dialog.h
@@ -202,7 +202,6 @@ private:
void _select_drive(int p_idx);
void _dir_submitted(String p_dir);
- void _file_submitted(const String &p_file);
void _action_pressed();
void _save_confirm_pressed();
void _cancel_pressed();
@@ -240,6 +239,9 @@ protected:
static void _bind_methods();
public:
+ // Public for use with callable_mp.
+ void _file_submitted(const String &p_file);
+
void popup_file_dialog();
void clear_filters();
void add_filter(const String &p_filter, const String &p_description = "");
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 177bc6d2b2..b89bd23859 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -690,7 +690,6 @@ void EditorFileSystem::scan() {
_update_extensions();
- abort_scan = false;
if (!use_threads) {
scanning = true;
scan_total = 0;
@@ -1162,8 +1161,6 @@ void EditorFileSystem::scan_changes() {
scanning_changes = true;
scanning_changes_done = false;
- abort_scan = false;
-
if (!use_threads) {
if (filesystem) {
EditorProgressBG pr("sources", TTR("ScanSources"), 1000);
@@ -1195,8 +1192,6 @@ void EditorFileSystem::_notification(int p_what) {
case NOTIFICATION_EXIT_TREE: {
Thread &active_thread = thread.is_started() ? thread : thread_sources;
if (use_threads && active_thread.is_started()) {
- //abort thread if in progress
- abort_scan = true;
while (scanning) {
OS::get_singleton()->delay_usec(1000);
}
diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h
index f4e69b95e7..e06c6e4593 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -168,7 +168,6 @@ class EditorFileSystem : public Node {
EditorFileSystemDirectory *new_filesystem = nullptr;
- bool abort_scan = false;
bool scanning = false;
bool importing = false;
bool first_scan = true;
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index fffe77f1c4..c31d13d122 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -96,6 +96,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)EditorSettings::get_singleton()->get("interface/editor/font_subpixel_positioning");
TextServer::Hinting font_hinting;
+ TextServer::Hinting font_mono_hinting;
switch (font_hinting_setting) {
case 0:
// The "Auto" setting uses the setting that best matches the OS' font rendering:
@@ -104,18 +105,23 @@ void editor_register_fonts(Ref<Theme> p_theme) {
// - Linux has configurable font hinting, but most distributions including Ubuntu default to "Light".
#ifdef MACOS_ENABLED
font_hinting = TextServer::HINTING_NONE;
+ font_mono_hinting = TextServer::HINTING_NONE;
#else
font_hinting = TextServer::HINTING_LIGHT;
+ font_mono_hinting = TextServer::HINTING_LIGHT;
#endif
break;
case 1:
font_hinting = TextServer::HINTING_NONE;
+ font_mono_hinting = TextServer::HINTING_NONE;
break;
case 2:
font_hinting = TextServer::HINTING_LIGHT;
+ font_mono_hinting = TextServer::HINTING_LIGHT;
break;
default:
font_hinting = TextServer::HINTING_NORMAL;
+ font_mono_hinting = TextServer::HINTING_LIGHT;
break;
}
@@ -163,7 +169,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
default_font_bold->set_fallbacks(fallbacks_bold);
default_font_bold_msdf->set_fallbacks(fallbacks_bold);
- Ref<FontFile> default_font_mono = load_internal_font(_font_JetBrainsMono_Regular, _font_JetBrainsMono_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning);
+ Ref<FontFile> default_font_mono = load_internal_font(_font_JetBrainsMono_Regular, _font_JetBrainsMono_Regular_size, font_mono_hinting, font_antialiasing, true, font_subpixel_positioning);
default_font_mono->set_fallbacks(fallbacks);
// Init base font configs and load custom fonts.
@@ -260,7 +266,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
Ref<FontVariation> mono_fc;
mono_fc.instantiate();
if (custom_font_path_source.length() > 0 && dir->file_exists(custom_font_path_source)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path_source, font_hinting, font_antialiasing, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path_source, font_mono_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font_mono);
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index 7e7d7ca418..1b8146a0f0 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -324,11 +324,16 @@ bool EditorHelpSearch::Runner::_phase_match_classes_init() {
}
bool EditorHelpSearch::Runner::_phase_match_classes() {
+ if (!iterator_doc) {
+ return true;
+ }
+
DocData::ClassDoc &class_doc = iterator_doc->value;
if (class_doc.name.is_empty()) {
++iterator_doc;
return false;
}
+
if (!_is_class_disabled_by_feature_profile(class_doc.name)) {
ClassMatch match;
match.doc = &class_doc;
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index f001887ef9..5de205153d 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -426,6 +426,9 @@ void EditorProperty::_set_read_only(bool p_read_only) {
void EditorProperty::set_read_only(bool p_read_only) {
read_only = p_read_only;
+ if (GDVIRTUAL_CALL(_set_read_only, p_read_only)) {
+ return;
+ }
_set_read_only(p_read_only);
}
@@ -458,7 +461,7 @@ StringName EditorProperty::_get_revert_property() const {
return property;
}
-void EditorProperty::update_revert_and_pin_status() {
+void EditorProperty::update_editor_property_status() {
if (property == StringName()) {
return; //no property, so nothing to do
}
@@ -469,15 +472,26 @@ void EditorProperty::update_revert_and_pin_status() {
CRASH_COND(!node);
new_pinned = node->is_property_pinned(property);
}
+
Variant current = object->get(_get_revert_property());
bool new_can_revert = EditorPropertyRevert::can_property_revert(object, property, &current) && !is_read_only();
- if (new_can_revert != can_revert || new_pinned != pinned) {
+ bool new_checked = checked;
+ if (checkable) { // for properties like theme overrides.
+ bool valid = false;
+ Variant value = object->get(property, &valid);
+ if (valid) {
+ new_checked = value.get_type() != Variant::NIL;
+ }
+ }
+
+ if (new_can_revert != can_revert || new_pinned != pinned || new_checked != checked) {
if (new_can_revert != can_revert) {
emit_signal(SNAME("property_can_revert_changed"), property, new_can_revert);
}
can_revert = new_can_revert;
pinned = new_pinned;
+ checked = new_checked;
queue_redraw();
}
}
@@ -974,7 +988,9 @@ void EditorProperty::_bind_methods() {
ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "focusable_idx")));
GDVIRTUAL_BIND(_update_property)
- ClassDB::bind_method(D_METHOD("_update_revert_and_pin_status"), &EditorProperty::update_revert_and_pin_status);
+ GDVIRTUAL_BIND(_set_read_only, "read_only")
+
+ ClassDB::bind_method(D_METHOD("_update_editor_property_status"), &EditorProperty::update_editor_property_status);
}
EditorProperty::EditorProperty() {
@@ -1127,11 +1143,10 @@ Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) cons
}
Size2 EditorInspectorCategory::get_minimum_size() const {
- Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Tree"));
- int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Tree"));
+ Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
+ int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"));
Size2 ms;
- ms.width = 1;
ms.height = font->get_height(font_size);
if (icon.is_valid()) {
ms.height = MAX(icon->get_height(), ms.height);
@@ -1651,6 +1666,10 @@ void EditorInspectorArray::_panel_draw(int p_index) {
void EditorInspectorArray::_panel_gui_input(Ref<InputEvent> p_event, int p_index) {
ERR_FAIL_INDEX(p_index, (int)array_elements.size());
+ if (read_only) {
+ return;
+ }
+
Ref<InputEventKey> key_ref = p_event;
if (key_ref.is_valid()) {
const InputEventKey &key = **key_ref;
@@ -2151,7 +2170,7 @@ void EditorInspectorArray::drop_data_fw(const Point2 &p_point, const Variant &p_
}
bool EditorInspectorArray::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
- if (!movable) {
+ if (!movable || read_only) {
return false;
}
// First, update drawing.
@@ -2271,7 +2290,9 @@ VBoxContainer *EditorInspectorArray::get_vbox(int p_index) {
}
}
-EditorInspectorArray::EditorInspectorArray() {
+EditorInspectorArray::EditorInspectorArray(bool p_read_only) {
+ read_only = p_read_only;
+
set_mouse_filter(Control::MOUSE_FILTER_STOP);
odd_style.instantiate();
@@ -2297,6 +2318,7 @@ EditorInspectorArray::EditorInspectorArray() {
add_button = EditorInspector::create_inspector_action_button(TTR("Add Element"));
add_button->connect("pressed", callable_mp(this, &EditorInspectorArray::_add_button_pressed));
+ add_button->set_disabled(read_only);
vbox->add_child(add_button);
control_dropping = memnew(Control);
@@ -2317,6 +2339,7 @@ EditorInspectorArray::EditorInspectorArray() {
new_size_spin_box->set_max(16384);
new_size_spin_box->connect("value_changed", callable_mp(this, &EditorInspectorArray::_new_size_spin_box_value_changed));
new_size_spin_box->get_line_edit()->connect("text_submitted", callable_mp(this, &EditorInspectorArray::_new_size_spin_box_text_submitted));
+ new_size_spin_box->set_editable(!read_only);
resize_dialog_vbox->add_margin_child(TTRC("New Size:"), new_size_spin_box);
vbox->connect("visibility_changed", callable_mp(this, &EditorInspectorArray::_vbox_visibility_changed));
@@ -2544,7 +2567,7 @@ void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, EditorIn
ep->set_read_only(read_only);
ep->update_property();
ep->_update_pin_flags();
- ep->update_revert_and_pin_status();
+ ep->update_editor_property_status();
ep->set_deletable(deletable_properties);
ep->update_cache();
}
@@ -3030,7 +3053,7 @@ void EditorInspector::update_tree() {
bool movable = true;
bool numbered = false;
bool foldable = use_folding;
- String add_button_text;
+ String add_button_text = TTR("Add Element");
String swap_method;
for (int i = (p.type == Variant::NIL ? 1 : 2); i < class_name_components.size(); i++) {
if (class_name_components[i].begins_with("page_size") && class_name_components[i].get_slice_count("=") == 2) {
@@ -3051,7 +3074,7 @@ void EditorInspector::update_tree() {
if (p.type == Variant::NIL) {
// Setup the array to use a method to create/move/delete elements.
array_element_prefix = class_name_components[0];
- editor_inspector_array = memnew(EditorInspectorArray);
+ editor_inspector_array = memnew(EditorInspectorArray(all_read_only));
String array_label = path.contains("/") ? path.substr(path.rfind("/") + 1) : path;
array_label = EditorPropertyNameProcessor::get_singleton()->process_name(property_label_string, property_name_style);
@@ -3063,7 +3086,7 @@ void EditorInspector::update_tree() {
// Setup the array to use the count property and built-in functions to create/move/delete elements.
if (class_name_components.size() >= 2) {
array_element_prefix = class_name_components[1];
- editor_inspector_array = memnew(EditorInspectorArray);
+ editor_inspector_array = memnew(EditorInspectorArray(all_read_only));
int page = per_array_page.has(array_element_prefix) ? per_array_page[array_element_prefix] : 0;
editor_inspector_array->setup_with_count_property(object, class_name_components[0], p.name, array_element_prefix, page, c, foldable, movable, numbered, page_size, add_button_text, swap_method);
@@ -3203,6 +3226,7 @@ void EditorInspector::update_tree() {
// Use the existing one.
ep->set_label(property_label_string);
}
+
for (int j = 0; j < properties.size(); j++) {
String prop = properties[j];
@@ -3250,7 +3274,7 @@ void EditorInspector::update_tree() {
ep->set_doc_path(doc_info.path);
ep->update_property();
ep->_update_pin_flags();
- ep->update_revert_and_pin_status();
+ ep->update_editor_property_status();
ep->update_cache();
if (current_selected && ep->property == current_selected) {
@@ -3289,7 +3313,7 @@ void EditorInspector::update_property(const String &p_prop) {
for (EditorProperty *E : editor_property_map[p_prop]) {
E->update_property();
- E->update_revert_and_pin_status();
+ E->update_editor_property_status();
E->update_cache();
}
}
@@ -3632,7 +3656,7 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
if (editor_property_map.has(p_name)) {
for (EditorProperty *E : editor_property_map[p_name]) {
- E->update_revert_and_pin_status();
+ E->update_editor_property_status();
}
}
}
@@ -3746,7 +3770,7 @@ void EditorInspector::_property_checked(const String &p_path, bool p_checked) {
for (EditorProperty *E : editor_property_map[p_path]) {
E->set_checked(p_checked);
E->update_property();
- E->update_revert_and_pin_status();
+ E->update_editor_property_status();
E->update_cache();
}
}
@@ -3770,8 +3794,8 @@ void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) {
undo_redo->add_undo_method(node, "_set_property_pinned", p_path, !p_pinned);
if (editor_property_map.has(p_path)) {
for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) {
- undo_redo->add_do_method(E->get(), "_update_revert_and_pin_status");
- undo_redo->add_undo_method(E->get(), "_update_revert_and_pin_status");
+ undo_redo->add_do_method(E->get(), "_update_editor_property_status");
+ undo_redo->add_undo_method(E->get(), "_update_editor_property_status");
}
}
undo_redo->commit_action();
@@ -3779,7 +3803,7 @@ void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) {
node->set_property_pinned(p_path, p_pinned);
if (editor_property_map.has(p_path)) {
for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) {
- E->get()->update_revert_and_pin_status();
+ E->get()->update_editor_property_status();
}
}
}
@@ -3860,7 +3884,7 @@ void EditorInspector::_notification(int p_what) {
for (EditorProperty *E : F.value) {
if (E && !E->is_cache_valid()) {
E->update_property();
- E->update_revert_and_pin_status();
+ E->update_editor_property_status();
E->update_cache();
}
}
@@ -3882,7 +3906,7 @@ void EditorInspector::_notification(int p_what) {
if (editor_property_map.has(prop)) {
for (EditorProperty *E : editor_property_map[prop]) {
E->update_property();
- E->update_revert_and_pin_status();
+ E->update_editor_property_status();
E->update_cache();
}
}
@@ -3975,13 +3999,7 @@ void EditorInspector::_check_meta_name(const String &p_name) {
} else if (!p_name.is_valid_identifier()) {
error = TTR("Metadata name must be a valid identifier.");
} else if (object->has_meta(p_name)) {
- Node *node = Object::cast_to<Node>(object);
- if (node) {
- error = vformat(TTR("Metadata with name \"%s\" already exists on \"%s\"."), p_name, node->get_name());
- } else {
- // This should normally never be reached, but the error is set just in case.
- error = vformat(TTR("Metadata with name \"%s\" already exists."), p_name, node->get_name());
- }
+ error = vformat(TTR("Metadata with name \"%s\" already exists."), p_name);
} else if (p_name[0] == '_') {
error = TTR("Names starting with _ are reserved for editor-only metadata.");
}
@@ -4001,14 +4019,6 @@ void EditorInspector::_show_add_meta_dialog() {
if (!add_meta_dialog) {
add_meta_dialog = memnew(ConfirmationDialog);
- Node *node = Object::cast_to<Node>(object);
- if (node) {
- add_meta_dialog->set_title(vformat(TTR("Add Metadata Property for \"%s\""), node->get_name()));
- } else {
- // This should normally never be reached, but the title is set just in case.
- add_meta_dialog->set_title(vformat(TTR("Add Metadata Property"), node->get_name()));
- }
-
VBoxContainer *vbc = memnew(VBoxContainer);
add_meta_dialog->add_child(vbc);
HBoxContainer *hbc = memnew(HBoxContainer);
@@ -4038,6 +4048,14 @@ void EditorInspector::_show_add_meta_dialog() {
add_meta_name->connect("text_changed", callable_mp(this, &EditorInspector::_check_meta_name));
}
+ Node *node = Object::cast_to<Node>(object);
+ if (node) {
+ add_meta_dialog->set_title(vformat(TTR("Add Metadata Property for \"%s\""), node->get_name()));
+ } else {
+ // This should normally be reached when the object is derived from Resource.
+ add_meta_dialog->set_title(vformat(TTR("Add Metadata Property for \"%s\""), object->get_class()));
+ }
+
add_meta_dialog->popup_centered();
add_meta_name->set_text("");
_check_meta_name("");
@@ -4046,6 +4064,7 @@ void EditorInspector::_show_add_meta_dialog() {
void EditorInspector::_bind_methods() {
ClassDB::bind_method("_edit_request_change", &EditorInspector::_edit_request_change);
+ ClassDB::bind_method("get_selected_path", &EditorInspector::get_selected_path);
ADD_SIGNAL(MethodInfo("property_selected", PropertyInfo(Variant::STRING, "property")));
ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::BOOL, "advance")));
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index d634eae23f..872007e637 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -120,6 +120,8 @@ private:
HashMap<StringName, Variant> cache;
GDVIRTUAL0(_update_property)
+ GDVIRTUAL1(_set_read_only, bool)
+
void _update_pin_flags();
protected:
@@ -151,7 +153,7 @@ public:
void set_doc_path(const String &p_doc_path);
virtual void update_property();
- void update_revert_and_pin_status();
+ void update_editor_property_status();
virtual bool use_keying_next() const;
@@ -333,6 +335,7 @@ class EditorInspectorArray : public EditorInspectorSection {
int begin_array_index = 0;
int end_array_index = 0;
+ bool read_only = false;
bool movable = true;
bool numbered = false;
@@ -404,7 +407,7 @@ public:
void setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "", const String &p_swap_method = "");
VBoxContainer *get_vbox(int p_index);
- EditorInspectorArray();
+ EditorInspectorArray(bool p_read_only);
};
class EditorPaginator : public HBoxContainer {
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 804722299c..28768b7f34 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -429,7 +429,7 @@ void EditorNode::_version_control_menu_option(int p_idx) {
void EditorNode::_update_title() {
const String appname = ProjectSettings::get_singleton()->get("application/config/name");
- String title = (appname.is_empty() ? TTR("Unnamed Project") : appname) + String(" - ") + VERSION_NAME;
+ String title = (appname.is_empty() ? TTR("Unnamed Project") : appname);
const String edited = editor_data.get_edited_scene_root() ? editor_data.get_edited_scene_root()->get_scene_file_path() : String();
if (!edited.is_empty()) {
// Display the edited scene name before the program name so that it can be seen in the OS task bar.
@@ -439,8 +439,10 @@ void EditorNode::_update_title() {
// Display the "modified" mark before anything else so that it can always be seen in the OS task bar.
title = vformat("(*) %s", title);
}
-
- DisplayServer::get_singleton()->window_set_title(title);
+ DisplayServer::get_singleton()->window_set_title(title + String(" - ") + VERSION_NAME);
+ if (project_title) {
+ project_title->set_text(title);
+ }
}
void EditorNode::shortcut_input(const Ref<InputEvent> &p_event) {
@@ -465,15 +467,15 @@ void EditorNode::shortcut_input(const Ref<InputEvent> &p_event) {
}
if (ED_IS_SHORTCUT("editor/editor_2d", p_event)) {
- _editor_select(EDITOR_2D);
+ editor_select(EDITOR_2D);
} else if (ED_IS_SHORTCUT("editor/editor_3d", p_event)) {
- _editor_select(EDITOR_3D);
+ editor_select(EDITOR_3D);
} else if (ED_IS_SHORTCUT("editor/editor_script", p_event)) {
- _editor_select(EDITOR_SCRIPT);
+ editor_select(EDITOR_SCRIPT);
} else if (ED_IS_SHORTCUT("editor/editor_help", p_event)) {
emit_signal(SNAME("request_help_search"), "");
} else if (ED_IS_SHORTCUT("editor/editor_assetlib", p_event) && AssetLibraryEditorPlugin::is_available()) {
- _editor_select(EDITOR_ASSETLIB);
+ editor_select(EDITOR_ASSETLIB);
} else if (ED_IS_SHORTCUT("editor/editor_next", p_event)) {
_editor_select_next();
} else if (ED_IS_SHORTCUT("editor/editor_prev", p_event)) {
@@ -584,7 +586,7 @@ void EditorNode::_update_from_settings() {
void EditorNode::_select_default_main_screen_plugin() {
if (EDITOR_3D < main_editor_buttons.size() && main_editor_buttons[EDITOR_3D]->is_visible()) {
// If the 3D editor is enabled, use this as the default.
- _editor_select(EDITOR_3D);
+ editor_select(EDITOR_3D);
return;
}
@@ -593,12 +595,12 @@ void EditorNode::_select_default_main_screen_plugin() {
for (int i = 0; i < main_editor_buttons.size(); i++) {
Button *editor_button = main_editor_buttons[i];
if (editor_button->is_visible()) {
- _editor_select(i);
+ editor_select(i);
return;
}
}
- _editor_select(-1);
+ editor_select(-1);
}
void EditorNode::_notification(int p_what) {
@@ -659,6 +661,12 @@ void EditorNode::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
Engine::get_singleton()->set_editor_hint(true);
+ Window *window = static_cast<Window *>(get_tree()->get_root());
+ if (window) {
+ // Handle macOS fullscreen and extend-to-title changes.
+ window->connect("titlebar_changed", callable_mp(this, &EditorNode::_titlebar_resized));
+ }
+
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/low_processor_mode_sleep_usec")));
get_tree()->get_root()->set_as_audio_listener_3d(false);
get_tree()->get_root()->set_as_audio_listener_2d(false);
@@ -713,6 +721,8 @@ void EditorNode::_notification(int p_what) {
ProjectSettings::get_singleton()->save();
}
+ _titlebar_resized();
+
/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
} break;
@@ -750,7 +760,8 @@ void EditorNode::_notification(int p_what) {
EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor/theme") ||
EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/font") ||
EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/main_font") ||
- EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/code_font");
+ EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/code_font") ||
+ EditorSettings::get_singleton()->check_changed_settings_in_group("filesystem/file_dialog/thumbnail_size");
if (theme_changed) {
theme = create_custom_theme(theme_base->get_theme());
@@ -1169,6 +1180,18 @@ void EditorNode::_reload_project_settings() {
void EditorNode::_vp_resized() {
}
+void EditorNode::_titlebar_resized() {
+ const Size2 &margin = DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID);
+ if (left_menu_spacer) {
+ int w = (gui_base->is_layout_rtl()) ? margin.y : margin.x;
+ left_menu_spacer->set_custom_minimum_size(Size2(w, 0));
+ }
+ if (right_menu_spacer) {
+ int w = (gui_base->is_layout_rtl()) ? margin.x : margin.y;
+ right_menu_spacer->set_custom_minimum_size(Size2(w, 0));
+ }
+}
+
void EditorNode::_version_button_pressed() {
DisplayServer::get_singleton()->clipboard_set(version_btn->get_meta(META_TEXT_TO_COPY));
}
@@ -1190,7 +1213,7 @@ void EditorNode::_editor_select_next() {
}
} while (!main_editor_buttons[editor]->is_visible());
- _editor_select(editor);
+ editor_select(editor);
}
void EditorNode::_open_command_palette() {
@@ -1208,7 +1231,7 @@ void EditorNode::_editor_select_prev() {
}
} while (!main_editor_buttons[editor]->is_visible());
- _editor_select(editor);
+ editor_select(editor);
}
Error EditorNode::load_resource(const String &p_resource, bool p_ignore_broken_deps) {
@@ -2390,7 +2413,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
else if (main_plugin != editor_plugin_screen && (!ScriptEditor::get_singleton() || !ScriptEditor::get_singleton()->is_visible_in_tree() || ScriptEditor::get_singleton()->can_take_away_focus())) {
// Update screen main_plugin.
- _editor_select(plugin_index);
+ editor_select(plugin_index);
main_plugin->edit(current_obj);
} else {
editor_plugin_screen->edit(current_obj);
@@ -2450,7 +2473,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
write_movie_file = GLOBAL_GET("editor/movie_writer/movie_file");
}
if (write_movie_file == String()) {
- show_accept(TTR("Movie Maker mode is enabled, but no movie file path has been specified.\nA default movie file path can be specified in the project settings under the 'Editor/Movie Writer' category.\nAlternatively, for running single scenes, a 'movie_path' metadata can be added to the root node,\nspecifying the path to a movie file that will be used when recording that scene."), TTR("OK"));
+ show_accept(TTR("Movie Maker mode is enabled, but no movie file path has been specified.\nA default movie file path can be specified in the project settings under the Editor > Movie Writer category.\nAlternatively, for running single scenes, a `movie_file` string metadata can be added to the root node,\nspecifying the path to a movie file that will be used when recording that scene."), TTR("OK"));
return;
}
}
@@ -2763,18 +2786,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
}
} else if (extensions.size()) {
String root_name = scene->get_name();
- // Very similar to node naming logic.
- switch (ProjectSettings::get_singleton()->get("editor/scene/scene_naming").operator int()) {
- case SCENE_NAME_CASING_AUTO:
- // Use casing of the root node.
- break;
- case SCENE_NAME_CASING_PASCAL_CASE: {
- root_name = root_name.to_pascal_case();
- } break;
- case SCENE_NAME_CASING_SNAKE_CASE:
- root_name = root_name.replace("-", "_").to_snake_case();
- break;
- }
+ root_name = EditorNode::adjust_scene_name_casing(root_name);
file->set_current_path(root_name + "." + extensions.front()->get().to_lower());
}
file->popup_file_dialog();
@@ -3080,8 +3092,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case HELP_SUPPORT_GODOT_DEVELOPMENT: {
OS::get_singleton()->shell_open("https://godotengine.org/donate");
} break;
- case SET_RENDERING_DRIVER_SAVE_AND_RESTART: {
- ProjectSettings::get_singleton()->set("rendering/driver/driver_name", rendering_driver_request);
+ case SET_RENDERER_NAME_SAVE_AND_RESTART: {
+ ProjectSettings::get_singleton()->set("rendering/renderer/rendering_method", renderer_request);
ProjectSettings::get_singleton()->save();
save_all_scenes();
@@ -3090,6 +3102,19 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
}
}
+String EditorNode::adjust_scene_name_casing(const String &root_name) {
+ switch (ProjectSettings::get_singleton()->get("editor/scene/scene_naming").operator int()) {
+ case SCENE_NAME_CASING_AUTO:
+ // Use casing of the root node.
+ break;
+ case SCENE_NAME_CASING_PASCAL_CASE:
+ return root_name.to_pascal_case();
+ case SCENE_NAME_CASING_SNAKE_CASE:
+ return root_name.replace("-", "_").to_snake_case();
+ }
+ return root_name;
+}
+
void EditorNode::_request_screenshot() {
_screenshot();
}
@@ -3303,7 +3328,7 @@ VBoxContainer *EditorNode::get_main_screen_control() {
return main_screen_vbox;
}
-void EditorNode::_editor_select(int p_which) {
+void EditorNode::editor_select(int p_which) {
static bool selecting = false;
if (selecting || changing_scene) {
return;
@@ -3357,7 +3382,7 @@ void EditorNode::select_editor_by_name(const String &p_name) {
for (int i = 0; i < main_editor_buttons.size(); i++) {
if (main_editor_buttons[i]->get_text() == p_name) {
- _editor_select(i);
+ editor_select(i);
return;
}
}
@@ -3370,7 +3395,7 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed
Button *tb = memnew(Button);
tb->set_flat(true);
tb->set_toggle_mode(true);
- tb->connect("pressed", callable_mp(singleton, &EditorNode::_editor_select).bind(singleton->main_editor_buttons.size()));
+ tb->connect("pressed", callable_mp(singleton, &EditorNode::editor_select).bind(singleton->main_editor_buttons.size()));
tb->set_name(p_editor->get_name());
tb->set_text(p_editor->get_name());
@@ -3387,7 +3412,7 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed
tb->add_theme_font_size_override("font_size", singleton->gui_base->get_theme_font_size(SNAME("main_button_font_size"), SNAME("EditorFonts")));
singleton->main_editor_buttons.push_back(tb);
- singleton->main_editor_button_vb->add_child(tb);
+ singleton->main_editor_button_hb->add_child(tb);
singleton->editor_table.push_back(p_editor);
singleton->distraction_free->move_to_front();
@@ -3404,7 +3429,7 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor, bool p_config_chan
for (int i = 0; i < singleton->main_editor_buttons.size(); i++) {
if (p_editor->get_name() == singleton->main_editor_buttons[i]->get_text()) {
if (singleton->main_editor_buttons[i]->is_pressed()) {
- singleton->_editor_select(EDITOR_SCRIPT);
+ singleton->editor_select(EDITOR_SCRIPT);
}
memdelete(singleton->main_editor_buttons[i]);
@@ -3628,7 +3653,7 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) {
int index = p_state["editor_index"];
if (current < 2) { // If currently in spatial/2d, only switch to spatial/2d. If currently in script, stay there.
if (index < 2 || !get_edited_scene()) {
- _editor_select(index);
+ editor_select(index);
}
}
}
@@ -3639,9 +3664,9 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) {
int n2d = 0, n3d = 0;
_find_node_types(get_edited_scene(), n2d, n3d);
if (n2d > n3d) {
- _editor_select(EDITOR_2D);
+ editor_select(EDITOR_2D);
} else if (n3d > n2d) {
- _editor_select(EDITOR_3D);
+ editor_select(EDITOR_3D);
}
}
}
@@ -3668,10 +3693,6 @@ bool EditorNode::is_changing_scene() const {
return changing_scene;
}
-void EditorNode::_clear_undo_history() {
- get_undo_redo()->clear_history(false);
-}
-
void EditorNode::set_current_scene(int p_idx) {
// Save the folding in case the scene gets reloaded.
if (editor_data.get_scene_path(p_idx) != "" && editor_data.get_edited_scene_root(p_idx)) {
@@ -3932,7 +3953,7 @@ void EditorNode::edit_foreign_resource(Ref<Resource> p_resource) {
InspectorDock::get_singleton()->call_deferred("edit_resource", p_resource);
}
-bool EditorNode::is_resource_read_only(Ref<Resource> p_resource) {
+bool EditorNode::is_resource_read_only(Ref<Resource> p_resource, bool p_foreign_resources_are_writable) {
ERR_FAIL_COND_V(p_resource.is_null(), false);
String path = p_resource->get_path();
@@ -3944,7 +3965,11 @@ bool EditorNode::is_resource_read_only(Ref<Resource> p_resource) {
// If the base resource is a packed scene, we treat it as read-only if it is not the currently edited scene.
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) {
- return true;
+ // If we have not flagged foreign resources as writable or the base scene the resource is
+ // part was imported, it can be considered read-only.
+ if (!p_foreign_resources_are_writable || FileAccess::exists(base + ".import")) {
+ return true;
+ }
}
} else {
// If a corresponding .import file exists for the base file, we assume it to be imported and should therefore treated as read-only.
@@ -5878,27 +5903,27 @@ void EditorNode::_bottom_panel_raise_toggled(bool p_pressed) {
top_split->set_visible(!p_pressed);
}
-void EditorNode::_update_rendering_driver_color() {
- if (rendering_driver->get_text() == "opengl3") {
- rendering_driver->add_theme_color_override("font_color", Color::hex(0x5586a4ff));
- } else if (rendering_driver->get_text() == "vulkan") {
- rendering_driver->add_theme_color_override("font_color", theme_base->get_theme_color(SNAME("vulkan_color"), SNAME("Editor")));
+void EditorNode::_update_renderer_color() {
+ if (renderer->get_text() == "gl_compatibility") {
+ renderer->add_theme_color_override("font_color", Color::hex(0x5586a4ff));
+ } else if (renderer->get_text() == "forward_plus" || renderer->get_text() == "mobile") {
+ renderer->add_theme_color_override("font_color", theme_base->get_theme_color(SNAME("vulkan_color"), SNAME("Editor")));
}
}
-void EditorNode::_rendering_driver_selected(int p_which) {
- String driver = rendering_driver->get_item_metadata(p_which);
+void EditorNode::_renderer_selected(int p_which) {
+ String rendering_method = renderer->get_item_metadata(p_which);
- String current_driver = OS::get_singleton()->get_current_rendering_driver_name();
+ String current_renderer = GLOBAL_GET("rendering/renderer/rendering_method");
- if (driver == current_driver) {
+ if (rendering_method == current_renderer) {
return;
}
- rendering_driver_request = driver;
+ renderer_request = rendering_method;
video_restart_dialog->popup_centered();
- rendering_driver->select(rendering_driver_current);
- _update_rendering_driver_color();
+ renderer->select(renderer_current);
+ _update_renderer_color();
}
void EditorNode::_resource_saved(Ref<Resource> p_resource, const String &p_path) {
@@ -5933,7 +5958,7 @@ void EditorNode::_feature_profile_changed() {
if ((profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D) && singleton->main_editor_buttons[EDITOR_3D]->is_pressed()) ||
(profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCRIPT) && singleton->main_editor_buttons[EDITOR_SCRIPT]->is_pressed()) ||
(AssetLibraryEditorPlugin::is_available() && profile->is_feature_disabled(EditorFeatureProfile::FEATURE_ASSET_LIB) && singleton->main_editor_buttons[EDITOR_ASSETLIB]->is_pressed())) {
- _editor_select(EDITOR_2D);
+ editor_select(EDITOR_2D);
}
} else {
import_tabs->set_tab_hidden(import_tabs->get_tab_idx_from_control(ImportDock::get_singleton()), false);
@@ -5956,19 +5981,14 @@ void EditorNode::_bind_methods() {
GLOBAL_DEF("editor/scene/scene_naming", SCENE_NAME_CASING_SNAKE_CASE);
ProjectSettings::get_singleton()->set_custom_property_info("editor/scene/scene_naming", PropertyInfo(Variant::INT, "editor/scene/scene_naming", PROPERTY_HINT_ENUM, "Auto,PascalCase,snake_case"));
ClassDB::bind_method("edit_current", &EditorNode::edit_current);
- ClassDB::bind_method("_editor_select", &EditorNode::_editor_select);
- ClassDB::bind_method("_node_renamed", &EditorNode::_node_renamed);
ClassDB::bind_method("edit_node", &EditorNode::edit_node);
ClassDB::bind_method(D_METHOD("push_item", "object", "property", "inspector_only"), &EditorNode::push_item, DEFVAL(""), DEFVAL(false));
- ClassDB::bind_method("_get_scene_metadata", &EditorNode::_get_scene_metadata);
ClassDB::bind_method("set_edited_scene", &EditorNode::set_edited_scene);
ClassDB::bind_method("open_request", &EditorNode::open_request);
ClassDB::bind_method("edit_foreign_resource", &EditorNode::edit_foreign_resource);
ClassDB::bind_method("is_resource_read_only", &EditorNode::is_resource_read_only);
- ClassDB::bind_method("_close_messages", &EditorNode::_close_messages);
- ClassDB::bind_method("_show_messages", &EditorNode::_show_messages);
ClassDB::bind_method("stop_child_process", &EditorNode::stop_child_process);
@@ -5977,19 +5997,10 @@ void EditorNode::_bind_methods() {
ClassDB::bind_method("_set_main_scene_state", &EditorNode::_set_main_scene_state);
ClassDB::bind_method("_update_recent_scenes", &EditorNode::_update_recent_scenes);
- ClassDB::bind_method("_clear_undo_history", &EditorNode::_clear_undo_history);
-
ClassDB::bind_method("edit_item_resource", &EditorNode::edit_item_resource);
ClassDB::bind_method(D_METHOD("get_gui_base"), &EditorNode::get_gui_base);
- ClassDB::bind_method(D_METHOD("_on_plugin_ready"), &EditorNode::_on_plugin_ready); // Still used by some connect_compat.
-
- ClassDB::bind_method("_screenshot", &EditorNode::_screenshot);
- ClassDB::bind_method("_save_screenshot", &EditorNode::_save_screenshot);
-
- ClassDB::bind_method("_version_button_pressed", &EditorNode::_version_button_pressed);
-
ADD_SIGNAL(MethodInfo("play_pressed"));
ADD_SIGNAL(MethodInfo("pause_pressed"));
ADD_SIGNAL(MethodInfo("stop_pressed"));
@@ -6601,14 +6612,14 @@ EditorNode::EditorNode() {
if (can_expand) {
// Add spacer to avoid other controls under window minimize/maximize/close buttons (left side).
- Control *menu_spacer = memnew(Control);
- menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
- menu_spacer->set_custom_minimum_size(Size2(DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID).x, 0));
- menu_hb->add_child(menu_spacer);
+ left_menu_spacer = memnew(Control);
+ left_menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ menu_hb->add_child(left_menu_spacer);
}
main_menu = memnew(MenuBar);
menu_hb->add_child(main_menu);
+
main_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
main_menu->set_flat(true);
main_menu->set_start_index(0); // Main menu, add to the start of global menu.
@@ -6777,22 +6788,30 @@ EditorNode::EditorNode() {
project_menu->add_shortcut(ED_GET_SHORTCUT("editor/quit_to_project_list"), RUN_PROJECT_MANAGER, true);
// Spacer to center 2D / 3D / Script buttons.
- Control *left_spacer = memnew(Control);
+ HBoxContainer *left_spacer = memnew(HBoxContainer);
left_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ left_spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL);
menu_hb->add_child(left_spacer);
- menu_hb->add_spacer();
+ if (can_expand && global_menu) {
+ project_title = memnew(Label);
+ project_title->add_theme_font_override("font", gui_base->get_theme_font(SNAME("bold"), SNAME("EditorFonts")));
+ project_title->add_theme_font_size_override("font_size", gui_base->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")));
+ project_title->set_focus_mode(Control::FOCUS_NONE);
+ project_title->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
+ project_title->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
+ project_title->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ left_spacer->add_child(project_title);
+ }
- main_editor_button_vb = memnew(HBoxContainer);
- menu_hb->add_child(main_editor_button_vb);
+ main_editor_button_hb = memnew(HBoxContainer);
+ menu_hb->add_child(main_editor_button_hb);
// Options are added and handled by DebuggerEditorPlugin.
debug_menu = memnew(PopupMenu);
debug_menu->set_name(TTR("Debug"));
main_menu->add_child(debug_menu);
- menu_hb->add_spacer();
-
settings_menu = memnew(PopupMenu);
settings_menu->set_name(TTR("Editor"));
main_menu->add_child(settings_menu);
@@ -6866,6 +6885,7 @@ EditorNode::EditorNode() {
// Spacer to center 2D / 3D / Script buttons.
Control *right_spacer = memnew(Control);
right_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ right_spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL);
menu_hb->add_child(right_spacer);
launch_pad = memnew(PanelContainer);
@@ -6881,23 +6901,24 @@ EditorNode::EditorNode() {
play_button->set_toggle_mode(true);
play_button->set_focus_mode(Control::FOCUS_NONE);
play_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY));
+ play_button->set_tooltip_text(TTR("Run the project's default scene."));
- ED_SHORTCUT_AND_COMMAND("editor/play", TTR("Play"), Key::F5);
- ED_SHORTCUT_OVERRIDE("editor/play", "macos", KeyModifierMask::META | Key::B);
- play_button->set_shortcut(ED_GET_SHORTCUT("editor/play"));
+ ED_SHORTCUT_AND_COMMAND("editor/run_project", TTR("Run Project"), Key::F5);
+ ED_SHORTCUT_OVERRIDE("editor/run_project", "macos", KeyModifierMask::META | Key::B);
+ play_button->set_shortcut(ED_GET_SHORTCUT("editor/run_project"));
pause_button = memnew(Button);
pause_button->set_flat(true);
pause_button->set_toggle_mode(true);
pause_button->set_icon(gui_base->get_theme_icon(SNAME("Pause"), SNAME("EditorIcons")));
pause_button->set_focus_mode(Control::FOCUS_NONE);
- pause_button->set_tooltip_text(TTR("Pause the scene execution for debugging."));
+ pause_button->set_tooltip_text(TTR("Pause the running project's execution for debugging."));
pause_button->set_disabled(true);
launch_pad_hb->add_child(pause_button);
- ED_SHORTCUT("editor/pause_scene", TTR("Pause Scene"), Key::F7);
- ED_SHORTCUT_OVERRIDE("editor/pause_scene", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::Y);
- pause_button->set_shortcut(ED_GET_SHORTCUT("editor/pause_scene"));
+ ED_SHORTCUT("editor/pause_running_project", TTR("Pause Running Project"), Key::F7);
+ ED_SHORTCUT_OVERRIDE("editor/pause_running_project", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::Y);
+ pause_button->set_shortcut(ED_GET_SHORTCUT("editor/pause_running_project"));
stop_button = memnew(Button);
stop_button->set_flat(true);
@@ -6905,12 +6926,12 @@ EditorNode::EditorNode() {
stop_button->set_focus_mode(Control::FOCUS_NONE);
stop_button->set_icon(gui_base->get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")));
stop_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_STOP));
- stop_button->set_tooltip_text(TTR("Stop the scene."));
+ stop_button->set_tooltip_text(TTR("Stop the currently running project."));
stop_button->set_disabled(true);
- ED_SHORTCUT("editor/stop", TTR("Stop"), Key::F8);
- ED_SHORTCUT_OVERRIDE("editor/stop", "macos", KeyModifierMask::META | Key::PERIOD);
- stop_button->set_shortcut(ED_GET_SHORTCUT("editor/stop"));
+ ED_SHORTCUT("editor/stop_running_project", TTR("Stop Running Project"), Key::F8);
+ ED_SHORTCUT_OVERRIDE("editor/stop_running_project", "macos", KeyModifierMask::META | Key::PERIOD);
+ stop_button->set_shortcut(ED_GET_SHORTCUT("editor/stop_running_project"));
run_native = memnew(EditorRunNative);
launch_pad_hb->add_child(run_native);
@@ -6922,10 +6943,11 @@ EditorNode::EditorNode() {
play_scene_button->set_toggle_mode(true);
play_scene_button->set_focus_mode(Control::FOCUS_NONE);
play_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_SCENE));
+ play_scene_button->set_tooltip_text(TTR("Run the currently edited scene."));
- ED_SHORTCUT_AND_COMMAND("editor/play_scene", TTR("Play Scene"), Key::F6);
- ED_SHORTCUT_OVERRIDE("editor/play_scene", "macos", KeyModifierMask::META | Key::R);
- play_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/play_scene"));
+ ED_SHORTCUT_AND_COMMAND("editor/run_current_scene", TTR("Run Current Scene"), Key::F6);
+ ED_SHORTCUT_OVERRIDE("editor/run_current_scene", "macos", KeyModifierMask::META | Key::R);
+ play_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/run_current_scene"));
play_custom_scene_button = memnew(Button);
play_custom_scene_button->set_flat(true);
@@ -6933,12 +6955,11 @@ EditorNode::EditorNode() {
play_custom_scene_button->set_toggle_mode(true);
play_custom_scene_button->set_focus_mode(Control::FOCUS_NONE);
play_custom_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_CUSTOM_SCENE));
+ play_custom_scene_button->set_tooltip_text(TTR("Run a specific scene."));
- _reset_play_buttons();
-
- ED_SHORTCUT_AND_COMMAND("editor/play_custom_scene", TTR("Play Custom Scene"), KeyModifierMask::CTRL | KeyModifierMask::SHIFT | Key::F5);
- ED_SHORTCUT_OVERRIDE("editor/play_custom_scene", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::R);
- play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/play_custom_scene"));
+ ED_SHORTCUT_AND_COMMAND("editor/run_specific_scene", TTR("Run Specific Scene"), KeyModifierMask::META | KeyModifierMask::SHIFT | Key::F5);
+ ED_SHORTCUT_OVERRIDE("editor/run_specific_scene", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::R);
+ play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/run_specific_scene"));
write_movie_panel = memnew(PanelContainer);
write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonNormal"), SNAME("EditorStyles")));
@@ -6962,58 +6983,54 @@ EditorNode::EditorNode() {
HBoxContainer *right_menu_hb = memnew(HBoxContainer);
menu_hb->add_child(right_menu_hb);
- rendering_driver = memnew(OptionButton);
-
+ renderer = memnew(OptionButton);
// Hide the renderer selection dropdown until OpenGL support is more mature.
// The renderer can still be changed in the project settings or using `--rendering-driver opengl3`.
- rendering_driver->set_visible(false);
-
- rendering_driver->set_flat(true);
- rendering_driver->set_focus_mode(Control::FOCUS_NONE);
- rendering_driver->connect("item_selected", callable_mp(this, &EditorNode::_rendering_driver_selected));
- rendering_driver->add_theme_font_override("font", gui_base->get_theme_font(SNAME("bold"), SNAME("EditorFonts")));
- rendering_driver->add_theme_font_size_override("font_size", gui_base->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")));
+ renderer->set_visible(false);
+ renderer->set_flat(true);
+ renderer->set_focus_mode(Control::FOCUS_NONE);
+ renderer->connect("item_selected", callable_mp(this, &EditorNode::_renderer_selected));
+ renderer->add_theme_font_override("font", gui_base->get_theme_font(SNAME("bold"), SNAME("EditorFonts")));
+ renderer->add_theme_font_size_override("font_size", gui_base->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")));
- right_menu_hb->add_child(rendering_driver);
+ right_menu_hb->add_child(renderer);
if (can_expand) {
// Add spacer to avoid other controls under the window minimize/maximize/close buttons (right side).
- Control *menu_spacer = memnew(Control);
- menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
- menu_spacer->set_custom_minimum_size(Size2(DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID).y, 0));
- menu_hb->add_child(menu_spacer);
+ right_menu_spacer = memnew(Control);
+ right_menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ menu_hb->add_child(right_menu_spacer);
}
- // Only display the render drivers that are available for this display driver.
- int display_driver_idx = OS::get_singleton()->get_display_driver_id();
- Vector<String> render_drivers = DisplayServer::get_create_function_rendering_drivers(display_driver_idx);
- String current_rendering_driver = OS::get_singleton()->get_current_rendering_driver_name();
+ String current_renderer = GLOBAL_GET("rendering/renderer/rendering_method");
+
+ PackedStringArray renderers = ProjectSettings::get_singleton()->get_custom_property_info().get(StringName("rendering/renderer/rendering_method")).hint_string.split(",", false);
// As we are doing string comparisons, keep in standard case to prevent problems with capitals
// "vulkan" in particular uses lowercase "v" in the code, and uppercase in the UI.
- current_rendering_driver = current_rendering_driver.to_lower();
+ current_renderer = current_renderer.to_lower();
- for (int i = 0; i < render_drivers.size(); i++) {
- String driver = render_drivers[i];
+ for (int i = 0; i < renderers.size(); i++) {
+ String rendering_method = renderers[i];
- // Add the driver to the UI.
- rendering_driver->add_item(driver);
- rendering_driver->set_item_metadata(i, driver);
+ // Add the renderers name to the UI.
+ renderer->add_item(rendering_method);
+ renderer->set_item_metadata(i, rendering_method);
// Lowercase for standard comparison.
- driver = driver.to_lower();
+ rendering_method = rendering_method.to_lower();
- if (current_rendering_driver == driver) {
- rendering_driver->select(i);
- rendering_driver_current = i;
+ if (current_renderer == rendering_method) {
+ renderer->select(i);
+ renderer_current = i;
}
}
- _update_rendering_driver_color();
+ _update_renderer_color();
video_restart_dialog = memnew(ConfirmationDialog);
- video_restart_dialog->set_text(TTR("Changing the video driver requires restarting the editor."));
+ video_restart_dialog->set_text(TTR("Changing the renderer requires restarting the editor."));
video_restart_dialog->set_ok_button_text(TTR("Save & Restart"));
- video_restart_dialog->connect("confirmed", callable_mp(this, &EditorNode::_menu_option).bind(SET_RENDERING_DRIVER_SAVE_AND_RESTART));
+ video_restart_dialog->connect("confirmed", callable_mp(this, &EditorNode::_menu_option).bind(SET_RENDERER_NAME_SAVE_AND_RESTART));
gui_base->add_child(video_restart_dialog);
progress_hb = memnew(BackgroundProgress);
@@ -7537,12 +7554,13 @@ EditorNode::EditorNode() {
screenshot_timer->set_owner(get_owner());
// Adjust spacers to center 2D / 3D / Script buttons.
- int max_w = MAX(launch_pad_hb->get_minimum_size().x + right_menu_hb->get_minimum_size().x, main_menu->get_minimum_size().x);
+ int max_w = MAX(launch_pad->get_minimum_size().x + right_menu_hb->get_minimum_size().x, main_menu->get_minimum_size().x);
left_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - main_menu->get_minimum_size().x), 0));
- right_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - launch_pad_hb->get_minimum_size().x - right_menu_hb->get_minimum_size().x), 0));
+ right_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - launch_pad->get_minimum_size().x - right_menu_hb->get_minimum_size().x), 0));
// Extend menu bar to window title.
if (can_expand) {
+ DisplayServer::get_singleton()->window_set_window_buttons_offset(Vector2i(menu_hb->get_minimum_size().y / 2, menu_hb->get_minimum_size().y / 2), DisplayServer::MAIN_WINDOW_ID);
DisplayServer::get_singleton()->window_set_flag(DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE, true, DisplayServer::MAIN_WINDOW_ID);
menu_hb->set_can_move_window(true);
}
diff --git a/editor/editor_node.h b/editor/editor_node.h
index df3d2ae0f8..fab280bc14 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -125,6 +125,12 @@ public:
EDITOR_ASSETLIB
};
+ enum SceneNameCasing {
+ SCENE_NAME_CASING_AUTO,
+ SCENE_NAME_CASING_PASCAL_CASE,
+ SCENE_NAME_CASING_SNAKE_CASE
+ };
+
struct ExecuteThreadArgs {
String path;
List<String> args;
@@ -218,7 +224,7 @@ private:
HELP_ABOUT,
HELP_SUPPORT_GODOT_DEVELOPMENT,
- SET_RENDERING_DRIVER_SAVE_AND_RESTART,
+ SET_RENDERER_NAME_SAVE_AND_RESTART,
GLOBAL_NEW_WINDOW,
GLOBAL_SCENE,
@@ -233,12 +239,6 @@ private:
MAX_BUILD_CALLBACKS = 128
};
- enum ScriptNameCasing {
- SCENE_NAME_CASING_AUTO,
- SCENE_NAME_CASING_PASCAL_CASE,
- SCENE_NAME_CASING_SNAKE_CASE
- };
-
struct BottomPanelItem {
String name;
Control *control = nullptr;
@@ -286,12 +286,12 @@ private:
Control *theme_base = nullptr;
Control *gui_base = nullptr;
VBoxContainer *main_vbox = nullptr;
- OptionButton *rendering_driver = nullptr;
+ OptionButton *renderer = nullptr;
ConfirmationDialog *video_restart_dialog = nullptr;
- int rendering_driver_current = 0;
- String rendering_driver_request;
+ int renderer_current = 0;
+ String renderer_request;
// Split containers.
HSplitContainer *left_l_hsplit = nullptr;
@@ -322,6 +322,9 @@ private:
HBoxContainer *bottom_hb = nullptr;
Control *vp_base = nullptr;
+ Label *project_title = nullptr;
+ Control *left_menu_spacer = nullptr;
+ Control *right_menu_spacer = nullptr;
EditorTitleBar *menu_hb = nullptr;
VBoxContainer *main_screen_vbox = nullptr;
MenuBar *main_menu = nullptr;
@@ -397,7 +400,7 @@ private:
String current_path;
MenuButton *update_spinner = nullptr;
- HBoxContainer *main_editor_button_vb = nullptr;
+ HBoxContainer *main_editor_button_hb = nullptr;
Vector<Button *> main_editor_buttons;
Vector<EditorPlugin *> editor_table;
@@ -543,7 +546,6 @@ private:
void _update_file_menu_opened();
void _update_file_menu_closed();
- void _on_plugin_ready(Object *p_script, const String &p_activate_name);
void _remove_plugin_from_enabled(const String &p_name);
void _fs_changed();
@@ -553,7 +555,6 @@ private:
void _node_renamed();
void _editor_select_next();
void _editor_select_prev();
- void _editor_select(int p_which);
void _set_scene_metadata(const String &p_file, int p_idx = -1);
void _get_scene_metadata(const String &p_file);
void _update_title();
@@ -562,6 +563,7 @@ private:
void _close_messages();
void _show_messages();
void _vp_resized();
+ void _titlebar_resized();
void _version_button_pressed();
int _save_external_resources();
@@ -599,8 +601,8 @@ private:
void _update_from_settings();
- void _rendering_driver_selected(int);
- void _update_rendering_driver_color();
+ void _renderer_selected(int);
+ void _update_renderer_color();
void _exit_editor(int p_exit_code);
@@ -658,8 +660,6 @@ private:
void _update_layouts_menu();
void _layout_menu_option(int p_id);
- void _clear_undo_history();
-
void _update_addon_config();
void _toggle_distraction_free_mode();
@@ -703,7 +703,11 @@ protected:
void set_current_tab(int p_tab);
public:
- void set_visible_editor(EditorTable p_table) { _editor_select(p_table); }
+ // Public for use with callable_mp.
+ void _on_plugin_ready(Object *p_script, const String &p_activate_name);
+
+ void editor_select(int p_which);
+ void set_visible_editor(EditorTable p_table) { editor_select(p_table); }
bool call_build();
@@ -720,6 +724,8 @@ public:
static HBoxContainer *get_menu_hb() { return singleton->menu_hb; }
static VSplitContainer *get_top_split() { return singleton->top_split; }
+ static String adjust_scene_name_casing(const String &root_name);
+
static bool has_unsaved_changes() { return singleton->unsaved_cache; }
static void disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames);
static void add_io_error(const String &p_error);
@@ -784,7 +790,7 @@ public:
void open_request(const String &p_path);
void edit_foreign_resource(Ref<Resource> p_resource);
- bool is_resource_read_only(Ref<Resource> p_resource);
+ bool is_resource_read_only(Ref<Resource> p_resource, bool p_foreign_resources_are_writable = false);
bool is_changing_scene() const;
diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp
index a8df486381..bd19df41fe 100644
--- a/editor/editor_plugin_settings.cpp
+++ b/editor/editor_plugin_settings.cpp
@@ -46,7 +46,7 @@ void EditorPluginSettings::_notification(int p_what) {
} break;
case Node::NOTIFICATION_READY: {
- plugin_config_dialog->connect("plugin_ready", Callable(EditorNode::get_singleton(), "_on_plugin_ready"));
+ plugin_config_dialog->connect("plugin_ready", callable_mp(EditorNode::get_singleton(), &EditorNode::_on_plugin_ready));
plugin_list->connect("button_clicked", callable_mp(this, &EditorPluginSettings::_cell_button_pressed));
} break;
}
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 7364258a07..3b99962435 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -1758,7 +1758,7 @@ void EditorPropertyVector2::_value_changed(double val, const String &p_name) {
Vector2 v2;
v2.x = spin[0]->get_value();
v2.y = spin[1]->get_value();
- emit_changed(get_edited_property(), v2, p_name);
+ emit_changed(get_edited_property(), v2, linked->is_pressed() ? "" : p_name);
}
void EditorPropertyVector2::update_property() {
@@ -2005,7 +2005,7 @@ void EditorPropertyVector3::_value_changed(double val, const String &p_name) {
v3.y = Math::deg_to_rad(v3.y);
v3.z = Math::deg_to_rad(v3.z);
}
- emit_changed(get_edited_property(), v3, p_name);
+ emit_changed(get_edited_property(), v3, linked->is_pressed() ? "" : p_name);
}
void EditorPropertyVector3::update_property() {
@@ -2171,7 +2171,7 @@ void EditorPropertyVector2i::_value_changed(double val, const String &p_name) {
Vector2i v2;
v2.x = spin[0]->get_value();
v2.y = spin[1]->get_value();
- emit_changed(get_edited_property(), v2, p_name);
+ emit_changed(get_edited_property(), v2, linked->is_pressed() ? "" : p_name);
}
void EditorPropertyVector2i::update_property() {
@@ -2413,7 +2413,7 @@ void EditorPropertyVector3i::_value_changed(double val, const String &p_name) {
v3.x = spin[0]->get_value();
v3.y = spin[1]->get_value();
v3.z = spin[2]->get_value();
- emit_changed(get_edited_property(), v3, p_name);
+ emit_changed(get_edited_property(), v3, linked->is_pressed() ? "" : p_name);
}
void EditorPropertyVector3i::update_property() {
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index ad84b30689..728a3b0f80 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -268,6 +268,7 @@ void EditorPropertyArray::update_property() {
size_slider->set_step(1);
size_slider->set_max(1000000);
size_slider->set_h_size_flags(SIZE_EXPAND_FILL);
+ size_slider->set_read_only(is_read_only());
size_slider->connect("value_changed", callable_mp(this, &EditorPropertyArray::_length_changed));
hbox->add_child(size_slider);
@@ -278,6 +279,7 @@ void EditorPropertyArray::update_property() {
button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Element"));
button_add_item->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
button_add_item->connect(SNAME("pressed"), callable_mp(this, &EditorPropertyArray::_add_element));
+ button_add_item->set_disabled(is_read_only());
vbox->add_child(button_add_item);
paginator = memnew(EditorPaginator);
@@ -328,6 +330,7 @@ void EditorPropertyArray::update_property() {
Button *reorder_button = memnew(Button);
reorder_button->set_icon(get_theme_icon(SNAME("TripleBar"), SNAME("EditorIcons")));
reorder_button->set_default_cursor_shape(Control::CURSOR_MOVE);
+ reorder_button->set_disabled(is_read_only());
reorder_button->connect("gui_input", callable_mp(this, &EditorPropertyArray::_reorder_button_gui_input));
reorder_button->connect("button_down", callable_mp(this, &EditorPropertyArray::_reorder_button_down).bind(i + offset));
reorder_button->connect("button_up", callable_mp(this, &EditorPropertyArray::_reorder_button_up));
@@ -358,6 +361,7 @@ void EditorPropertyArray::update_property() {
prop->connect("property_changed", callable_mp(this, &EditorPropertyArray::_property_changed));
prop->connect("object_id_selected", callable_mp(this, &EditorPropertyArray::_object_id_selected));
prop->set_h_size_flags(SIZE_EXPAND_FILL);
+ prop->set_read_only(is_read_only());
hbox->add_child(prop);
bool is_untyped_array = array.get_type() == Variant::ARRAY && subtype == Variant::NIL;
@@ -366,10 +370,12 @@ void EditorPropertyArray::update_property() {
Button *edit = memnew(Button);
edit->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
hbox->add_child(edit);
+ edit->set_disabled(is_read_only());
edit->connect("pressed", callable_mp(this, &EditorPropertyArray::_change_type).bind(edit, i + offset));
} else {
Button *remove = memnew(Button);
remove->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ remove->set_disabled(is_read_only());
remove->connect("pressed", callable_mp(this, &EditorPropertyArray::_remove_pressed).bind(i + offset));
hbox->add_child(remove);
}
@@ -409,6 +415,10 @@ void EditorPropertyArray::_button_draw() {
}
bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const {
+ if (is_read_only()) {
+ return false;
+ }
+
String allowed_type = Variant::get_type_name(subtype);
// When the subtype is of type Object, an additional subtype may be specified in the hint string
@@ -609,7 +619,7 @@ void EditorPropertyArray::setup(Variant::Type p_array_type, const String &p_hint
}
void EditorPropertyArray::_reorder_button_gui_input(const Ref<InputEvent> &p_event) {
- if (reorder_from_index < 0) {
+ if (reorder_from_index < 0 || is_read_only()) {
return;
}
@@ -646,6 +656,10 @@ void EditorPropertyArray::_reorder_button_gui_input(const Ref<InputEvent> &p_eve
}
void EditorPropertyArray::_reorder_button_down(int p_index) {
+ if (is_read_only()) {
+ return;
+ }
+
reorder_from_index = p_index;
reorder_to_index = p_index;
reorder_selected_element_hbox = Object::cast_to<HBoxContainer>(property_vbox->get_child(p_index % page_length));
@@ -656,6 +670,10 @@ void EditorPropertyArray::_reorder_button_down(int p_index) {
}
void EditorPropertyArray::_reorder_button_up() {
+ if (is_read_only()) {
+ return;
+ }
+
if (reorder_from_index != reorder_to_index) {
// Move the element.
Variant array = object->get_array();
@@ -1097,6 +1115,10 @@ void EditorPropertyDictionary::update_property() {
}
}
+ ERR_FAIL_COND(!prop);
+
+ prop->set_read_only(is_read_only());
+
if (i == amount) {
PanelContainer *pc = memnew(PanelContainer);
property_vbox->add_child(pc);
@@ -1135,6 +1157,7 @@ void EditorPropertyDictionary::update_property() {
prop->set_h_size_flags(SIZE_EXPAND_FILL);
Button *edit = memnew(Button);
edit->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
+ edit->set_disabled(is_read_only());
hbox->add_child(edit);
edit->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_change_type).bind(edit, change_index));
@@ -1143,6 +1166,7 @@ void EditorPropertyDictionary::update_property() {
if (i == amount + 1) {
button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Key/Value Pair"));
button_add_item->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
+ button_add_item->set_disabled(is_read_only());
button_add_item->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_add_key_value));
add_vbox->add_child(button_add_item);
}
diff --git a/editor/editor_quick_open.cpp b/editor/editor_quick_open.cpp
index 539cb7cd8a..b4ec3bca15 100644
--- a/editor/editor_quick_open.cpp
+++ b/editor/editor_quick_open.cpp
@@ -31,6 +31,7 @@
#include "editor_quick_open.h"
#include "core/os/keyboard.h"
+#include "editor/editor_node.h"
void EditorQuickOpen::popup_dialog(const StringName &p_base, bool p_enable_multi, bool p_dontclear) {
base_type = p_base;
@@ -57,17 +58,29 @@ void EditorQuickOpen::_build_search_cache(EditorFileSystemDirectory *p_efsd) {
Vector<String> base_types = String(base_type).split(String(","));
for (int i = 0; i < p_efsd->get_file_count(); i++) {
- String file_type = p_efsd->get_file_type(i);
+ String file = p_efsd->get_file_path(i);
+ String engine_type = p_efsd->get_file_type(i);
+ // TODO: Fix lack of caching for resource's script's global class name (if applicable).
+ String script_type;
+ if (_load_resources) {
+ Ref<Resource> res = ResourceLoader::load(file);
+ if (res.is_valid()) {
+ Ref<Script> scr = res->get_script();
+ if (scr.is_valid()) {
+ script_type = scr->get_language()->get_global_class_name(file);
+ }
+ }
+ }
+ String actual_type = script_type.is_empty() ? engine_type : script_type;
// Iterate all possible base types.
for (String &parent_type : base_types) {
- if (ClassDB::is_parent_class(file_type, parent_type)) {
- String file = p_efsd->get_file_path(i);
+ if (ClassDB::is_parent_class(engine_type, parent_type) || EditorNode::get_editor_data().script_class_is_parent(script_type, parent_type)) {
files.push_back(file.substr(6, file.length()));
// Store refs to used icons.
String ext = file.get_extension();
if (!icons.has(ext)) {
- icons.insert(ext, get_theme_icon((has_theme_icon(file_type, SNAME("EditorIcons")) ? file_type : String("Object")), SNAME("EditorIcons")));
+ icons.insert(ext, get_theme_icon((has_theme_icon(actual_type, SNAME("EditorIcons")) ? actual_type : String("Object")), SNAME("EditorIcons")));
}
// Stop testing base types as soon as we got a match.
diff --git a/editor/editor_quick_open.h b/editor/editor_quick_open.h
index e41a8c7e75..83cbbd7cac 100644
--- a/editor/editor_quick_open.h
+++ b/editor/editor_quick_open.h
@@ -43,6 +43,7 @@ class EditorQuickOpen : public ConfirmationDialog {
Tree *search_options = nullptr;
StringName base_type;
bool allow_multi_select = false;
+ bool _load_resources = false; // Prohibitively slow for now.
Vector<String> files;
OAHashMap<String, Ref<Texture2D>> icons;
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index 5346052f4d..de8259c25c 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -53,6 +53,7 @@ void EditorResourcePicker::_update_resource() {
if (edited_resource.is_valid() && edited_resource->get_path().is_resource_file()) {
resource_path = edited_resource->get_path() + "\n";
}
+ String class_name = _get_resource_type(edited_resource);
if (preview_rect) {
preview_rect->set_texture(Ref<Texture2D>());
@@ -64,16 +65,20 @@ void EditorResourcePicker::_update_resource() {
assign_button->set_text(TTR("<empty>"));
assign_button->set_tooltip_text("");
} else {
- assign_button->set_icon(EditorNode::get_singleton()->get_object_icon(edited_resource.operator->(), "Object"));
+ assign_button->set_icon(EditorNode::get_singleton()->get_object_icon(edited_resource.operator->(), SNAME("Object")));
if (!edited_resource->get_name().is_empty()) {
assign_button->set_text(edited_resource->get_name());
} else if (edited_resource->get_path().is_resource_file()) {
assign_button->set_text(edited_resource->get_path().get_file());
} else {
- assign_button->set_text(edited_resource->get_class());
+ assign_button->set_text(class_name);
}
- assign_button->set_tooltip_text(resource_path + TTR("Type:") + " " + edited_resource->get_class());
+
+ if (edited_resource->get_path().is_resource_file()) {
+ resource_path = edited_resource->get_path() + "\n";
+ }
+ assign_button->set_tooltip_text(resource_path + TTR("Type:") + " " + class_name);
// Preview will override the above, so called at the end.
EditorResourcePreview::get_singleton()->queue_edited_resource_preview(edited_resource, this, "_update_resource_preview", edited_resource->get_instance_id());
@@ -134,16 +139,29 @@ void EditorResourcePicker::_file_selected(const String &p_path) {
if (!base_type.is_empty()) {
bool any_type_matches = false;
+ String res_type = loaded_resource->get_class();
+ Ref<Script> res_script = loaded_resource->get_script();
+ bool is_global_class = false;
+ if (res_script.is_valid()) {
+ String script_type = EditorNode::get_editor_data().script_class_get_name(res_script->get_path());
+ if (!script_type.is_empty()) {
+ is_global_class = true;
+ res_type = script_type;
+ }
+ }
+
for (int i = 0; i < base_type.get_slice_count(","); i++) {
String base = base_type.get_slice(",", i);
- if (loaded_resource->is_class(base)) {
- any_type_matches = true;
+
+ any_type_matches = is_global_class ? EditorNode::get_editor_data().script_class_is_parent(res_type, base) : loaded_resource->is_class(base);
+
+ if (!any_type_matches) {
break;
}
}
if (!any_type_matches) {
- EditorNode::get_singleton()->show_warning(vformat(TTR("The selected resource (%s) does not match any type expected for this property (%s)."), loaded_resource->get_class(), base_type));
+ EditorNode::get_singleton()->show_warning(vformat(TTR("The selected resource (%s) does not match any type expected for this property (%s)."), res_type, base_type));
return;
}
}
@@ -186,7 +204,7 @@ void EditorResourcePicker::_update_menu_items() {
// Add options for changing existing value of the resource.
if (edited_resource.is_valid()) {
// Determine if the edited resource is part of another scene (foreign) which was imported
- bool is_edited_resource_foreign_import = EditorNode::get_singleton()->is_resource_read_only(edited_resource);
+ bool is_edited_resource_foreign_import = EditorNode::get_singleton()->is_resource_read_only(edited_resource, true);
// If the resource is determined to be foreign and imported, change the menu entry's description to 'inspect' rather than 'edit'
// since will only be able to view its properties in read-only mode.
@@ -227,16 +245,19 @@ void EditorResourcePicker::_update_menu_items() {
// Add options to copy/paste resource.
Ref<Resource> cb = EditorSettings::get_singleton()->get_resource_clipboard();
bool paste_valid = false;
- if (is_editable()) {
- if (cb.is_valid()) {
- if (base_type.is_empty()) {
- paste_valid = true;
- } else {
- for (int i = 0; i < base_type.get_slice_count(","); i++) {
- if (ClassDB::is_parent_class(cb->get_class(), base_type.get_slice(",", i))) {
- paste_valid = true;
- break;
- }
+ if (is_editable() && cb.is_valid()) {
+ if (base_type.is_empty()) {
+ paste_valid = true;
+ } else {
+ String res_type = _get_resource_type(cb);
+
+ for (int i = 0; i < base_type.get_slice_count(","); i++) {
+ String base = base_type.get_slice(",", i);
+
+ paste_valid = ClassDB::is_parent_class(res_type, base) || EditorNode::get_editor_data().script_class_is_parent(res_type, base);
+
+ if (!paste_valid) {
+ break;
}
}
}
@@ -281,6 +302,9 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
for (int i = 0; i < base_type.get_slice_count(","); i++) {
String base = base_type.get_slice(",", i);
ResourceLoader::get_recognized_extensions_for_type(base, &extensions);
+ if (ScriptServer::is_global_class(base)) {
+ ResourceLoader::get_recognized_extensions_for_type(ScriptServer::get_global_class_native_base(base), &extensions);
+ }
}
HashSet<String> valid_extensions;
@@ -408,13 +432,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
Variant obj;
if (ScriptServer::is_global_class(intype)) {
- obj = ClassDB::instantiate(ScriptServer::get_global_class_native_base(intype));
- if (obj) {
- Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(intype));
- if (script.is_valid()) {
- ((Object *)obj)->set_script(script);
- }
- }
+ obj = EditorNode::get_editor_data().script_class_instance(intype);
} else {
obj = ClassDB::instantiate(intype);
}
@@ -512,23 +530,40 @@ void EditorResourcePicker::_button_draw() {
void EditorResourcePicker::_button_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
- // Only attempt to update and show the menu if we have
- // a valid resource or the Picker is editable, as
- // there will otherwise be nothing to display.
- if (edited_resource.is_valid() || is_editable()) {
- _update_menu_items();
-
- Vector2 pos = get_screen_position() + mb->get_position();
- edit_menu->reset_size();
- edit_menu->set_position(pos);
- edit_menu->popup();
- }
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
+ // Only attempt to update and show the menu if we have
+ // a valid resource or the Picker is editable, as
+ // there will otherwise be nothing to display.
+ if (edited_resource.is_valid() || is_editable()) {
+ _update_menu_items();
+
+ Vector2 pos = get_screen_position() + mb->get_position();
+ edit_menu->reset_size();
+ edit_menu->set_position(pos);
+ edit_menu->popup();
}
}
}
+String EditorResourcePicker::_get_resource_type(const Ref<Resource> &p_resource) const {
+ if (p_resource.is_null()) {
+ return String();
+ }
+ String res_type = p_resource->get_class();
+
+ Ref<Script> res_script = p_resource->get_script();
+ if (res_script.is_null()) {
+ return res_type;
+ }
+
+ // TODO: Replace with EditorFileSystem when PR #60606 is merged to use cached resource type.
+ String script_type = EditorNode::get_editor_data().script_class_get_name(res_script->get_path());
+ if (!script_type.is_empty()) {
+ res_type = script_type;
+ }
+ return res_type;
+}
+
void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<String> *p_vector) const {
Vector<String> allowed_types = base_type.split(",");
int size = allowed_types.size();
@@ -550,7 +585,9 @@ void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<Strin
List<StringName> allowed_subtypes;
List<StringName> inheriters;
- ClassDB::get_inheriters_from_class(base, &inheriters);
+ if (!ScriptServer::is_global_class(base)) {
+ ClassDB::get_inheriters_from_class(base, &inheriters);
+ }
for (const StringName &subtype_name : inheriters) {
p_vector->insert(subtype_name);
allowed_subtypes.push_back(subtype_name);
@@ -602,32 +639,29 @@ bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const {
}
} else if (drag_data.has("type") && String(drag_data["type"]) == "resource") {
res = drag_data["resource"];
+ } else if (drag_data.has("type") && String(drag_data["type"]) == "files") {
+ Vector<String> files = drag_data["files"];
+
+ // TODO: Extract the typename of the dropped filepath's resource in a more performant way, without fully loading it.
+ if (files.size() == 1) {
+ String file = files[0];
+ res = ResourceLoader::load(file);
+ }
}
HashSet<String> allowed_types;
_get_allowed_types(true, &allowed_types);
- if (res.is_valid() && _is_type_valid(res->get_class(), allowed_types)) {
- return true;
- }
+ if (res.is_valid()) {
+ String res_type = _get_resource_type(res);
- if (res.is_valid() && res->get_script()) {
- StringName custom_class = EditorNode::get_singleton()->get_object_custom_type_name(res->get_script());
- if (_is_type_valid(custom_class, allowed_types)) {
+ if (_is_type_valid(res_type, allowed_types)) {
return true;
}
- }
-
- if (drag_data.has("type") && String(drag_data["type"]) == "files") {
- Vector<String> files = drag_data["files"];
-
- if (files.size() == 1) {
- String file = files[0];
- String file_type = EditorFileSystem::get_singleton()->get_file_type(file);
- if (!file_type.is_empty() && _is_type_valid(file_type, allowed_types)) {
- return true;
- }
+ StringName custom_class = EditorNode::get_singleton()->get_object_custom_type_name(res.ptr());
+ if (_is_type_valid(custom_class, allowed_types)) {
+ return true;
}
}
@@ -685,8 +719,10 @@ void EditorResourcePicker::drop_data_fw(const Point2 &p_point, const Variant &p_
HashSet<String> allowed_types;
_get_allowed_types(false, &allowed_types);
+ String res_type = _get_resource_type(dropped_resource);
+
// If the accepted dropped resource is from the extended list, it requires conversion.
- if (!_is_type_valid(dropped_resource->get_class(), allowed_types)) {
+ if (!_is_type_valid(res_type, allowed_types)) {
for (const String &E : allowed_types) {
String at = E.strip_edges();
diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h
index 3d6127e656..d1a20f04b7 100644
--- a/editor/editor_resource_picker.h
+++ b/editor/editor_resource_picker.h
@@ -91,6 +91,7 @@ class EditorResourcePicker : public HBoxContainer {
void _button_draw();
void _button_input(const Ref<InputEvent> &p_event);
+ String _get_resource_type(const Ref<Resource> &p_resource) const;
void _get_allowed_types(bool p_with_convert, HashSet<String> *p_vector) const;
bool _is_drop_valid(const Dictionary &p_drag_data) const;
bool _is_type_valid(const String p_type_name, HashSet<String> p_allowed_types) const;
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index ec67cde112..2c09543d92 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -416,45 +416,50 @@ void EditorSettingsDialog::_update_shortcuts() {
List<String> slist;
EditorSettings::get_singleton()->get_shortcut_list(&slist);
+ slist.sort(); // Sort alphabetically.
const EditorPropertyNameProcessor::Style name_style = EditorPropertyNameProcessor::get_settings_style();
const EditorPropertyNameProcessor::Style tooltip_style = EditorPropertyNameProcessor::get_tooltip_style(name_style);
+ // Create all sections first.
for (const String &E : slist) {
Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(E);
- if (!sc->has_meta("original")) {
+ String section_name = E.get_slice("/", 0);
+
+ if (sections.has(section_name)) {
continue;
}
- // Shortcut Section
+ TreeItem *section = shortcuts->create_item(root);
- TreeItem *section;
- String section_name = E.get_slice("/", 0);
+ const String item_name = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, name_style);
+ const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, tooltip_style);
- if (sections.has(section_name)) {
- section = sections[section_name];
- } else {
- section = shortcuts->create_item(root);
-
- const String item_name = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, name_style);
- const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, tooltip_style);
-
- section->set_text(0, item_name);
- section->set_tooltip_text(0, tooltip);
- section->set_selectable(0, false);
- section->set_selectable(1, false);
- section->set_custom_bg_color(0, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor")));
- section->set_custom_bg_color(1, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor")));
-
- if (collapsed.has(item_name)) {
- section->set_collapsed(collapsed[item_name]);
- }
+ section->set_text(0, item_name);
+ section->set_tooltip_text(0, tooltip);
+ section->set_selectable(0, false);
+ section->set_selectable(1, false);
+ section->set_custom_bg_color(0, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor")));
+ section->set_custom_bg_color(1, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor")));
- sections[section_name] = section;
+ if (collapsed.has(item_name)) {
+ section->set_collapsed(collapsed[item_name]);
}
- // Shortcut Item
+ sections[section_name] = section;
+ }
+ // Add shortcuts to sections.
+ for (const String &E : slist) {
+ Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(E);
+ if (!sc->has_meta("original")) {
+ continue;
+ }
+
+ String section_name = E.get_slice("/", 0);
+ TreeItem *section = sections[section_name];
+
+ // Shortcut Item
if (!shortcut_filter.is_subsequence_ofn(sc->get_name())) {
continue;
}
@@ -552,6 +557,10 @@ void EditorSettingsDialog::_shortcut_cell_double_clicked() {
const ShortcutButton edit_btn_id = EditorSettingsDialog::SHORTCUT_EDIT;
const int edit_btn_col = 1;
TreeItem *ti = shortcuts->get_selected();
+ if (ti == nullptr) {
+ return;
+ }
+
String type = ti->get_meta("type");
int col = shortcuts->get_selected_column();
if (type == "shortcut" && col == 0) {
@@ -763,6 +772,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
shortcut_editor = memnew(InputEventConfigurationDialog);
shortcut_editor->connect("confirmed", callable_mp(this, &EditorSettingsDialog::_event_config_confirmed));
shortcut_editor->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_KEY);
+ shortcut_editor->set_close_on_escape(false);
add_child(shortcut_editor);
set_hide_on_ok(true);
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index edbd2dd62f..486a1f5a84 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -42,10 +42,15 @@
#include "modules/svg/image_loader_svg.h"
#endif
-HashMap<Color, Color> EditorColorMap::editor_color_map;
+HashMap<Color, Color> EditorColorMap::color_conversion_map;
+HashSet<StringName> EditorColorMap::color_conversion_exceptions;
-void EditorColorMap::add_color_pair(const String p_from_color, const String p_to_color) {
- editor_color_map[Color::html(p_from_color)] = Color::html(p_to_color);
+void EditorColorMap::add_conversion_color_pair(const String p_from_color, const String p_to_color) {
+ color_conversion_map[Color::html(p_from_color)] = Color::html(p_to_color);
+}
+
+void EditorColorMap::add_conversion_exception(const StringName p_icon_name) {
+ color_conversion_exceptions.insert(p_icon_name);
}
void EditorColorMap::create() {
@@ -53,105 +58,139 @@ void EditorColorMap::create() {
// This can be a basis for proper palette validation later.
// Convert: FROM TO
- add_color_pair("#478cbf", "#478cbf"); // Godot Blue
- add_color_pair("#414042", "#414042"); // Godot Gray
+ add_conversion_color_pair("#478cbf", "#478cbf"); // Godot Blue
+ add_conversion_color_pair("#414042", "#414042"); // Godot Gray
- add_color_pair("#ffffff", "#414141"); // Pure white
- add_color_pair("#000000", "#bfbfbf"); // Pure black
+ add_conversion_color_pair("#ffffff", "#414141"); // Pure white
+ add_conversion_color_pair("#000000", "#bfbfbf"); // Pure black
// Keep pure RGB colors as is, but list them for explicitly.
- add_color_pair("#ff0000", "#ff0000"); // Pure red
- add_color_pair("#00ff00", "#00ff00"); // Pure green
- add_color_pair("#0000ff", "#0000ff"); // Pure blue
+ add_conversion_color_pair("#ff0000", "#ff0000"); // Pure red
+ add_conversion_color_pair("#00ff00", "#00ff00"); // Pure green
+ add_conversion_color_pair("#0000ff", "#0000ff"); // Pure blue
// GUI Colors
- add_color_pair("#e0e0e0", "#5a5a5a"); // Common icon color
- add_color_pair("#fefefe", "#fefefe"); // Forced light color
- add_color_pair("#808080", "#808080"); // GUI disabled color
- add_color_pair("#b3b3b3", "#363636"); // GUI disabled light color
- add_color_pair("#699ce8", "#699ce8"); // GUI highlight color
- add_color_pair("#f9f9f9", "#606060"); // Scrollbar grabber highlight color
-
- add_color_pair("#c38ef1", "#a85de9"); // Animation
- add_color_pair("#fc7f7f", "#cd3838"); // Spatial
- add_color_pair("#8da5f3", "#3d64dd"); // 2D
- add_color_pair("#4b70ea", "#1a3eac"); // 2D Dark
- add_color_pair("#8eef97", "#2fa139"); // Control
-
- add_color_pair("#5fb2ff", "#0079f0"); // Selection (blue)
- add_color_pair("#003e7a", "#2b74bb"); // Selection (darker blue)
- add_color_pair("#f7f5cf", "#615f3a"); // Gizmo (yellow)
+ add_conversion_color_pair("#e0e0e0", "#5a5a5a"); // Common icon color
+ add_conversion_color_pair("#fefefe", "#fefefe"); // Forced light color
+ add_conversion_color_pair("#808080", "#808080"); // GUI disabled color
+ add_conversion_color_pair("#b3b3b3", "#363636"); // GUI disabled light color
+ add_conversion_color_pair("#699ce8", "#699ce8"); // GUI highlight color
+ add_conversion_color_pair("#f9f9f9", "#606060"); // Scrollbar grabber highlight color
+
+ add_conversion_color_pair("#c38ef1", "#a85de9"); // Animation
+ add_conversion_color_pair("#fc7f7f", "#cd3838"); // Spatial
+ add_conversion_color_pair("#8da5f3", "#3d64dd"); // 2D
+ add_conversion_color_pair("#4b70ea", "#1a3eac"); // 2D Dark
+ add_conversion_color_pair("#8eef97", "#2fa139"); // Control
+
+ add_conversion_color_pair("#5fb2ff", "#0079f0"); // Selection (blue)
+ add_conversion_color_pair("#003e7a", "#2b74bb"); // Selection (darker blue)
+ add_conversion_color_pair("#f7f5cf", "#615f3a"); // Gizmo (yellow)
// Rainbow
- add_color_pair("#ff4545", "#ff2929"); // Red
- add_color_pair("#ffe345", "#ffe337"); // Yellow
- add_color_pair("#80ff45", "#74ff34"); // Green
- add_color_pair("#45ffa2", "#2cff98"); // Aqua
- add_color_pair("#45d7ff", "#22ccff"); // Blue
- add_color_pair("#8045ff", "#702aff"); // Purple
- add_color_pair("#ff4596", "#ff2781"); // Pink
+ add_conversion_color_pair("#ff4545", "#ff2929"); // Red
+ add_conversion_color_pair("#ffe345", "#ffe337"); // Yellow
+ add_conversion_color_pair("#80ff45", "#74ff34"); // Green
+ add_conversion_color_pair("#45ffa2", "#2cff98"); // Aqua
+ add_conversion_color_pair("#45d7ff", "#22ccff"); // Blue
+ add_conversion_color_pair("#8045ff", "#702aff"); // Purple
+ add_conversion_color_pair("#ff4596", "#ff2781"); // Pink
// Audio gradients
- add_color_pair("#e1da5b", "#d6cf4b"); // Yellow
+ add_conversion_color_pair("#e1da5b", "#d6cf4b"); // Yellow
- add_color_pair("#62aeff", "#1678e0"); // Frozen gradient top
- add_color_pair("#75d1e6", "#41acc5"); // Frozen gradient middle
- add_color_pair("#84ffee", "#49ccba"); // Frozen gradient bottom
+ add_conversion_color_pair("#62aeff", "#1678e0"); // Frozen gradient top
+ add_conversion_color_pair("#75d1e6", "#41acc5"); // Frozen gradient middle
+ add_conversion_color_pair("#84ffee", "#49ccba"); // Frozen gradient bottom
- add_color_pair("#f70000", "#c91616"); // Color track red
- add_color_pair("#eec315", "#d58c0b"); // Color track orange
- add_color_pair("#dbee15", "#b7d10a"); // Color track yellow
- add_color_pair("#288027", "#218309"); // Color track green
+ add_conversion_color_pair("#f70000", "#c91616"); // Color track red
+ add_conversion_color_pair("#eec315", "#d58c0b"); // Color track orange
+ add_conversion_color_pair("#dbee15", "#b7d10a"); // Color track yellow
+ add_conversion_color_pair("#288027", "#218309"); // Color track green
// Resource groups
- add_color_pair("#ffca5f", "#fea900"); // Mesh resource (orange)
- add_color_pair("#2998ff", "#68b6ff"); // Shape resource (blue)
- add_color_pair("#a2d2ff", "#4998e3"); // Shape resource (light blue)
+ add_conversion_color_pair("#ffca5f", "#fea900"); // Mesh resource (orange)
+ add_conversion_color_pair("#2998ff", "#68b6ff"); // Shape resource (blue)
+ add_conversion_color_pair("#a2d2ff", "#4998e3"); // Shape resource (light blue)
// Animation editor tracks
// The property track icon color is set by the common icon color.
- add_color_pair("#ea7940", "#bd5e2c"); // 3D Position track
- add_color_pair("#ff2b88", "#bd165f"); // 3D Rotation track
- add_color_pair("#eac840", "#bd9d1f"); // 3D Scale track
- add_color_pair("#3cf34e", "#16a827"); // Call Method track
- add_color_pair("#2877f6", "#236be6"); // Bezier Curve track
- add_color_pair("#eae440", "#9f9722"); // Audio Playback track
- add_color_pair("#a448f0", "#9853ce"); // Animation Playback track
- add_color_pair("#5ad5c4", "#0a9c88"); // Blend Shape track
+ add_conversion_color_pair("#ea7940", "#bd5e2c"); // 3D Position track
+ add_conversion_color_pair("#ff2b88", "#bd165f"); // 3D Rotation track
+ add_conversion_color_pair("#eac840", "#bd9d1f"); // 3D Scale track
+ add_conversion_color_pair("#3cf34e", "#16a827"); // Call Method track
+ add_conversion_color_pair("#2877f6", "#236be6"); // Bezier Curve track
+ add_conversion_color_pair("#eae440", "#9f9722"); // Audio Playback track
+ add_conversion_color_pair("#a448f0", "#9853ce"); // Animation Playback track
+ add_conversion_color_pair("#5ad5c4", "#0a9c88"); // Blend Shape track
// Control layouts
- add_color_pair("#d6d6d6", "#474747"); // Highlighted part
- add_color_pair("#474747", "#d6d6d6"); // Background part
- add_color_pair("#919191", "#6e6e6e"); // Border part
+ add_conversion_color_pair("#d6d6d6", "#474747"); // Highlighted part
+ add_conversion_color_pair("#474747", "#d6d6d6"); // Background part
+ add_conversion_color_pair("#919191", "#6e6e6e"); // Border part
// TileSet editor icons
- add_color_pair("#fce00e", "#aa8d24"); // New Single Tile
- add_color_pair("#0e71fc", "#0350bd"); // New Autotile
- add_color_pair("#c6ced4", "#828f9b"); // New Atlas
+ add_conversion_color_pair("#fce00e", "#aa8d24"); // New Single Tile
+ add_conversion_color_pair("#0e71fc", "#0350bd"); // New Autotile
+ add_conversion_color_pair("#c6ced4", "#828f9b"); // New Atlas
// Visual script
- add_color_pair("#41ecad", "#25e3a0"); // VisualScript variant
- add_color_pair("#6f91f0", "#6d8eeb"); // VisualScript bool
- add_color_pair("#5abbef", "#4fb2e9"); // VisualScript int
- add_color_pair("#35d4f4", "#27ccf0"); // VisualScript float
- add_color_pair("#4593ec", "#4690e7"); // VisualScript String
- add_color_pair("#ac73f1", "#ad76ee"); // VisualScript Vector2
- add_color_pair("#f1738f", "#ee758e"); // VisualScript Rect2
- add_color_pair("#de66f0", "#dc6aed"); // VisualScript Vector3
- add_color_pair("#b9ec41", "#96ce1a"); // VisualScript Transform2D
- add_color_pair("#f74949", "#f77070"); // VisualScript Plane
- add_color_pair("#ec418e", "#ec69a3"); // VisualScript Quat
- add_color_pair("#ee5677", "#ee7991"); // VisualScript AABB
- add_color_pair("#e1ec41", "#b2bb19"); // VisualScript Basis
- add_color_pair("#f68f45", "#f49047"); // VisualScript Transform
- add_color_pair("#417aec", "#6993ec"); // VisualScript NodePath
- add_color_pair("#41ec80", "#2ce573"); // VisualScript RID
- add_color_pair("#55f3e3", "#12d5c3"); // VisualScript Object
- add_color_pair("#54ed9e", "#57e99f"); // VisualScript Dictionary
+ add_conversion_color_pair("#41ecad", "#25e3a0"); // VisualScript variant
+ add_conversion_color_pair("#6f91f0", "#6d8eeb"); // VisualScript bool
+ add_conversion_color_pair("#5abbef", "#4fb2e9"); // VisualScript int
+ add_conversion_color_pair("#35d4f4", "#27ccf0"); // VisualScript float
+ add_conversion_color_pair("#4593ec", "#4690e7"); // VisualScript String
+ add_conversion_color_pair("#ac73f1", "#ad76ee"); // VisualScript Vector2
+ add_conversion_color_pair("#f1738f", "#ee758e"); // VisualScript Rect2
+ add_conversion_color_pair("#de66f0", "#dc6aed"); // VisualScript Vector3
+ add_conversion_color_pair("#b9ec41", "#96ce1a"); // VisualScript Transform2D
+ add_conversion_color_pair("#f74949", "#f77070"); // VisualScript Plane
+ add_conversion_color_pair("#ec418e", "#ec69a3"); // VisualScript Quat
+ add_conversion_color_pair("#ee5677", "#ee7991"); // VisualScript AABB
+ add_conversion_color_pair("#e1ec41", "#b2bb19"); // VisualScript Basis
+ add_conversion_color_pair("#f68f45", "#f49047"); // VisualScript Transform
+ add_conversion_color_pair("#417aec", "#6993ec"); // VisualScript NodePath
+ add_conversion_color_pair("#41ec80", "#2ce573"); // VisualScript RID
+ add_conversion_color_pair("#55f3e3", "#12d5c3"); // VisualScript Object
+ add_conversion_color_pair("#54ed9e", "#57e99f"); // VisualScript Dictionary
// Visual shaders
- add_color_pair("#77ce57", "#67c046"); // Vector funcs
- add_color_pair("#ea686c", "#d95256"); // Vector transforms
- add_color_pair("#eac968", "#d9b64f"); // Textures and cubemaps
- add_color_pair("#cf68ea", "#c050dd"); // Functions and expressions
+ add_conversion_color_pair("#77ce57", "#67c046"); // Vector funcs
+ add_conversion_color_pair("#ea686c", "#d95256"); // Vector transforms
+ add_conversion_color_pair("#eac968", "#d9b64f"); // Textures and cubemaps
+ add_conversion_color_pair("#cf68ea", "#c050dd"); // Functions and expressions
+
+ // These icons should not be converted.
+ add_conversion_exception("EditorPivot");
+ add_conversion_exception("EditorHandle");
+ add_conversion_exception("Editor3DHandle");
+ add_conversion_exception("EditorBoneHandle");
+ add_conversion_exception("Godot");
+ add_conversion_exception("Sky");
+ add_conversion_exception("EditorControlAnchor");
+ add_conversion_exception("DefaultProjectIcon");
+ add_conversion_exception("GuiChecked");
+ add_conversion_exception("GuiRadioChecked");
+ add_conversion_exception("GuiIndeterminate");
+ add_conversion_exception("GuiCloseCustomizable");
+ add_conversion_exception("GuiGraphNodePort");
+ add_conversion_exception("GuiResizer");
+ add_conversion_exception("ZoomMore");
+ add_conversion_exception("ZoomLess");
+ add_conversion_exception("ZoomReset");
+ add_conversion_exception("LockViewport");
+ add_conversion_exception("GroupViewport");
+ add_conversion_exception("StatusError");
+ add_conversion_exception("StatusSuccess");
+ add_conversion_exception("StatusWarning");
+ add_conversion_exception("OverbrightIndicator");
+ add_conversion_exception("GuiMiniCheckerboard");
+
+ /// Code Editor.
+ add_conversion_exception("GuiTab");
+ add_conversion_exception("GuiSpace");
+ add_conversion_exception("CodeFoldedRightArrow");
+ add_conversion_exception("CodeFoldDownArrow");
+ add_conversion_exception("TextEditorPlay");
+ add_conversion_exception("Breakpoint");
}
static Ref<StyleBoxTexture> make_stylebox(Ref<Texture2D> p_texture, float p_left, float p_top, float p_right, float p_bottom, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, bool p_draw_center = true) {
@@ -206,67 +245,49 @@ static Ref<ImageTexture> editor_generate_icon(int p_index, float p_scale, float
img->adjust_bcs(1.0, 1.0, p_saturation);
}
- // In this case filter really helps.
return ImageTexture::create_from_image(img);
}
#endif
-void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = true, int p_thumb_size = 32, bool p_only_thumbs = false, float p_icon_saturation = 1.0) {
+void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme, float p_icon_saturation, int p_thumb_size, bool p_only_thumbs = false) {
#ifdef MODULE_SVG_ENABLED
- HashMap<Color, Color> icon_color_map;
-
- // The names of the icons to never convert, even if one of their colors
- // are contained in the dictionary above.
- HashSet<StringName> exceptions;
-
+ // Before we register the icons, we adjust their colors and saturation.
+ // Most icons follow the standard rules for color conversion to follow the editor
+ // theme's polarity (dark/light). We also adjust the saturation for most icons,
+ // following the editor setting.
+ // Some icons are excluded from this conversion, and instead use the configured
+ // accent color to replace their innate accent color to match the editor theme.
+ // And then some icons are completely excluded from the conversion.
+
+ // Standard color conversion map.
+ HashMap<Color, Color> color_conversion_map;
+ // Icons by default are set up for the dark theme, so if the theme is light,
+ // we apply the dark-to-light color conversion map.
if (!p_dark_theme) {
- for (KeyValue<Color, Color> &E : EditorColorMap::get()) {
- icon_color_map[E.key] = E.value;
+ for (KeyValue<Color, Color> &E : EditorColorMap::get_color_conversion_map()) {
+ color_conversion_map[E.key] = E.value;
}
-
- exceptions.insert("EditorPivot");
- exceptions.insert("EditorHandle");
- exceptions.insert("Editor3DHandle");
- exceptions.insert("EditorBoneHandle");
- exceptions.insert("Godot");
- exceptions.insert("Sky");
- exceptions.insert("EditorControlAnchor");
- exceptions.insert("DefaultProjectIcon");
- exceptions.insert("GuiChecked");
- exceptions.insert("GuiRadioChecked");
- exceptions.insert("GuiIndeterminate");
- exceptions.insert("GuiCloseCustomizable");
- exceptions.insert("GuiGraphNodePort");
- exceptions.insert("GuiResizer");
- exceptions.insert("ZoomMore");
- exceptions.insert("ZoomLess");
- exceptions.insert("ZoomReset");
- exceptions.insert("LockViewport");
- exceptions.insert("GroupViewport");
- exceptions.insert("StatusError");
- exceptions.insert("StatusSuccess");
- exceptions.insert("StatusWarning");
- exceptions.insert("OverbrightIndicator");
- exceptions.insert("GuiMiniCheckerboard");
-
- // Prevents Code Editor icons from changing
- exceptions.insert("GuiTab");
- exceptions.insert("GuiSpace");
- exceptions.insert("CodeFoldedRightArrow");
- exceptions.insert("CodeFoldDownArrow");
- exceptions.insert("TextEditorPlay");
- exceptions.insert("Breakpoint");
}
-
- // These ones should be converted even if we are using a dark theme.
+ // These colors should be converted even if we are using a dark theme.
const Color error_color = p_theme->get_color(SNAME("error_color"), SNAME("Editor"));
const Color success_color = p_theme->get_color(SNAME("success_color"), SNAME("Editor"));
const Color warning_color = p_theme->get_color(SNAME("warning_color"), SNAME("Editor"));
- icon_color_map[Color::html("#ff5f5f")] = error_color;
- icon_color_map[Color::html("#5fff97")] = success_color;
- icon_color_map[Color::html("#ffdd65")] = warning_color;
-
- // Use the accent color for some icons (checkbox, radio, toggle, etc.).
+ color_conversion_map[Color::html("#ff5f5f")] = error_color;
+ color_conversion_map[Color::html("#5fff97")] = success_color;
+ color_conversion_map[Color::html("#ffdd65")] = warning_color;
+
+ // The names of the icons to exclude from the standard color conversion.
+ HashSet<StringName> conversion_exceptions = EditorColorMap::get_color_conversion_exceptions();
+
+ // The names of the icons to exclude when adjusting for saturation.
+ HashSet<StringName> saturation_exceptions;
+ saturation_exceptions.insert("DefaultProjectIcon");
+ saturation_exceptions.insert("Godot");
+ saturation_exceptions.insert("Logo");
+
+ // Accent color conversion map.
+ // It is used on soem icons (checkbox, radio, toggle, etc.), regardless of the dark
+ // or light mode.
HashMap<Color, Color> accent_color_map;
HashSet<StringName> accent_color_icons;
@@ -292,16 +313,14 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
icon = editor_generate_icon(i, EDSCALE, 1.0, accent_color_map);
} else {
float saturation = p_icon_saturation;
-
- if (strcmp(editor_icons_names[i], "DefaultProjectIcon") == 0 || strcmp(editor_icons_names[i], "Godot") == 0 || strcmp(editor_icons_names[i], "Logo") == 0) {
+ if (saturation_exceptions.has(editor_icons_names[i])) {
saturation = 1.0;
}
- const int is_exception = exceptions.has(editor_icons_names[i]);
- if (is_exception) {
+ if (conversion_exceptions.has(editor_icons_names[i])) {
icon = editor_generate_icon(i, EDSCALE, saturation);
} else {
- icon = editor_generate_icon(i, EDSCALE, saturation, icon_color_map);
+ icon = editor_generate_icon(i, EDSCALE, saturation, color_conversion_map);
}
}
@@ -310,19 +329,26 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
}
// Generate thumbnail icons with the given thumbnail size.
- // We don't need filtering when generating at one of the default resolutions.
- const bool force_filter = p_thumb_size != 64 && p_thumb_size != 32;
+ // See editor\icons\editor_icons_builders.py for the code that determines which icons are thumbnails.
if (p_thumb_size >= 64) {
const float scale = (float)p_thumb_size / 64.0 * EDSCALE;
for (int i = 0; i < editor_bg_thumbs_count; i++) {
const int index = editor_bg_thumbs_indices[i];
- const int is_exception = exceptions.has(editor_icons_names[index]);
-
Ref<ImageTexture> icon;
- if (!p_dark_theme && !is_exception) {
- icon = editor_generate_icon(index, scale, force_filter, icon_color_map);
+
+ if (accent_color_icons.has(editor_icons_names[index])) {
+ icon = editor_generate_icon(index, scale, 1.0, accent_color_map);
} else {
- icon = editor_generate_icon(index, scale, force_filter);
+ float saturation = p_icon_saturation;
+ if (saturation_exceptions.has(editor_icons_names[index])) {
+ saturation = 1.0;
+ }
+
+ if (conversion_exceptions.has(editor_icons_names[index])) {
+ icon = editor_generate_icon(index, scale, saturation);
+ } else {
+ icon = editor_generate_icon(index, scale, saturation, color_conversion_map);
+ }
}
p_theme->set_icon(editor_icons_names[index], SNAME("EditorIcons"), icon);
@@ -331,13 +357,21 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
const float scale = (float)p_thumb_size / 32.0 * EDSCALE;
for (int i = 0; i < editor_md_thumbs_count; i++) {
const int index = editor_md_thumbs_indices[i];
- const bool is_exception = exceptions.has(editor_icons_names[index]);
-
Ref<ImageTexture> icon;
- if (!p_dark_theme && !is_exception) {
- icon = editor_generate_icon(index, scale, force_filter, icon_color_map);
+
+ if (accent_color_icons.has(editor_icons_names[index])) {
+ icon = editor_generate_icon(index, scale, 1.0, accent_color_map);
} else {
- icon = editor_generate_icon(index, scale, force_filter);
+ float saturation = p_icon_saturation;
+ if (saturation_exceptions.has(editor_icons_names[index])) {
+ saturation = 1.0;
+ }
+
+ if (conversion_exceptions.has(editor_icons_names[index])) {
+ icon = editor_generate_icon(index, scale, saturation);
+ } else {
+ icon = editor_generate_icon(index, scale, saturation, color_conversion_map);
+ }
}
p_theme->set_icon(editor_icons_names[index], SNAME("EditorIcons"), icon);
@@ -432,7 +466,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
if (dark_theme) {
ImageLoaderSVG::set_forced_color_map(HashMap<Color, Color>());
} else {
- ImageLoaderSVG::set_forced_color_map(EditorColorMap::get());
+ ImageLoaderSVG::set_forced_color_map(EditorColorMap::get_color_conversion_map());
}
#endif
@@ -475,9 +509,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color highlight_color = Color(accent_color.r, accent_color.g, accent_color.b, 0.275);
const Color disabled_highlight_color = highlight_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.5);
- float prev_icon_saturation = theme->has_color(SNAME("icon_saturation"), SNAME("Editor")) ? theme->get_color(SNAME("icon_saturation"), SNAME("Editor")).r : 1.0;
-
- theme->set_color("icon_saturation", "Editor", Color(icon_saturation, icon_saturation, icon_saturation)); // can't save single float in theme, so using color
+ // Can't save single float in theme, so using Color.
+ theme->set_color("icon_saturation", "Editor", Color(icon_saturation, icon_saturation, icon_saturation));
theme->set_color("accent_color", "Editor", accent_color);
theme->set_color("highlight_color", "Editor", highlight_color);
theme->set_color("disabled_highlight_color", "Editor", disabled_highlight_color);
@@ -518,7 +551,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Color readonly_warning_color = error_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.25);
if (!dark_theme) {
- // Darken some colors to be readable on a light background
+ // Darken some colors to be readable on a light background.
success_color = success_color.lerp(mono_color, 0.35);
warning_color = warning_color.lerp(mono_color, 0.35);
error_color = error_color.lerp(mono_color, 0.25);
@@ -541,22 +574,43 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_constant("dark_theme", "Editor", dark_theme);
theme->set_constant("color_picker_button_height", "Editor", 28 * EDSCALE);
- // Register icons + font
+ // Register editor icons.
+ // If the settings are comparable to the old theme, then just copy them over.
+ // Otherwise, regenerate them. Also check if we need to regenerate "thumb" icons.
+ bool keep_old_icons = false;
+ bool regenerate_thumb_icons = true;
+ if (p_theme != nullptr) {
+ // We check editor scale, theme dark/light mode, icon saturation, and accent color.
+
+ // That doesn't really work as expected, since theme constants are integers, and scales are floats.
+ // So this check will never work when changing between 100-199% values.
+ const float prev_scale = (float)p_theme->get_constant(SNAME("scale"), SNAME("Editor"));
+ const bool prev_dark_theme = (bool)p_theme->get_constant(SNAME("dark_theme"), SNAME("Editor"));
+ const Color prev_accent_color = p_theme->get_color(SNAME("accent_color"), SNAME("Editor"));
+ const float prev_icon_saturation = p_theme->get_color(SNAME("icon_saturation"), SNAME("Editor")).r;
+
+ keep_old_icons = (Math::is_equal_approx(prev_scale, EDSCALE) &&
+ prev_dark_theme == dark_theme &&
+ prev_accent_color == accent_color &&
+ prev_icon_saturation == icon_saturation);
+
+ const double prev_thumb_size = (double)p_theme->get_constant(SNAME("thumb_size"), SNAME("Editor"));
+
+ regenerate_thumb_icons = !Math::is_equal_approx(prev_thumb_size, thumb_size);
+ }
- // The editor scale, icon color (dark_theme bool), icon saturation, and accent color has not changed, so we do not regenerate the icons.
- if (p_theme != nullptr && fabs(p_theme->get_constant(SNAME("scale"), SNAME("Editor")) - EDSCALE) < 0.00001 && (bool)p_theme->get_constant(SNAME("dark_theme"), SNAME("Editor")) == dark_theme && prev_icon_saturation == icon_saturation && p_theme->get_color(SNAME("accent_color"), SNAME("Editor")) == accent_color) {
- // Register already generated icons.
+ if (keep_old_icons) {
for (int i = 0; i < editor_icons_count; i++) {
theme->set_icon(editor_icons_names[i], SNAME("EditorIcons"), p_theme->get_icon(editor_icons_names[i], SNAME("EditorIcons")));
}
} else {
- editor_register_and_generate_icons(theme, dark_theme, thumb_size, false, icon_saturation);
+ editor_register_and_generate_icons(theme, dark_theme, icon_saturation, thumb_size, false);
}
- // Thumbnail size has changed, so we regenerate the medium sizes
- if (p_theme != nullptr && fabs((double)p_theme->get_constant(SNAME("thumb_size"), SNAME("Editor")) - thumb_size) > 0.00001) {
- editor_register_and_generate_icons(p_theme, dark_theme, thumb_size, true);
+ if (regenerate_thumb_icons) {
+ editor_register_and_generate_icons(theme, dark_theme, icon_saturation, thumb_size, true);
}
+ // Register editor fonts.
editor_register_fonts(theme);
// Ensure borders are visible when using an editor scale below 100%.
diff --git a/editor/editor_themes.h b/editor/editor_themes.h
index 37db8160fa..da5db95d0e 100644
--- a/editor/editor_themes.h
+++ b/editor/editor_themes.h
@@ -39,13 +39,18 @@
class EditorColorMap {
// Godot Color values are used to avoid the ambiguity of strings
// (where "#ffffff", "fff", and "white" are all equivalent).
- static HashMap<Color, Color> editor_color_map;
+ static HashMap<Color, Color> color_conversion_map;
+ // The names of the icons to never convert, even if one of their colors
+ // are contained in the color map from above.
+ static HashSet<StringName> color_conversion_exceptions;
public:
static void create();
- static void add_color_pair(const String p_from_color, const String p_to_color);
+ static void add_conversion_color_pair(const String p_from_color, const String p_to_color);
+ static void add_conversion_exception(const StringName p_icon_name);
- static HashMap<Color, Color> &get() { return editor_color_map; };
+ static HashMap<Color, Color> &get_color_conversion_map() { return color_conversion_map; };
+ static HashSet<StringName> &get_color_conversion_exceptions() { return color_conversion_exceptions; };
};
Ref<Theme> create_editor_theme(Ref<Theme> p_theme = nullptr);
diff --git a/editor/editor_undo_redo_manager.cpp b/editor/editor_undo_redo_manager.cpp
index 8c04a4d595..064448fd96 100644
--- a/editor/editor_undo_redo_manager.cpp
+++ b/editor/editor_undo_redo_manager.cpp
@@ -131,12 +131,12 @@ void EditorUndoRedoManager::create_action(const String &p_name, UndoRedo::MergeM
void EditorUndoRedoManager::add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo;
- undo_redo->add_do_methodp(p_object, p_method, p_args, p_argcount);
+ undo_redo->add_do_method(Callable(p_object, p_method).bindp(p_args, p_argcount));
}
void EditorUndoRedoManager::add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo;
- undo_redo->add_undo_methodp(p_object, p_method, p_args, p_argcount);
+ undo_redo->add_undo_method(Callable(p_object, p_method).bindp(p_args, p_argcount));
}
void EditorUndoRedoManager::_add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index bcc85570ed..13ab5cebf6 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -710,7 +710,7 @@ String EditorExportPlatform::_export_customize(const String &p_path, LocalVector
if (type == "PackedScene") { // Its a scene.
Ref<PackedScene> ps = ResourceLoader::load(p_path, "PackedScene", ResourceFormatLoader::CACHE_MODE_IGNORE);
ERR_FAIL_COND_V(ps.is_null(), p_path);
- Node *node = ps->instantiate();
+ Node *node = ps->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); // Make sure the child scene root gets the correct inheritance chain.
ERR_FAIL_COND_V(node == nullptr, p_path);
if (customize_scenes_plugins.size()) {
for (uint32_t i = 0; i < customize_scenes_plugins.size(); i++) {
diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp
index 8c67885971..43aac5e981 100644
--- a/editor/export/project_export.cpp
+++ b/editor/export/project_export.cpp
@@ -865,10 +865,10 @@ void ProjectExportDialog::_validate_export_path(const String &p_path) {
if (invalid_path) {
export_project->get_ok_button()->set_disabled(true);
- export_project->get_line_edit()->disconnect("text_submitted", Callable(export_project, "_file_submitted"));
+ export_project->get_line_edit()->disconnect("text_submitted", callable_mp(export_project, &EditorFileDialog::_file_submitted));
} else {
export_project->get_ok_button()->set_disabled(false);
- export_project->get_line_edit()->connect("text_submitted", Callable(export_project, "_file_submitted"));
+ export_project->get_line_edit()->connect("text_submitted", callable_mp(export_project, &EditorFileDialog::_file_submitted));
}
}
@@ -901,9 +901,9 @@ void ProjectExportDialog::_export_project() {
// with _validate_export_path.
// FIXME: This is a hack, we should instead change EditorFileDialog to allow
// disabling validation by the "text_submitted" signal.
- if (!export_project->get_line_edit()->is_connected("text_submitted", Callable(export_project, "_file_submitted"))) {
+ if (!export_project->get_line_edit()->is_connected("text_submitted", callable_mp(export_project, &EditorFileDialog::_file_submitted))) {
export_project->get_ok_button()->set_disabled(false);
- export_project->get_line_edit()->connect("text_submitted", Callable(export_project, "_file_submitted"));
+ export_project->get_line_edit()->connect("text_submitted", callable_mp(export_project, &EditorFileDialog::_file_submitted));
}
export_project->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 19b4932d3d..424eab2f02 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1751,22 +1751,7 @@ void FileSystemDock::_tree_rmb_option(int p_option) {
case FOLDER_COLLAPSE_ALL: {
// Expand or collapse the folder
if (selected_strings.size() == 1) {
- bool is_collapsed = (p_option == FOLDER_COLLAPSE_ALL);
-
- Vector<TreeItem *> needs_check;
- needs_check.push_back(tree->get_selected());
-
- while (needs_check.size()) {
- needs_check[0]->set_collapsed(is_collapsed);
-
- TreeItem *child = needs_check[0]->get_first_child();
- while (child) {
- needs_check.push_back(child);
- child = child->get_next();
- }
-
- needs_check.remove_at(0);
- }
+ tree->get_selected()->set_collapsed_recursive(p_option == FOLDER_COLLAPSE_ALL);
}
} break;
default: {
diff --git a/editor/icons/MemberAnnotation.svg b/editor/icons/MemberAnnotation.svg
index c73ebf7b9b..39bef6d9ee 100644
--- a/editor/icons/MemberAnnotation.svg
+++ b/editor/icons/MemberAnnotation.svg
@@ -1 +1 @@
-<svg width="16" height="16" version="1.0" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><script id="custom-useragent-string-page-script"/><path d="m13.821 12.756c-5.0033 3.9148-12.551 2.248-12.49-4.538 0.67424-11.471 17.312-7.4502 12.446 2.1173-1.0549 1.1955-2.0737 1.4617-3.1983 0.4329-0.21023-0.19282-0.44783-1.1594-0.3819-1.5089 0.35827-1.8946 1.0885-4.0778-0.72151-4.7234-2.4171-0.86457-4.5592 1.6495-4.9697 4.0193-0.47396 2.7343 2.284 3.3749 4.1487 1.9879 0.4553-0.36324 1.6433-1.3796 1.6806-1.9742" fill="none" stroke="#e0e0e0" stroke-linejoin="round" stroke-width="1.4928"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13.821 12.756c-5.0033 3.9148-12.551 2.248-12.49-4.538.67424-11.471 17.312-7.4502 12.446 2.1173-1.0549 1.1955-2.0737 1.4617-3.1983.4329-.21023-.19282-.44783-1.1594-.3819-1.5089.35827-1.8946 1.0885-4.0778-.72151-4.7234-2.4171-.86457-4.5592 1.6495-4.9697 4.0193-.47396 2.7343 2.284 3.3749 4.1487 1.9879.4553-.36324 1.6433-1.3796 1.6806-1.9742" fill="none" stroke="#e0e0e0" stroke-linejoin="round" stroke-width="1.4928"/></svg>
diff --git a/editor/icons/MethodOverride.svg b/editor/icons/MethodOverride.svg
new file mode 100644
index 0000000000..004b9bf283
--- /dev/null
+++ b/editor/icons/MethodOverride.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 4.2333332 4.2333332" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m.49005985 3.3580432.83285685-.0000001v-.7093212c.0027125-.6681099.2054076-1.1321001 1.0021593-1.1328214h.3207573v-.79375l1.3229167 1.0648649-1.3229167 1.0518017v-.79375h-.3364788c-.2888876 0-.4514151.2436282-.4573001.5980603 0 .2833012.0000193.4455045.0000289.7134508h.79375v.4907171l-2.15577345.00147z" fill="#5fb2ff"/></svg>
diff --git a/editor/icons/MethodOverrideAndSlot.svg b/editor/icons/MethodOverrideAndSlot.svg
new file mode 100644
index 0000000000..d3bd9f0253
--- /dev/null
+++ b/editor/icons/MethodOverrideAndSlot.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 4.2333332 4.2333332" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m.15761184 3.636193h.37155483l.004252-.7093212c.0027092-.6681099.12999225-1.1321001.92674393-1.1328214h.1273374l.0042585-.7357171 1.3186582 1.006832-1.3229167 1.0700676v-.8531081h-.1260545c-.2888876 0-.3972562.2847204-.4031411.6391525 0 .2833012.0000193.4455045.0000289.7134508h1.2412654v.4907171h-2.14198686z" fill="#5fb2ff"/><path d="m2.38125.79375h1.5875v2.6458333h-1.5875v-.5291666h1.0583333v-1.5875h-1.0583333z" fill="#5fff97"/></svg>
diff --git a/editor/icons/VisualScriptComment.svg b/editor/icons/VisualScriptComment.svg
deleted file mode 100644
index 3887853b58..0000000000
--- a/editor/icons/VisualScriptComment.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="14" viewBox="0 0 14 14" width="14" xmlns="http://www.w3.org/2000/svg"><path d="m3 1v2h-2v2h2v4h-2v2h2v2h2v-2h4v2h2v-2h2v-2h-2v-4h2v-2h-2v-2h-2v2h-4v-2zm2 4h4v4h-4z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/VisualScriptExpression.svg b/editor/icons/VisualScriptExpression.svg
deleted file mode 100644
index d6a3c2d9a8..0000000000
--- a/editor/icons/VisualScriptExpression.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m4.859536 3.0412379c-2.0539867 0-3.7190721 1.6650852-3.7190721 3.719072v6.1984521h2.4793814v-2.479381h2.4793814v-2.4793803h-2.4793814v-1.2396908c0-.6846622.5550285-1.2396907 1.2396907-1.2396907h1.2396907v-2.4793813z"/><path d="m7.5889175 3.0000003 2.5000005 4.9999997-2.5000005 5h2.5000005l1.135249-2.727 1.36475 2.727h2.499999l-2.499999-5 2.499999-4.9999997h-2.499999l-1.13525 2.7269998-1.364749-2.7269998zm7.4999985 9.9999997v-6.25z"/></g></svg>
diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp
index d1f37179f3..1e0f45419f 100644
--- a/editor/import/dynamic_font_import_settings.cpp
+++ b/editor/import/dynamic_font_import_settings.cpp
@@ -302,6 +302,7 @@ static UniRange unicode_ranges[] = {
{ 0x10D00, 0x10D3F, U"Hanifi Rohingya" },
{ 0x10E60, 0x10E7F, U"Rumi Numeral Symbols" },
{ 0x10E80, 0x10EBF, U"Yezidi" },
+ { 0x10EC0, 0x10EFF, U"Arabic Extended-C" },
{ 0x10F00, 0x10F2F, U"Old Sogdian" },
{ 0x10F30, 0x10F6F, U"Sogdian" },
{ 0x10F70, 0x10FAF, U"Old Uyghur" },
@@ -333,11 +334,13 @@ static UniRange unicode_ranges[] = {
{ 0x11A50, 0x11AAF, U"Soyombo" },
{ 0x11AB0, 0x11ABF, U"Unified Canadian Aboriginal Syllabics Extended-A" },
{ 0x11AC0, 0x11AFF, U"Pau Cin Hau" },
+ { 0x11B00, 0x11B5F, U"Devanagari Extended-A" },
{ 0x11C00, 0x11C6F, U"Bhaiksuki" },
{ 0x11C70, 0x11CBF, U"Marchen" },
{ 0x11D00, 0x11D5F, U"Masaram Gondi" },
{ 0x11D60, 0x11DAF, U"Gunjala Gondi" },
{ 0x11EE0, 0x11EFF, U"Makasar" },
+ { 0x11F00, 0x11F5F, U"Kawi" },
{ 0x11FB0, 0x11FBF, U"Lisu Supplement" },
{ 0x11FC0, 0x11FFF, U"Tamil Supplement" },
{ 0x12000, 0x123FF, U"Cuneiform" },
@@ -370,6 +373,7 @@ static UniRange unicode_ranges[] = {
{ 0x1D000, 0x1D0FF, U"Byzantine Musical Symbols" },
{ 0x1D100, 0x1D1FF, U"Musical Symbols" },
{ 0x1D200, 0x1D24F, U"Ancient Greek Musical Notation" },
+ { 0x1D2C0, 0x1D2DF, U"Kaktovik Numerals" },
{ 0x1D2E0, 0x1D2FF, U"Mayan Numerals" },
{ 0x1D300, 0x1D35F, U"Tai Xuan Jing Symbols" },
{ 0x1D360, 0x1D37F, U"Counting Rod Numerals" },
@@ -377,9 +381,11 @@ static UniRange unicode_ranges[] = {
{ 0x1D800, 0x1DAAF, U"Sutton SignWriting" },
{ 0x1DF00, 0x1DFFF, U"Latin Extended-G" },
{ 0x1E000, 0x1E02F, U"Glagolitic Supplement" },
+ { 0x1E030, 0x1E08F, U"Cyrillic Extended-D" },
{ 0x1E100, 0x1E14F, U"Nyiakeng Puachue Hmong" },
{ 0x1E290, 0x1E2BF, U"Toto" },
{ 0x1E2C0, 0x1E2FF, U"Wancho" },
+ { 0x1E4D0, 0x1E4FF, U"Nag Mundari" },
{ 0x1E7E0, 0x1E7FF, U"Ethiopic Extended-B" },
{ 0x1E800, 0x1E8DF, U"Mende Kikakui" },
{ 0x1E900, 0x1E95F, U"Adlam" },
@@ -409,6 +415,7 @@ static UniRange unicode_ranges[] = {
{ 0x2CEB0, 0x2EBEF, U"CJK Unified Ideographs Extension F" },
{ 0x2F800, 0x2FA1F, U"CJK Compatibility Ideographs Supplement" },
{ 0x30000, 0x3134F, U"CJK Unified Ideographs Extension G" },
+ { 0x31350, 0x323AF, U"CJK Unified Ideographs Extension H" },
//{ 0xE0000, 0xE007F, U"Tags" },
//{ 0xE0100, 0xE01EF, U"Variation Selectors Supplement" },
{ 0xF0000, 0xFFFFF, U"Supplementary Private Use Area-A" },
@@ -1002,6 +1009,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) {
vars_list_root = vars_list->create_item();
+ import_settings_data->settings.clear();
import_settings_data->defaults.clear();
for (List<ResourceImporter::ImportOption>::Element *E = options_general.front(); E; E = E->next()) {
import_settings_data->defaults[E->get().option.name] = E->get().default_value;
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 41061c3fc3..b5798a5784 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -1891,6 +1891,39 @@ void ResourceImporterScene::_replace_owner(Node *p_node, Node *p_scene, Node *p_
}
}
+Array ResourceImporterScene::_get_skinned_pose_transforms(ImporterMeshInstance3D *p_src_mesh_node) {
+ Array skin_pose_transform_array;
+
+ const Ref<Skin> skin = p_src_mesh_node->get_skin();
+ if (skin.is_valid()) {
+ NodePath skeleton_path = p_src_mesh_node->get_skeleton_path();
+ const Node *node = p_src_mesh_node->get_node_or_null(skeleton_path);
+ const Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node);
+ if (skeleton) {
+ int bind_count = skin->get_bind_count();
+
+ for (int i = 0; i < bind_count; i++) {
+ Transform3D bind_pose = skin->get_bind_pose(i);
+ String bind_name = skin->get_bind_name(i);
+
+ int bone_idx = bind_name.is_empty() ? skin->get_bind_bone(i) : skeleton->find_bone(bind_name);
+ ERR_FAIL_COND_V(bone_idx >= skeleton->get_bone_count(), Array());
+
+ Transform3D bp_global_rest;
+ if (bone_idx >= 0) {
+ bp_global_rest = skeleton->get_bone_global_pose(bone_idx);
+ } else {
+ bp_global_rest = skeleton->get_bone_global_pose(i);
+ }
+
+ skin_pose_transform_array.push_back(bp_global_rest * bind_pose);
+ }
+ }
+ }
+
+ return skin_pose_transform_array;
+}
+
void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches) {
ImporterMeshInstance3D *src_mesh_node = Object::cast_to<ImporterMeshInstance3D>(p_node);
if (src_mesh_node) {
@@ -2007,7 +2040,8 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m
}
if (generate_lods) {
- src_mesh_node->get_mesh()->generate_lods(merge_angle, split_angle);
+ Array skin_pose_transform_array = _get_skinned_pose_transforms(src_mesh_node);
+ src_mesh_node->get_mesh()->generate_lods(merge_angle, split_angle, skin_pose_transform_array);
}
if (create_shadow_meshes) {
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index da37893cc5..386519bc59 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -34,11 +34,14 @@
#include "core/error/error_macros.h"
#include "core/io/resource_importer.h"
#include "core/variant/dictionary.h"
-#include "scene/3d/node_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/resources/animation.h"
+#include "scene/resources/box_shape_3d.h"
+#include "scene/resources/capsule_shape_3d.h"
+#include "scene/resources/cylinder_shape_3d.h"
#include "scene/resources/mesh.h"
#include "scene/resources/shape_3d.h"
-#include "scene/resources/skin.h"
+#include "scene/resources/sphere_shape_3d.h"
class Material;
class AnimationPlayer;
@@ -208,6 +211,7 @@ class ResourceImporterScene : public ResourceImporter {
SHAPE_TYPE_CAPSULE,
};
+ Array _get_skinned_pose_transforms(ImporterMeshInstance3D *p_src_mesh_node);
void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner);
void _generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches);
void _add_shapes(Node *p_node, const Vector<Ref<Shape3D>> &p_shapes);
@@ -309,11 +313,6 @@ public:
virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
};
-#include "scene/resources/box_shape_3d.h"
-#include "scene/resources/capsule_shape_3d.h"
-#include "scene/resources/cylinder_shape_3d.h"
-#include "scene/resources/sphere_shape_3d.h"
-
template <class M>
Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Mesh> &p_mesh, const M &p_options) {
ShapeType generate_shape_type = SHAPE_TYPE_DECOMPOSE_CONVEX;
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index f4b8646e18..ca7b2d0015 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -101,13 +101,13 @@ void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_propert
undo_redo->create_action(TTR("Parameter Changed:") + " " + String(p_property), UndoRedo::MERGE_ENDS);
undo_redo->add_do_property(tree, p_property, p_value);
undo_redo->add_undo_property(tree, p_property, tree->get(p_property));
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
updating = false;
}
-void AnimationNodeBlendTreeEditor::_update_graph() {
+void AnimationNodeBlendTreeEditor::update_graph() {
if (updating || blend_tree.is_null()) {
return;
}
@@ -364,8 +364,8 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
to_slot = -1;
}
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
}
@@ -416,8 +416,8 @@ void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Ve
undo_redo->create_action(TTR("Node Moved"));
undo_redo->add_do_method(blend_tree.ptr(), "set_node_position", p_which, p_to / EDSCALE);
undo_redo->add_undo_method(blend_tree.ptr(), "set_node_position", p_which, p_from / EDSCALE);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
updating = false;
}
@@ -437,8 +437,8 @@ void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int
undo_redo->create_action(TTR("Nodes Connected"));
undo_redo->add_do_method(blend_tree.ptr(), "connect_node", p_to, p_to_index, p_from);
undo_redo->add_undo_method(blend_tree.ptr(), "disconnect_node", p_to, p_to_index);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
}
@@ -453,8 +453,8 @@ void AnimationNodeBlendTreeEditor::_disconnection_request(const String &p_from,
undo_redo->create_action(TTR("Nodes Disconnected"));
undo_redo->add_do_method(blend_tree.ptr(), "disconnect_node", p_to, p_to_index);
undo_redo->add_undo_method(blend_tree.ptr(), "connect_node", p_to, p_to_index, p_from);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
updating = false;
}
@@ -468,8 +468,8 @@ void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options,
undo_redo->create_action(TTR("Set Animation"));
undo_redo->add_do_method(anim.ptr(), "set_animation", option);
undo_redo->add_undo_method(anim.ptr(), "set_animation", anim->get_animation());
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
}
@@ -491,8 +491,8 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
}
}
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
}
@@ -819,7 +819,7 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
_update_theme();
if (is_visible_in_tree()) {
- _update_graph();
+ update_graph();
}
} break;
@@ -900,12 +900,23 @@ void AnimationNodeBlendTreeEditor::_scroll_changed(const Vector2 &p_scroll) {
}
void AnimationNodeBlendTreeEditor::_bind_methods() {
- ClassDB::bind_method("_update_graph", &AnimationNodeBlendTreeEditor::_update_graph);
+ ClassDB::bind_method("update_graph", &AnimationNodeBlendTreeEditor::update_graph);
ClassDB::bind_method("_update_filters", &AnimationNodeBlendTreeEditor::_update_filters);
}
AnimationNodeBlendTreeEditor *AnimationNodeBlendTreeEditor::singleton = nullptr;
+// AnimationNode's "node_changed" signal means almost update_input.
+void AnimationNodeBlendTreeEditor::_node_changed(const StringName &p_node_name) {
+ // TODO:
+ // Here is executed during the commit of EditorNode::undo_redo, it is not possible to create an undo_redo action here.
+ // The disconnect when the number of enabled inputs decreases is done in AnimationNodeBlendTree and update_graph().
+ // This means that there is no place to register undo_redo actions.
+ // In order to implement undo_redo correctly, we may need to implement AnimationNodeEdit such as AnimationTrackKeyEdit
+ // and add it to _node_selected() with EditorNode::get_singleton()->push_item(AnimationNodeEdit).
+ update_graph();
+}
+
void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<AnimationNode> p_node) {
if (blend_tree.is_null()) {
return;
@@ -940,8 +951,8 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
undo_redo->add_undo_method(blend_tree.ptr(), "rename_node", name, prev_name);
undo_redo->add_do_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + prev_name, base_path + name);
undo_redo->add_undo_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + name, base_path + prev_name);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
updating = false;
gn->set_name(new_name);
@@ -979,7 +990,7 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
}
}
- _update_graph(); // Needed to update the signal connections with the new name.
+ update_graph(); // Needed to update the signal connections with the new name.
}
void AnimationNodeBlendTreeEditor::_node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node) {
@@ -996,6 +1007,7 @@ bool AnimationNodeBlendTreeEditor::can_edit(const Ref<AnimationNode> &p_node) {
void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) {
if (blend_tree.is_valid()) {
+ blend_tree->disconnect("node_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_changed));
blend_tree->disconnect("removed_from_graph", callable_mp(this, &AnimationNodeBlendTreeEditor::_removed_from_graph));
}
@@ -1008,9 +1020,10 @@ void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) {
} else {
read_only = EditorNode::get_singleton()->is_resource_read_only(blend_tree);
+ blend_tree->connect("node_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_changed));
blend_tree->connect("removed_from_graph", callable_mp(this, &AnimationNodeBlendTreeEditor::_removed_from_graph));
- _update_graph();
+ update_graph();
}
add_node->set_disabled(read_only);
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index 30a54930a2..46e0d18c69 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -71,8 +71,6 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
int to_slot = -1;
String from_node = "";
- void _update_graph();
-
struct AddOption {
String name;
String type;
@@ -95,6 +93,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, const StringName &p_which);
void _node_renamed(const String &p_text, Ref<AnimationNode> p_node);
void _node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node);
+ void _node_changed(const StringName &p_node_name);
bool updating;
@@ -150,6 +149,8 @@ public:
virtual bool can_edit(const Ref<AnimationNode> &p_node) override;
virtual void edit(const Ref<AnimationNode> &p_node) override;
+ void update_graph();
+
AnimationNodeBlendTreeEditor();
};
diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp
index ed231c446b..1de4fbaabc 100644
--- a/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_editor_plugin.cpp
@@ -50,10 +50,18 @@
#include "scene/scene_string_names.h"
void AnimationTreeEditor::edit(AnimationTree *p_tree) {
+ if (p_tree && !p_tree->is_connected("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed))) {
+ p_tree->connect("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed), CONNECT_DEFERRED);
+ }
+
if (tree == p_tree) {
return;
}
+ if (tree && tree->is_connected("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed))) {
+ tree->disconnect("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed));
+ }
+
tree = p_tree;
Vector<String> path;
@@ -73,6 +81,13 @@ void AnimationTreeEditor::_path_button_pressed(int p_path) {
}
}
+void AnimationTreeEditor::_animation_list_changed() {
+ AnimationNodeBlendTreeEditor *bte = AnimationNodeBlendTreeEditor::get_singleton();
+ if (bte) {
+ bte->update_graph();
+ }
+}
+
void AnimationTreeEditor::_update_path() {
while (path_hb->get_child_count() > 1) {
memdelete(path_hb->get_child(1));
diff --git a/editor/plugins/animation_tree_editor_plugin.h b/editor/plugins/animation_tree_editor_plugin.h
index a33d97f62f..9ef9fff8cd 100644
--- a/editor/plugins/animation_tree_editor_plugin.h
+++ b/editor/plugins/animation_tree_editor_plugin.h
@@ -65,6 +65,7 @@ class AnimationTreeEditor : public VBoxContainer {
ObjectID current_root;
void _path_button_pressed(int p_path);
+ void _animation_list_changed();
static Vector<String> get_animation_list();
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 070834b33b..8dc08e3a93 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -4715,12 +4715,10 @@ void CanvasItemEditor::_reset_drag() {
}
void CanvasItemEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_update_override_camera_button", "game_running"), &CanvasItemEditor::_update_override_camera_button);
ClassDB::bind_method("_get_editor_data", &CanvasItemEditor::_get_editor_data);
ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state);
ClassDB::bind_method(D_METHOD("update_viewport"), &CanvasItemEditor::update_viewport);
- ClassDB::bind_method(D_METHOD("_zoom_on_position"), &CanvasItemEditor::_zoom_on_position);
ClassDB::bind_method("_set_owner_for_node_and_children", &CanvasItemEditor::_set_owner_for_node_and_children);
@@ -4984,8 +4982,8 @@ CanvasItemEditor::CanvasItemEditor() {
SceneTreeDock::get_singleton()->connect("node_created", callable_mp(this, &CanvasItemEditor::_node_created));
SceneTreeDock::get_singleton()->connect("add_node_used", callable_mp(this, &CanvasItemEditor::_reset_create_position));
- EditorNode::get_singleton()->call_deferred(SNAME("connect"), "play_pressed", Callable(this, "_update_override_camera_button").bind(true));
- EditorNode::get_singleton()->call_deferred(SNAME("connect"), "stop_pressed", Callable(this, "_update_override_camera_button").bind(false));
+ EditorNode::get_singleton()->call_deferred(SNAME("connect"), callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(true));
+ EditorNode::get_singleton()->call_deferred(SNAME("connect"), "stop_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(false));
// A fluid container for all toolbars.
HFlowContainer *main_flow = memnew(HFlowContainer);
@@ -5883,9 +5881,6 @@ void CanvasItemEditorViewport::_notification(int p_what) {
}
}
-void CanvasItemEditorViewport::_bind_methods() {
-}
-
CanvasItemEditorViewport::CanvasItemEditorViewport(CanvasItemEditor *p_canvas_item_editor) {
default_texture_node_type = "Sprite2D";
// Node2D
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 0a840d6fd6..b731d3cc7d 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -618,8 +618,6 @@ class CanvasItemEditorViewport : public Control {
void _show_resource_type_selector();
void _update_theme();
- static void _bind_methods();
-
protected:
void _notification(int p_what);
diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp
index 2df951518e..ba11479714 100644
--- a/editor/plugins/font_config_plugin.cpp
+++ b/editor/plugins/font_config_plugin.cpp
@@ -622,6 +622,16 @@ void EditorPropertyOTFeatures::update_property() {
supported = fd->get_supported_feature_list();
}
+ if (supported.is_empty()) {
+ edit->set_text(vformat(TTR("No supported features")));
+ if (container) {
+ set_bottom_editor(nullptr);
+ memdelete(container);
+ button_add = nullptr;
+ container = nullptr;
+ }
+ return;
+ }
edit->set_text(vformat(TTR("Features (%d of %d set)"), dict.size(), supported.size()));
bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property());
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index c8b49678d2..33aad0ac61 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -7645,6 +7645,7 @@ void Node3DEditor::_update_preview_environment() {
preview_sun->get_parent()->remove_child(preview_sun);
sun_state->show();
sun_vb->hide();
+ preview_sun_dangling = true;
}
if (directional_light_count > 0) {
@@ -7658,6 +7659,7 @@ void Node3DEditor::_update_preview_environment() {
add_child(preview_sun, true);
sun_state->hide();
sun_vb->show();
+ preview_sun_dangling = false;
}
}
@@ -7673,6 +7675,7 @@ void Node3DEditor::_update_preview_environment() {
preview_environment->get_parent()->remove_child(preview_environment);
environ_state->show();
environ_vb->hide();
+ preview_env_dangling = true;
}
if (world_env_count > 0) {
environ_state->set_text(TTR("Scene contains\nWorldEnvironment.\nPreview disabled."));
@@ -7685,6 +7688,7 @@ void Node3DEditor::_update_preview_environment() {
add_child(preview_environment);
environ_state->hide();
environ_vb->show();
+ preview_env_dangling = false;
}
}
}
@@ -7854,7 +7858,6 @@ Node3DEditor::Node3DEditor() {
sun_button->set_toggle_mode(true);
sun_button->set_flat(true);
sun_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED);
- sun_button->set_disabled(true);
// Preview is enabled by default - ensure this applies on editor startup when there is no state yet.
sun_button->set_pressed(true);
@@ -7865,7 +7868,6 @@ Node3DEditor::Node3DEditor() {
environ_button->set_toggle_mode(true);
environ_button->set_flat(true);
environ_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED);
- environ_button->set_disabled(true);
// Preview is enabled by default - ensure this applies on editor startup when there is no state yet.
environ_button->set_pressed(true);
@@ -8333,6 +8335,12 @@ void fragment() {
}
Node3DEditor::~Node3DEditor() {
memdelete(preview_node);
+ if (preview_sun_dangling && preview_sun) {
+ memdelete(preview_sun);
+ }
+ if (preview_env_dangling && preview_environment) {
+ memdelete(preview_environment);
+ }
}
void Node3DEditorPlugin::make_visible(bool p_visible) {
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 580cb878ce..c76f534c22 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -763,7 +763,9 @@ private:
Button *sun_environ_settings = nullptr;
DirectionalLight3D *preview_sun = nullptr;
+ bool preview_sun_dangling = false;
WorldEnvironment *preview_environment = nullptr;
+ bool preview_env_dangling = false;
Ref<Environment> environment;
Ref<CameraAttributesPhysical> camera_attributes;
Ref<ProceduralSkyMaterial> sky_material;
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 0a111aeb49..3679657567 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -227,6 +227,7 @@ void ScriptEditorBase::_bind_methods() {
// TODO: This signal is no use for VisualScript.
ADD_SIGNAL(MethodInfo("search_in_files_requested", PropertyInfo(Variant::STRING, "text")));
ADD_SIGNAL(MethodInfo("replace_in_files_requested", PropertyInfo(Variant::STRING, "text")));
+ ADD_SIGNAL(MethodInfo("go_to_method", PropertyInfo(Variant::OBJECT, "script"), PropertyInfo(Variant::STRING, "method")));
}
class EditorScriptCodeCompletionCache : public ScriptCodeCompletionCache {
@@ -2380,6 +2381,7 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
se->connect("request_save_history", callable_mp(this, &ScriptEditor::_save_history));
se->connect("search_in_files_requested", callable_mp(this, &ScriptEditor::_on_find_in_files_requested));
se->connect("replace_in_files_requested", callable_mp(this, &ScriptEditor::_on_replace_in_files_requested));
+ se->connect("go_to_method", callable_mp(this, &ScriptEditor::script_goto_method));
//test for modification, maybe the script was not edited but was loaded
@@ -2544,7 +2546,7 @@ void ScriptEditor::apply_scripts() const {
}
}
-void ScriptEditor::reload_scripts() {
+void ScriptEditor::reload_scripts(bool p_refresh_only) {
for (int i = 0; i < tab_container->get_tab_count(); i++) {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
@@ -2557,30 +2559,33 @@ void ScriptEditor::reload_scripts() {
continue; //internal script, who cares
}
- uint64_t last_date = edited_res->get_last_modified_time();
- uint64_t date = FileAccess::get_modified_time(edited_res->get_path());
+ if (!p_refresh_only) {
+ uint64_t last_date = edited_res->get_last_modified_time();
+ uint64_t date = FileAccess::get_modified_time(edited_res->get_path());
- if (last_date == date) {
- continue;
- }
+ if (last_date == date) {
+ continue;
+ }
- Ref<Script> script = edited_res;
- if (script != nullptr) {
- Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
- ERR_CONTINUE(!rel_script.is_valid());
- script->set_source_code(rel_script->get_source_code());
- script->set_last_modified_time(rel_script->get_last_modified_time());
- script->reload(true);
- }
+ Ref<Script> script = edited_res;
+ if (script != nullptr) {
+ Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
+ ERR_CONTINUE(!rel_script.is_valid());
+ script->set_source_code(rel_script->get_source_code());
+ script->set_last_modified_time(rel_script->get_last_modified_time());
+ script->reload(true);
+ }
- Ref<TextFile> text_file = edited_res;
- if (text_file != nullptr) {
- Error err;
- Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err);
- ERR_CONTINUE(!rel_text_file.is_valid());
- text_file->set_text(rel_text_file->get_text());
- text_file->set_last_modified_time(rel_text_file->get_last_modified_time());
+ Ref<TextFile> text_file = edited_res;
+ if (text_file != nullptr) {
+ Error err;
+ Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err);
+ ERR_CONTINUE(!rel_text_file.is_valid());
+ text_file->set_text(rel_text_file->get_text());
+ text_file->set_last_modified_time(rel_text_file->get_last_modified_time());
+ }
}
+
se->reload_text();
}
@@ -3059,26 +3064,15 @@ void ScriptEditor::shortcut_input(const Ref<InputEvent> &p_event) {
}
}
-void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) {
- Ref<InputEventMouseButton> mb = ev;
- if (mb.is_valid() && mb->is_pressed()) {
- switch (mb->get_button_index()) {
- case MouseButton::MIDDLE: {
- // Right-click selects automatically; middle-click does not.
- int idx = script_list->get_item_at_position(mb->get_position(), true);
- if (idx >= 0) {
- script_list->select(idx);
- _script_selected(idx);
- _menu_option(FILE_CLOSE);
- }
- } break;
+void ScriptEditor::_script_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index) {
+ if (p_mouse_button_index == MouseButton::MIDDLE) {
+ script_list->select(p_item);
+ _script_selected(p_item);
+ _menu_option(FILE_CLOSE);
+ }
- case MouseButton::RIGHT: {
- _make_script_list_context_menu();
- } break;
- default:
- break;
- }
+ if (p_mouse_button_index == MouseButton::RIGHT) {
+ _make_script_list_context_menu();
}
}
@@ -3688,7 +3682,7 @@ ScriptEditor::ScriptEditor() {
script_list->set_v_size_flags(SIZE_EXPAND_FILL);
script_split->set_split_offset(70 * EDSCALE);
_sort_list_on_update = true;
- script_list->connect("gui_input", callable_mp(this, &ScriptEditor::_script_list_gui_input), CONNECT_DEFERRED);
+ script_list->connect("item_clicked", callable_mp(this, &ScriptEditor::_script_list_clicked), CONNECT_DEFERRED);
script_list->set_allow_rmb_select(true);
script_list->set_drag_forwarding(this);
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index a8e6cc6868..1e78dc4ec4 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -426,7 +426,7 @@ class ScriptEditor : public PanelContainer {
virtual void input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
- void _script_list_gui_input(const Ref<InputEvent> &ev);
+ void _script_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index);
void _make_script_list_context_menu();
void _help_search(String p_text);
@@ -477,7 +477,7 @@ public:
bool toggle_scripts_panel();
bool is_scripts_panel_toggled();
void apply_scripts() const;
- void reload_scripts();
+ void reload_scripts(bool p_refresh_only = false);
void open_script_create_dialog(const String &p_base_name, const String &p_base_path);
void open_text_file_create_dialog(const String &p_base_path, const String &p_base_name = "");
Ref<Resource> open_file(const String &p_file);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 42dcfb8b1f..7a57f8a1e2 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -956,10 +956,7 @@ void ScriptTextEditor::_update_connected_methods() {
CodeEdit *text_edit = code_editor->get_text_editor();
text_edit->set_gutter_width(connection_gutter, text_edit->get_line_height());
for (int i = 0; i < text_edit->get_line_count(); i++) {
- if (text_edit->get_line_gutter_metadata(i, connection_gutter) == "") {
- continue;
- }
- text_edit->set_line_gutter_metadata(i, connection_gutter, "");
+ text_edit->set_line_gutter_metadata(i, connection_gutter, Dictionary());
text_edit->set_line_gutter_icon(i, connection_gutter, nullptr);
text_edit->set_line_gutter_clickable(i, connection_gutter, false);
}
@@ -974,6 +971,7 @@ void ScriptTextEditor::_update_connected_methods() {
return;
}
+ // Add connection icons to methods.
Vector<Node *> nodes = _find_all_node_for_script(base, base, script);
HashSet<StringName> methods_found;
for (int i = 0; i < nodes.size(); i++) {
@@ -1002,8 +1000,11 @@ void ScriptTextEditor::_update_connected_methods() {
for (int j = 0; j < functions.size(); j++) {
String name = functions[j].get_slice(":", 0);
if (name == method) {
+ Dictionary line_meta;
+ line_meta["type"] = "connection";
+ line_meta["method"] = method;
line = functions[j].get_slice(":", 1).to_int() - 1;
- text_edit->set_line_gutter_metadata(line, connection_gutter, method);
+ text_edit->set_line_gutter_metadata(line, connection_gutter, line_meta);
text_edit->set_line_gutter_icon(line, connection_gutter, get_parent_control()->get_theme_icon(SNAME("Slot"), SNAME("EditorIcons")));
text_edit->set_line_gutter_clickable(line, connection_gutter, true);
methods_found.insert(method);
@@ -1033,6 +1034,58 @@ void ScriptTextEditor::_update_connected_methods() {
}
}
}
+
+ // Add override icons to methods.
+ methods_found.clear();
+ for (int i = 0; i < functions.size(); i++) {
+ StringName name = StringName(functions[i].get_slice(":", 0));
+ if (methods_found.has(name)) {
+ continue;
+ }
+
+ String found_base_class;
+ StringName base_class = script->get_instance_base_type();
+ Ref<Script> inherited_script = script->get_base_script();
+ while (!inherited_script.is_null()) {
+ if (inherited_script->has_method(name)) {
+ found_base_class = "script:" + inherited_script->get_path();
+ break;
+ }
+
+ base_class = inherited_script->get_instance_base_type();
+ inherited_script = inherited_script->get_base_script();
+ }
+
+ if (found_base_class.is_empty() && base_class) {
+ List<MethodInfo> methods;
+ ClassDB::get_method_list(base_class, &methods);
+ for (int j = 0; j < methods.size(); j++) {
+ if (methods[j].name == name) {
+ found_base_class = "builtin:" + base_class;
+ break;
+ }
+ }
+ }
+
+ if (!found_base_class.is_empty()) {
+ int line = functions[i].get_slice(":", 1).to_int() - 1;
+
+ Dictionary line_meta = text_edit->get_line_gutter_metadata(line, connection_gutter);
+ if (line_meta.is_empty()) {
+ // Add override icon to gutter.
+ line_meta["type"] = "inherits";
+ line_meta["method"] = name;
+ line_meta["base_class"] = found_base_class;
+ text_edit->set_line_gutter_icon(line, connection_gutter, get_parent_control()->get_theme_icon(SNAME("MethodOverride"), SNAME("EditorIcons")));
+ text_edit->set_line_gutter_clickable(line, connection_gutter, true);
+ } else {
+ // If method is also connected to signal, then merge icons and keep the click behavior of the slot.
+ text_edit->set_line_gutter_icon(line, connection_gutter, get_parent_control()->get_theme_icon(SNAME("MethodOverrideAndSlot"), SNAME("EditorIcons")));
+ }
+
+ methods_found.insert(name);
+ }
+ }
}
void ScriptTextEditor::_update_gutter_indexes() {
@@ -1054,18 +1107,40 @@ void ScriptTextEditor::_gutter_clicked(int p_line, int p_gutter) {
return;
}
- String method = code_editor->get_text_editor()->get_line_gutter_metadata(p_line, p_gutter);
- if (method.is_empty()) {
+ Dictionary meta = code_editor->get_text_editor()->get_line_gutter_metadata(p_line, p_gutter);
+ String type = meta.get("type", "");
+ if (type.is_empty()) {
return;
}
- Node *base = get_tree()->get_edited_scene_root();
- if (!base) {
+ // All types currently need a method name.
+ String method = meta.get("method", "");
+ if (method.is_empty()) {
return;
}
- Vector<Node *> nodes = _find_all_node_for_script(base, base, script);
- connection_info_dialog->popup_connections(method, nodes);
+ if (type == "connection") {
+ Node *base = get_tree()->get_edited_scene_root();
+ if (!base) {
+ return;
+ }
+
+ Vector<Node *> nodes = _find_all_node_for_script(base, base, script);
+ connection_info_dialog->popup_connections(method, nodes);
+ } else if (type == "inherits") {
+ String base_class_raw = meta["base_class"];
+ PackedStringArray base_class_split = base_class_raw.split(":", true, 1);
+
+ if (base_class_split[0] == "script") {
+ // Go to function declaration.
+ Ref<Script> base_script = ResourceLoader::load(base_class_split[1]);
+ ERR_FAIL_COND(!base_script.is_valid());
+ emit_signal(SNAME("go_to_method"), base_script, method);
+ } else if (base_class_split[0] == "builtin") {
+ // Open method documentation.
+ emit_signal(SNAME("go_to_help"), "class_method:" + base_class_split[1] + ":" + method);
+ }
+ }
}
void ScriptTextEditor::_edit_option(int p_op) {
@@ -1487,16 +1562,17 @@ bool ScriptTextEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_
}
static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) {
- if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene) {
- return nullptr;
- }
-
- Ref<Script> scr = p_current_node->get_script();
-
- if (scr.is_valid() && scr == script) {
- return p_current_node;
+ // Check scripts only for the nodes belonging to the edited scene.
+ if (p_current_node == p_edited_scene || p_current_node->get_owner() == p_edited_scene) {
+ Ref<Script> scr = p_current_node->get_script();
+ if (scr.is_valid() && scr == script) {
+ return p_current_node;
+ }
}
+ // Traverse all children, even the ones not owned by the edited scene as they
+ // can still have child nodes added within the edited scene and thus owned by
+ // it (e.g. nodes added to subscene's root or to its editable children).
for (int i = 0; i < p_current_node->get_child_count(); i++) {
Node *n = _find_script_node(p_edited_scene, p_current_node->get_child(i), script);
if (n) {
@@ -1558,8 +1634,13 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
}
if (d.has("type") && String(d["type"]) == "nodes") {
- Node *sn = _find_script_node(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root(), script);
+ Node *scene_root = get_tree()->get_edited_scene_root();
+ if (!scene_root) {
+ EditorNode::get_singleton()->show_warning(TTR("Can't drop nodes without an open scene."));
+ return;
+ }
+ Node *sn = _find_script_node(scene_root, scene_root, script);
if (!sn) {
EditorNode::get_singleton()->show_warning(vformat(TTR("Can't drop nodes because script '%s' is not used in this scene."), get_name()));
return;
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 246bc4b183..ae3c578eaa 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -1366,6 +1366,7 @@ void ShaderEditorPlugin::_shader_selected(int p_index) {
edited_shaders[p_index].shader_editor->validate_script();
}
shader_tabs->set_current_tab(p_index);
+ shader_list->select(p_index);
}
void ShaderEditorPlugin::_shader_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index) {
@@ -1375,11 +1376,10 @@ void ShaderEditorPlugin::_shader_list_clicked(int p_item, Vector2 p_local_mouse_
}
void ShaderEditorPlugin::_close_shader(int p_index) {
- int index = shader_tabs->get_current_tab();
- ERR_FAIL_INDEX(index, shader_tabs->get_tab_count());
- Control *c = shader_tabs->get_tab_control(index);
+ ERR_FAIL_INDEX(p_index, shader_tabs->get_tab_count());
+ Control *c = shader_tabs->get_tab_control(p_index);
memdelete(c);
- edited_shaders.remove_at(index);
+ edited_shaders.remove_at(p_index);
_update_shader_list();
EditorNode::get_singleton()->get_undo_redo()->clear_history(); // To prevent undo on deleted graphs.
}
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index ae21aad337..d0a1ddafa1 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -984,11 +984,17 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) {
}
void SpriteFramesEditor::edit(SpriteFrames *p_frames) {
- if (frames == p_frames) {
+ bool new_read_only_state = false;
+ if (p_frames) {
+ new_read_only_state = EditorNode::get_singleton()->is_resource_read_only(p_frames);
+ }
+
+ if (frames == p_frames && new_read_only_state == read_only) {
return;
}
frames = p_frames;
+ read_only = new_read_only_state;
if (p_frames) {
if (!p_frames->has_animation(edited_anim)) {
@@ -1009,6 +1015,20 @@ void SpriteFramesEditor::edit(SpriteFrames *p_frames) {
} else {
hide();
}
+
+ new_anim->set_disabled(read_only);
+ remove_anim->set_disabled(read_only);
+ anim_speed->set_editable(!read_only);
+ anim_loop->set_disabled(read_only);
+ load->set_disabled(read_only);
+ load_sheet->set_disabled(read_only);
+ copy->set_disabled(read_only);
+ paste->set_disabled(read_only);
+ empty->set_disabled(read_only);
+ empty2->set_disabled(read_only);
+ move_up->set_disabled(read_only);
+ move_down->set_disabled(read_only);
+ _delete->set_disabled(read_only);
}
void SpriteFramesEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
@@ -1016,6 +1036,10 @@ void SpriteFramesEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
}
Variant SpriteFramesEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
+ if (read_only) {
+ return false;
+ }
+
if (!frames->has_animation(edited_anim)) {
return false;
}
@@ -1038,6 +1062,10 @@ Variant SpriteFramesEditor::get_drag_data_fw(const Point2 &p_point, Control *p_f
}
bool SpriteFramesEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+ if (read_only) {
+ return false;
+ }
+
Dictionary d = p_data;
if (!d.has("type")) {
@@ -1169,6 +1197,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
remove_anim->set_flat(true);
remove_anim->set_tooltip_text(TTR("Remove Animation"));
hbc_animlist->add_child(remove_anim);
+ remove_anim->set_disabled(true);
remove_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_remove));
anim_search_box = memnew(LineEdit);
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index f2530b732f..092f556c63 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -57,6 +57,8 @@ class SpriteFramesEditor : public HSplitContainer {
};
int dominant_param = PARAM_FRAME_COUNT;
+ bool read_only = false;
+
Button *load = nullptr;
Button *load_sheet = nullptr;
Button *_delete = nullptr;
diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp
index 3ea62184c6..4b2f28658a 100644
--- a/editor/plugins/texture_3d_editor_plugin.cpp
+++ b/editor/plugins/texture_3d_editor_plugin.cpp
@@ -138,10 +138,6 @@ void Texture3DEditor::edit(Ref<Texture3D> p_texture) {
}
}
-void Texture3DEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_layer_changed"), &Texture3DEditor::_layer_changed);
-}
-
Texture3DEditor::Texture3DEditor() {
set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);
set_custom_minimum_size(Size2(1, 150));
@@ -173,7 +169,7 @@ Texture3DEditor::Texture3DEditor() {
info->add_theme_constant_override("shadow_offset_y", 2);
setting = false;
- layer->connect("value_changed", Callable(this, "_layer_changed"));
+ layer->connect("value_changed", callable_mp(this, &Texture3DEditor::_layer_changed));
}
Texture3DEditor::~Texture3DEditor() {
diff --git a/editor/plugins/texture_3d_editor_plugin.h b/editor/plugins/texture_3d_editor_plugin.h
index 357bdb0845..7795c83c8a 100644
--- a/editor/plugins/texture_3d_editor_plugin.h
+++ b/editor/plugins/texture_3d_editor_plugin.h
@@ -66,8 +66,6 @@ class Texture3DEditor : public Control {
protected:
void _notification(int p_what);
- static void _bind_methods();
-
public:
void edit(Ref<Texture3D> p_texture);
Texture3DEditor();
diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp
index dd8633360e..b0a174c1bc 100644
--- a/editor/plugins/texture_layered_editor_plugin.cpp
+++ b/editor/plugins/texture_layered_editor_plugin.cpp
@@ -214,10 +214,6 @@ void TextureLayeredEditor::edit(Ref<TextureLayered> p_texture) {
}
}
-void TextureLayeredEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_layer_changed"), &TextureLayeredEditor::_layer_changed);
-}
-
TextureLayeredEditor::TextureLayeredEditor() {
set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);
set_custom_minimum_size(Size2(1, 150));
@@ -249,7 +245,7 @@ TextureLayeredEditor::TextureLayeredEditor() {
info->add_theme_constant_override("shadow_offset_y", 2);
setting = false;
- layer->connect("value_changed", Callable(this, "_layer_changed"));
+ layer->connect("value_changed", callable_mp(this, &TextureLayeredEditor::_layer_changed));
}
TextureLayeredEditor::~TextureLayeredEditor() {
diff --git a/editor/plugins/texture_layered_editor_plugin.h b/editor/plugins/texture_layered_editor_plugin.h
index f49aa83eb2..f4dbc104c8 100644
--- a/editor/plugins/texture_layered_editor_plugin.h
+++ b/editor/plugins/texture_layered_editor_plugin.h
@@ -68,7 +68,6 @@ class TextureLayeredEditor : public Control {
protected:
void _notification(int p_what);
virtual void gui_input(const Ref<InputEvent> &p_event) override;
- static void _bind_methods();
public:
void edit(Ref<TextureLayered> p_texture);
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 1fb9b42449..e2ed8e44c4 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -134,7 +134,7 @@ void ThemeItemImportTree::_update_items_tree() {
data_type_node->set_checked(IMPORT_ITEM_DATA, false);
data_type_node->set_editable(IMPORT_ITEM_DATA, true);
- List<TreeItem *> *item_list;
+ List<TreeItem *> *item_list = nullptr;
switch (dt) {
case Theme::DATA_TYPE_COLOR:
@@ -398,7 +398,7 @@ void ThemeItemImportTree::_restore_selected_item(TreeItem *p_tree_item) {
void ThemeItemImportTree::_update_total_selected(Theme::DataType p_data_type) {
ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
- Label *total_selected_items_label;
+ Label *total_selected_items_label = nullptr;
switch (p_data_type) {
case Theme::DATA_TYPE_COLOR:
total_selected_items_label = total_selected_colors_label;
@@ -562,7 +562,7 @@ void ThemeItemImportTree::_select_all_data_type_pressed(int p_data_type) {
}
Theme::DataType data_type = (Theme::DataType)p_data_type;
- List<TreeItem *> *item_list;
+ List<TreeItem *> *item_list = nullptr;
switch (data_type) {
case Theme::DATA_TYPE_COLOR:
@@ -617,7 +617,7 @@ void ThemeItemImportTree::_select_full_data_type_pressed(int p_data_type) {
}
Theme::DataType data_type = (Theme::DataType)p_data_type;
- List<TreeItem *> *item_list;
+ List<TreeItem *> *item_list = nullptr;
switch (data_type) {
case Theme::DATA_TYPE_COLOR:
@@ -674,7 +674,7 @@ void ThemeItemImportTree::_deselect_all_data_type_pressed(int p_data_type) {
}
Theme::DataType data_type = (Theme::DataType)p_data_type;
- List<TreeItem *> *item_list;
+ List<TreeItem *> *item_list = nullptr;
switch (data_type) {
case Theme::DATA_TYPE_COLOR:
@@ -982,17 +982,17 @@ ThemeItemImportTree::ThemeItemImportTree() {
for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) {
Theme::DataType dt = (Theme::DataType)i;
- TextureRect *select_items_icon;
- Label *select_items_label;
- Button *deselect_all_items_button;
- Button *select_all_items_button;
- Button *select_full_items_button;
- Label *total_selected_items_label;
-
- String items_title = "";
- String select_all_items_tooltip = "";
- String select_full_items_tooltip = "";
- String deselect_all_items_tooltip = "";
+ TextureRect *select_items_icon = nullptr;
+ Label *select_items_label = nullptr;
+ Button *deselect_all_items_button = nullptr;
+ Button *select_all_items_button = nullptr;
+ Button *select_full_items_button = nullptr;
+ Label *total_selected_items_label = nullptr;
+
+ String items_title;
+ String select_all_items_tooltip;
+ String select_full_items_tooltip;
+ String deselect_all_items_tooltip;
switch (dt) {
case Theme::DATA_TYPE_COLOR:
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index d9291503cb..c823487279 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -403,6 +403,9 @@ void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_
// Update everything.
_update_zoom_and_panning();
+ base_tiles_drawing_root->set_size(_compute_base_tiles_control_size());
+ alternative_tiles_drawing_root->set_size(_compute_alternative_tiles_control_size());
+
// Update.
base_tiles_draw->queue_redraw();
base_tiles_texture_grid->queue_redraw();
@@ -601,7 +604,6 @@ TileAtlasView::TileAtlasView() {
base_tiles_drawing_root = memnew(Control);
base_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
- base_tiles_drawing_root->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
base_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST);
base_tiles_root_control->add_child(base_tiles_drawing_root);
@@ -645,7 +647,6 @@ TileAtlasView::TileAtlasView() {
alternative_tiles_drawing_root = memnew(Control);
alternative_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
- alternative_tiles_drawing_root->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
alternative_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST);
alternative_tiles_root_control->add_child(alternative_tiles_drawing_root);
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 228e475083..45b2a5eb14 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -401,7 +401,7 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<Pro
if (all_alternatve_id_zero) {
p_list->push_back(PropertyInfo(Variant::NIL, "Animation", PROPERTY_HINT_NONE, "animation_", PROPERTY_USAGE_GROUP));
p_list->push_back(PropertyInfo(Variant::INT, "animation_columns", PROPERTY_HINT_NONE, ""));
- p_list->push_back(PropertyInfo(Variant::VECTOR2I, "animation_separation", PROPERTY_HINT_NONE, "suffix:px"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, "animation_separation", PROPERTY_HINT_NONE, ""));
p_list->push_back(PropertyInfo(Variant::FLOAT, "animation_speed", PROPERTY_HINT_NONE, ""));
p_list->push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Frames,animation_frame_"));
// Not optimal, but returns value for the first tile. This is similar to what MultiNodeEdit does.
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index ee8148f00a..7c4326cde1 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -1358,7 +1358,7 @@ void VisualShaderEditor::_update_options_menu() {
Color unsupported_color = get_theme_color(SNAME("error_color"), SNAME("Editor"));
Color supported_color = get_theme_color(SNAME("warning_color"), SNAME("Editor"));
- static bool low_driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name") == "opengl3";
+ static bool low_driver = ProjectSettings::get_singleton()->get("rendering/renderer/rendering_method") == "gl_compatibility";
HashMap<String, TreeItem *> folders;
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index 39b30b31fb..f8ba3f0354 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -38,6 +38,7 @@ const int ERROR_CODE = 77;
#include "modules/regex/regex.h"
+#include "core/io/dir_access.h"
#include "core/os/time.h"
#include "core/templates/hash_map.h"
#include "core/templates/list.h"
@@ -216,6 +217,7 @@ static const char *gdscript_function_renames[][2] = {
{ "_get_configuration_warning", "_get_configuration_warnings" }, // Node
{ "_set_current", "set_current" }, // Camera2D
{ "_set_editor_description", "set_editor_description" }, // Node
+ { "_set_playing", "set_playing" }, // AnimatedSprite3D
{ "_toplevel_raise_self", "_top_level_raise_self" }, // CanvasItem
{ "_update_wrap_at", "_update_wrap_at_column" }, // TextEdit
{ "add_animation", "add_animation_library" }, // AnimationPlayer
@@ -230,6 +232,7 @@ static const char *gdscript_function_renames[][2] = {
{ "add_scene_import_plugin", "add_scene_format_importer_plugin" }, //EditorPlugin
{ "add_stylebox_override", "add_theme_stylebox_override" }, // Control
{ "add_torque", "apply_torque" }, //RigidBody2D
+ { "agent_set_neighbor_dist", "agent_set_neighbor_distance" }, // NavigationServer2D, NavigationServer3D
{ "apply_changes", "_apply_changes" }, // EditorPlugin
{ "body_add_force", "body_apply_force" }, // PhysicsServer2D
{ "body_add_torque", "body_apply_torque" }, // PhysicsServer2D
@@ -331,6 +334,7 @@ static const char *gdscript_function_renames[][2] = {
{ "get_metakey", "is_meta_pressed" }, // InputEventWithModifiers
{ "get_mid_height", "get_height" }, // CapsuleMesh
{ "get_motion_remainder", "get_remainder" }, // PhysicsTestMotionResult2D
+ { "get_neighbor_dist", "get_neighbor_distance" }, // NavigationAgent2D, NavigationAgent3D
{ "get_network_connected_peers", "get_peers" }, // Multiplayer API
{ "get_network_master", "get_multiplayer_authority" }, // Node
{ "get_network_peer", "get_multiplayer_peer" }, // Multiplayer API
@@ -418,6 +422,7 @@ static const char *gdscript_function_renames[][2] = {
{ "is_normalmap", "is_normal_map" }, // NoiseTexture
{ "is_refusing_new_network_connections", "is_refusing_new_connections" }, // Multiplayer API
{ "is_region", "is_region_enabled" }, // Sprite2D
+ { "is_rotating", "is_ignoring_rotation" }, // Camera2D
{ "is_scancode_unicode", "is_keycode_unicode" }, // OS
{ "is_selectable_when_hidden", "_is_selectable_when_hidden" }, // EditorNode3DGizmoPlugin
{ "is_set_as_toplevel", "is_set_as_top_level" }, // CanvasItem
@@ -510,6 +515,7 @@ static const char *gdscript_function_renames[][2] = {
{ "set_max_atlas_size", "set_max_texture_size" }, // LightmapGI
{ "set_metakey", "set_meta_pressed" }, // InputEventWithModifiers
{ "set_mid_height", "set_height" }, // CapsuleMesh
+ { "set_neighbor_dist", "set_neighbor_distance" }, // NavigationAgent2D, NavigationAgent3D
{ "set_network_master", "set_multiplayer_authority" }, // Node
{ "set_network_peer", "set_multiplayer_peer" }, // Multiplayer API
{ "set_oneshot", "set_one_shot" }, // AnimatedTexture
@@ -650,6 +656,7 @@ static const char *csharp_function_renames[][2] = {
{ "_GetConfigurationWarning", "_GetConfigurationWarnings" }, // Node
{ "_SetCurrent", "SetCurrent" }, // Camera2D
{ "_SetEditorDescription", "SetEditorDescription" }, // Node
+ { "_SetPlaying", "SetPlaying" }, // AnimatedSprite3D
{ "_ToplevelRaiseSelf", "_TopLevelRaiseSelf" }, // CanvasItem
{ "_UpdateWrapAt", "_UpdateWrapAtColumn" }, // TextEdit
{ "AddAnimation", "AddAnimationLibrary" }, // AnimationPlayer
@@ -664,6 +671,7 @@ static const char *csharp_function_renames[][2] = {
{ "AddSceneImportPlugin", "AddSceneFormatImporterPlugin" }, //EditorPlugin
{ "AddStyleboxOverride", "AddThemeStyleboxOverride" }, // Control
{ "AddTorque", "AddConstantTorque" }, //RigidBody2D
+ { "AgentSetNeighborDist", "AgentSetNeighborDistance" }, // NavigationServer2D, NavigationServer3D
{ "BindChildNodeToBone", "SetBoneChildren" }, // Skeleton3D
{ "BumpmapToNormalmap", "BumpMapToNormalMap" }, // Image
{ "CanBeHidden", "_CanBeHidden" }, // EditorNode3DGizmoPlugin
@@ -757,6 +765,7 @@ static const char *csharp_function_renames[][2] = {
{ "GetMetakey", "IsMetaPressed" }, // InputEventWithModifiers
{ "GetMidHeight", "GetHeight" }, // CapsuleMesh
{ "GetMotionRemainder", "GetRemainder" }, // PhysicsTestMotionResult2D
+ { "GetNeighborDist", "GetNeighborDistance" }, // NavigationAgent2D, NavigationAgent3D
{ "GetNetworkConnectedPeers", "GetPeers" }, // Multiplayer API
{ "GetNetworkMaster", "GetMultiplayerAuthority" }, // Node
{ "GetNetworkPeer", "GetMultiplayerPeer" }, // Multiplayer API
@@ -840,6 +849,7 @@ static const char *csharp_function_renames[][2] = {
{ "IsNormalmap", "IsNormalMap" }, // NoiseTexture
{ "IsRefusingNewNetworkConnections", "IsRefusingNewConnections" }, // Multiplayer API
{ "IsRegion", "IsRegionEnabled" }, // Sprite2D
+ { "IsRotating", "IsIgnoringRotation" }, // Camera2D
{ "IsScancodeUnicode", "IsKeycodeUnicode" }, // OS
{ "IsSelectableWhenHidden", "_IsSelectableWhenHidden" }, // EditorNode3DGizmoPlugin
{ "IsSetAsToplevel", "IsSetAsTopLevel" }, // CanvasItem
@@ -926,6 +936,7 @@ static const char *csharp_function_renames[][2] = {
{ "SetMaxAtlasSize", "SetMaxTextureSize" }, // LightmapGI
{ "SetMetakey", "SetMetaPressed" }, // InputEventWithModifiers
{ "SetMidHeight", "SetHeight" }, // CapsuleMesh
+ { "SetNeighborDist", "SetNeighborDistance" }, // NavigationAgent2D, NavigationAgent3D
{ "SetNetworkMaster", "SetMultiplayerAuthority" }, // Node
{ "SetNetworkPeer", "SetMultiplayerPeer" }, // Multiplayer API
{ "SetOneshot", "SetOneShot" }, // AnimatedTexture
@@ -1061,6 +1072,7 @@ static const char *gdscript_properties_renames[][2] = {
{ "focus_neighbour_left", "focus_neighbor_left" }, // Control
{ "focus_neighbour_right", "focus_neighbor_right" }, // Control
{ "focus_neighbour_top", "focus_neighbor_top" }, // Control
+ { "follow_viewport_enable", "follow_viewport_enabled" }, // CanvasItem
{ "file_icon_modulate", "file_icon_color" }, // Theme
{ "files_disabled", "file_disabled_color" }, // Theme
{ "folder_icon_modulate", "folder_icon_color" }, // Theme
@@ -1076,6 +1088,7 @@ static const char *gdscript_properties_renames[][2] = {
{ "margin_right", "offset_right" }, // Control broke NinePatchRect, StyleBox
{ "margin_top", "offset_top" }, // Control broke NinePatchRect, StyleBox
{ "mid_height", "height" }, // CapsuleMesh
+ { "neighbor_dist", "neighbor_distance" }, // NavigationAgent2D, NavigationAgent3D
{ "offset_h", "drag_horizontal_offset" }, // Camera2D
{ "offset_v", "drag_vertical_offset" }, // Camera2D
{ "off", "unchecked" }, // Theme
@@ -1164,6 +1177,7 @@ static const char *csharp_properties_renames[][2] = {
{ "FocusNeighbourLeft", "FocusNeighborLeft" }, // Control
{ "FocusNeighbourRight", "FocusNeighborRight" }, // Control
{ "FocusNeighbourTop", "FocusNeighborTop" }, // Control
+ { "FollowViewportEnable", "FollowViewportEnabled" }, // CanvasItem
{ "GlobalRateScale", "PlaybackSpeedScale" }, // AudioServer
{ "GravityDistanceScale", "GravityPointDistanceScale" }, // Area2D
{ "GravityVec", "GravityDirection" }, // Area2D
@@ -1176,6 +1190,7 @@ static const char *csharp_properties_renames[][2] = {
{ "MarginRight", "OffsetRight" }, // Control broke NinePatchRect, StyleBox
{ "MarginTop", "OffsetTop" }, // Control broke NinePatchRect, StyleBox
{ "MidHeight", "Height" }, // CapsuleMesh
+ { "NeighborDist", "NeighborDistance" }, // NavigationAgent2D, NavigationAgent3D
{ "OffsetH", "DragHorizontalOffset" }, // Camera2D
{ "OffsetV", "DragVerticalOffset" }, // Camera2D
{ "Ofs", "Offset" }, // Theme
@@ -2229,22 +2244,23 @@ Vector<String> ProjectConverter3To4::check_for_files() {
Vector<String> directories_to_check = Vector<String>();
directories_to_check.push_back("res://");
- core_bind::Directory dir = core_bind::Directory();
while (!directories_to_check.is_empty()) {
String path = directories_to_check.get(directories_to_check.size() - 1); // Is there any pop_back function?
- directories_to_check.resize(directories_to_check.size() - 1); // Remove last element.
- if (dir.open(path) == OK) {
- dir.set_include_hidden(true);
- dir.list_dir_begin();
- String current_dir = dir.get_current_dir();
- String file_name = dir.get_next();
+ directories_to_check.resize(directories_to_check.size() - 1); // Remove last element
+
+ Ref<DirAccess> dir = DirAccess::create_for_path(path);
+ if (dir.is_valid()) {
+ dir->set_include_hidden(true);
+ dir->list_dir_begin();
+ String current_dir = dir->get_current_dir();
+ String file_name = dir->_get_next();
while (file_name != "") {
if (file_name == ".git" || file_name == ".import" || file_name == ".godot") {
- file_name = dir.get_next();
+ file_name = dir->_get_next();
continue;
}
- if (dir.current_is_dir()) {
+ if (dir->current_is_dir()) {
directories_to_check.append(current_dir.path_join(file_name) + "/");
} else {
bool proper_extension = false;
@@ -2255,7 +2271,7 @@ Vector<String> ProjectConverter3To4::check_for_files() {
collected_files.append(current_dir.path_join(file_name));
}
}
- file_name = dir.get_next();
+ file_name = dir->_get_next();
}
} else {
print_verbose("Failed to open " + path);
@@ -2331,12 +2347,13 @@ bool ProjectConverter3To4::test_conversion(RegExContainer &reg_container) {
valid = valid && test_conversion_with_regex("[Master]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
valid = valid && test_conversion_with_regex("[MasterSync]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
- valid = valid && test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\"display/window/size/fullscreen\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true);
+ valid = valid && test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "if Settings.fullscreen:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)\nelse:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("OS.get_window_safe_area()", "DisplayServer.get_display_safe_area()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tmove_and_slide( a, b, c, d, e, f ) # Roman", "\tset_velocity(a)\n\tset_up_direction(b)\n\tset_floor_stop_on_slope_enabled(c)\n\tset_max_slides(d)\n\tset_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tmove_and_slide() # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide_with_snap( a, g, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tmove_and_slide_with_snap( a, g, b, c, d, e, f ) # Roman", "\tset_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tset_up_direction(b)\n\tset_floor_stop_on_slope_enabled(c)\n\tset_max_slides(d)\n\tset_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tmove_and_slide() # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a , b )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
@@ -3090,13 +3107,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
line = reg_container.reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true);
}
- // OS.window_fullscreen = true -> ProjectSettings.set("display/window/size/fullscreen",true)
+ // OS.window_fullscreen = a -> if a: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN) else: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
if (line.contains("window_fullscreen")) {
- if (builtin) {
- line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", $1)", true);
- } else {
- line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true);
- }
+ line = reg_container.reg_os_fullscreen.sub(line, "if $1:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)\nelse:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)", true);
}
// Instantiate
@@ -3144,8 +3157,13 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[5] + "`\n";
}
- line_new += starting_space + base_obj + "move_and_slide()\n";
- line = line_new + line.substr(0, start) + "velocity" + line.substr(end + start);
+ line_new += starting_space + base_obj + "move_and_slide()";
+
+ if (!line.begins_with(starting_space + "move_and_slide")) {
+ line = line_new + "\n" + line.substr(0, start) + "velocity" + line.substr(end + start);
+ } else {
+ line = line_new + line.substr(end + start);
+ }
}
}
}
@@ -3195,8 +3213,13 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[6] + "`\n";
}
- line_new += starting_space + base_obj + "move_and_slide()\n";
- line = line_new + line.substr(0, start) + "velocity" + line.substr(end + start); // move_and_slide used to return velocity
+ line_new += starting_space + base_obj + "move_and_slide()";
+
+ if (!line.begins_with(starting_space + "move_and_slide_with_snap")) {
+ line = line_new + "\n" + line.substr(0, start) + "velocity" + line.substr(end + start);
+ } else {
+ line = line_new + line.substr(end + start);
+ }
}
}
}
@@ -3490,6 +3513,20 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
}
+
+ // set_rotating(true) -> set_ignore_rotation(false)
+ if (line.contains("set_rotating(")) {
+ int start = line.find("set_rotating(");
+ int end = get_end_parenthesis(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 1) {
+ String opposite = parts[0] == "true" ? "false" : "true";
+ line = line.substr(0, start) + "set_ignore_rotation(" + opposite + ")";
+ }
+ }
+ }
+
// OS.get_window_safe_area() -> DisplayServer.get_display_safe_area()
if (line.contains("OS.get_window_safe_area(")) {
int start = line.find("OS.get_window_safe_area(");
@@ -3537,6 +3574,29 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
+ // rotating = true -> ignore_rotation = false # reversed "rotating" for Camera2D
+ if (line.contains("rotating")) {
+ int start = line.find("rotating");
+ bool foundNextEqual = false;
+ String line_to_check = line.substr(start + String("rotating").length());
+ String assigned_value;
+ for (int current_index = 0; line_to_check.length() > current_index; current_index++) {
+ char32_t chr = line_to_check.get(current_index);
+ if (chr == '\t' || chr == ' ') {
+ continue;
+ } else if (chr == '=') {
+ foundNextEqual = true;
+ assigned_value = line.right(current_index).strip_edges();
+ assigned_value = assigned_value == "true" ? "false" : "true";
+ } else {
+ break;
+ }
+ }
+ if (foundNextEqual) {
+ line = line.substr(0, start) + "ignore_rotation =" + assigned_value + " # reversed \"rotating\" for Camera2D";
+ }
+ }
+
// OS -> Time functions
if (line.contains("OS.get_ticks_msec")) {
line = line.replace("OS.get_ticks_msec", "Time.get_ticks_msec");
@@ -3950,6 +4010,8 @@ String ProjectConverter3To4::collect_string_from_vector(Vector<String> &vector)
#else // No RegEx.
+ProjectConverter3To4::ProjectConverter3To4(int _p_maximum_file_size_kb, int _p_maximum_line_length) {}
+
int ProjectConverter3To4::convert() {
ERR_FAIL_V_MSG(ERROR_CODE, "Can't run converter for Godot 3.x projects, because RegEx module is disabled.");
}
diff --git a/editor/project_converter_3_to_4.h b/editor/project_converter_3_to_4.h
index 2cecb9da79..d03e645ac7 100644
--- a/editor/project_converter_3_to_4.h
+++ b/editor/project_converter_3_to_4.h
@@ -31,7 +31,6 @@
#ifndef PROJECT_CONVERTER_3_TO_4_H
#define PROJECT_CONVERTER_3_TO_4_H
-#include "core/core_bind.h"
#include "core/io/file_access.h"
#include "core/object/ref_counted.h"
#include "core/string/ustring.h"
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index f11874a994..673da8872d 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -92,9 +92,9 @@ private:
Container *name_container;
Container *path_container;
Container *install_path_container;
- Container *rasterizer_container;
+ Container *renderer_container;
HBoxContainer *default_files_container;
- Ref<ButtonGroup> rasterizer_button_group;
+ Ref<ButtonGroup> renderer_button_group;
Label *msg;
LineEdit *project_path;
LineEdit *project_name;
@@ -473,16 +473,19 @@ private:
}
PackedStringArray project_features = ProjectSettings::get_required_features();
ProjectSettings::CustomMap initial_settings;
+
// Be sure to change this code if/when renderers are changed.
- int renderer_type = rasterizer_button_group->get_pressed_button()->get_meta(SNAME("driver_name"));
- initial_settings["rendering/vulkan/rendering/back_end"] = renderer_type;
- if (renderer_type == 0) {
- project_features.push_back("Vulkan Clustered");
- } else if (renderer_type == 1) {
- project_features.push_back("Vulkan Mobile");
+ String renderer_type = renderer_button_group->get_pressed_button()->get_meta(SNAME("rendering_method"));
+ initial_settings["rendering/renderer/rendering_method"] = renderer_type;
+
+ if (renderer_type == "forward_plus") {
+ project_features.push_back("Forward Plus");
+ } else if (renderer_type == "mobile") {
+ project_features.push_back("Mobile");
} else {
WARN_PRINT("Unknown renderer type. Please report this as a bug on GitHub.");
}
+
project_features.sort();
initial_settings["application/config/features"] = project_features;
initial_settings["application/config/name"] = project_name->get_text().strip_edges();
@@ -684,7 +687,7 @@ public:
msg->hide();
install_path_container->hide();
install_status_rect->hide();
- rasterizer_container->hide();
+ renderer_container->hide();
default_files_container->hide();
get_ok_button()->set_disabled(false);
@@ -735,7 +738,7 @@ public:
set_ok_button_text(TTR("Import & Edit"));
name_container->hide();
install_path_container->hide();
- rasterizer_container->hide();
+ renderer_container->hide();
default_files_container->hide();
project_path->grab_focus();
@@ -744,7 +747,7 @@ public:
set_ok_button_text(TTR("Create & Edit"));
name_container->show();
install_path_container->hide();
- rasterizer_container->show();
+ renderer_container->show();
default_files_container->show();
project_name->call_deferred(SNAME("grab_focus"));
project_name->call_deferred(SNAME("select_all"));
@@ -755,7 +758,7 @@ public:
project_name->set_text(zip_title);
name_container->show();
install_path_container->hide();
- rasterizer_container->hide();
+ renderer_container->hide();
default_files_container->hide();
project_path->grab_focus();
}
@@ -843,23 +846,23 @@ public:
msg->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
vb->add_child(msg);
- // rasterizer selection
- rasterizer_container = memnew(VBoxContainer);
- vb->add_child(rasterizer_container);
+ // Renderer selection.
+ renderer_container = memnew(VBoxContainer);
+ vb->add_child(renderer_container);
l = memnew(Label);
l->set_text(TTR("Renderer:"));
- rasterizer_container->add_child(l);
- Container *rshb = memnew(HBoxContainer);
- rasterizer_container->add_child(rshb);
- rasterizer_button_group.instantiate();
+ renderer_container->add_child(l);
+ HBoxContainer *rshc = memnew(HBoxContainer);
+ renderer_container->add_child(rshc);
+ renderer_button_group.instantiate();
Container *rvb = memnew(VBoxContainer);
rvb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- rshb->add_child(rvb);
+ rshc->add_child(rvb);
Button *rs_button = memnew(CheckBox);
- rs_button->set_button_group(rasterizer_button_group);
- rs_button->set_text(TTR("Vulkan Clustered"));
- rs_button->set_meta(SNAME("driver_name"), 0); // Vulkan backend "Forward Clustered"
+ rs_button->set_button_group(renderer_button_group);
+ rs_button->set_text(TTR("Forward+"));
+ rs_button->set_meta(SNAME("rendering_method"), "forward_plus");
rs_button->set_pressed(true);
rvb->add_child(rs_button);
l = memnew(Label);
@@ -871,15 +874,15 @@ public:
l->set_modulate(Color(1, 1, 1, 0.7));
rvb->add_child(l);
- rshb->add_child(memnew(VSeparator));
+ rshc->add_child(memnew(VSeparator));
rvb = memnew(VBoxContainer);
rvb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- rshb->add_child(rvb);
+ rshc->add_child(rvb);
rs_button = memnew(CheckBox);
- rs_button->set_button_group(rasterizer_button_group);
- rs_button->set_text(TTR("Vulkan Mobile"));
- rs_button->set_meta(SNAME("driver_name"), 1); // Vulkan backend "Forward Mobile"
+ rs_button->set_button_group(renderer_button_group);
+ rs_button->set_text(TTR("Mobile"));
+ rs_button->set_meta(SNAME("rendering_method"), "mobile");
rvb->add_child(rs_button);
l = memnew(Label);
l->set_text(
@@ -897,7 +900,7 @@ public:
l->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
l->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
l->set_modulate(Color(1, 1, 1, 0.7));
- rasterizer_container->add_child(l);
+ renderer_container->add_child(l);
default_files_container = memnew(HBoxContainer);
vb->add_child(default_files_container);
@@ -2164,9 +2167,11 @@ void ProjectManager::_open_selected_projects_ask() {
return;
}
+ const Size2i popup_min_width = Size2i(600.0 * EDSCALE, 0);
+
if (selected_list.size() > 1) {
- multi_open_ask->set_text(TTR("Are you sure to open more than one project?"));
- multi_open_ask->popup_centered();
+ multi_open_ask->set_text(vformat(TTR("You requested to open %d projects in parallel. Do you confirm?\nNote that usual checks for engine version compatibility will be bypassed."), selected_list.size()));
+ multi_open_ask->popup_centered(popup_min_width);
return;
}
@@ -2175,8 +2180,7 @@ void ProjectManager::_open_selected_projects_ask() {
return;
}
- // Update the project settings or don't open
- const String conf = project.path.path_join("project.godot");
+ // Update the project settings or don't open.
const int config_version = project.version;
PackedStringArray unsupported_features = project.unsupported_features;
@@ -2186,26 +2190,30 @@ void ProjectManager::_open_selected_projects_ask() {
ask_update_settings->get_ok_button()->set_text("OK");
- // Check if the config_version property was empty or 0
+ // Check if the config_version property was empty or 0.
if (config_version == 0) {
- ask_update_settings->set_text(vformat(TTR("The following project settings file does not specify the version of Godot through which it was created.\n\n%s\n\nIf you proceed with opening it, it will be converted to Godot's current configuration file format.\nWarning: You won't be able to open the project with previous versions of the engine anymore."), conf));
- ask_update_settings->popup_centered();
+ ask_update_settings->set_text(vformat(TTR("The selected project \"%s\" does not specify its supported Godot version in its configuration file (\"project.godot\").\n\nProject path: %s\n\nIf you proceed with opening it, it will be converted to Godot's current configuration file format.\n\nWarning: You won't be able to open the project with previous versions of the engine anymore."), project.project_name, project.path));
+ ask_update_settings->popup_centered(popup_min_width);
return;
}
- // Check if we need to convert project settings from an earlier engine version
+ // Check if we need to convert project settings from an earlier engine version.
if (config_version < ProjectSettings::CONFIG_VERSION) {
if (config_version == GODOT4_CONFIG_VERSION - 1 && ProjectSettings::CONFIG_VERSION == GODOT4_CONFIG_VERSION) { // Conversion from Godot 3 to 4.
full_convert_button->show();
+ ask_update_settings->set_text(vformat(TTR("The selected project \"%s\" was generated by Godot 3.x, and needs to be converted for Godot 4.x.\n\nProject path: %s\n\nYou have three options:\n- Convert only the configuration file (\"project.godot\"). Use this to open the project without attempting to convert its scenes, resources and scripts.\n- Convert the entire project including its scenes, resources and scripts (recommended if you are upgrading).\n- Do nothing and go back.\n\nWarning: If you select a conversion option, you won't be able to open the project with previous versions of the engine anymore."), project.project_name, project.path));
+ ask_update_settings->get_ok_button()->set_text(TTR("Convert project.godot Only"));
+ } else {
+ ask_update_settings->set_text(vformat(TTR("The selected project \"%s\" was generated by an older engine version, and needs to be converted for this version.\n\nProject path: %s\n\nDo you want to convert it?\n\nWarning: You won't be able to open the project with previous versions of the engine anymore."), project.project_name, project.path));
+ ask_update_settings->get_ok_button()->set_text(TTR("Convert project.godot"));
}
- ask_update_settings->set_text(vformat(TTR("The following project settings file was generated by an older engine version, and needs to be converted for this version:\n\n%s\n\nDo you want to convert it? You can also convert the entire project (recommended if you are upgrading).\nWarning: You won't be able to open the project with previous versions of the engine anymore."), conf));
- ask_update_settings->get_ok_button()->set_text(TTR("Convert project.godot"));
- ask_update_settings->popup_centered();
+ ask_update_settings->popup_centered(popup_min_width);
+ ask_update_settings->get_cancel_button()->grab_focus(); // To prevent accidents.
return;
}
- // Check if the file was generated by a newer, incompatible engine version
+ // Check if the file was generated by a newer, incompatible engine version.
if (config_version > ProjectSettings::CONFIG_VERSION) {
- dialog_error->set_text(vformat(TTR("Can't open project at '%s'.") + "\n" + TTR("The project settings were created by a newer engine version, whose settings are not compatible with this version."), project.path));
- dialog_error->popup_centered();
+ dialog_error->set_text(vformat(TTR("Can't open project \"%s\" at the following path:\n\n%s\n\nThe project settings were created by a newer engine version, whose settings are not compatible with this version."), project.project_name, project.path));
+ dialog_error->popup_centered(popup_min_width);
return;
}
// Check if the project is using features not supported by this build of Godot.
@@ -2234,14 +2242,20 @@ void ProjectManager::_open_selected_projects_ask() {
warning_message += TTR("Open anyway? Project will be modified.");
ask_update_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
ask_update_settings->set_text(warning_message);
- ask_update_settings->popup_centered();
+ ask_update_settings->popup_centered(popup_min_width);
return;
}
- // Open if the project is up-to-date
+ // Open if the project is up-to-date.
_open_selected_projects();
}
+void ProjectManager::_full_convert_button_pressed() {
+ ask_update_settings->hide();
+ ask_full_convert_dialog->popup_centered(Size2i(600.0 * EDSCALE, 0));
+ ask_full_convert_dialog->get_cancel_button()->grab_focus();
+}
+
void ProjectManager::_perform_full_project_conversion() {
Vector<ProjectList::Item> selected_list = _project_list->get_selected_projects();
if (selected_list.is_empty()) {
@@ -2869,21 +2883,18 @@ ProjectManager::ProjectManager() {
add_child(multi_scan_ask);
ask_update_settings = memnew(ConfirmationDialog);
+ ask_update_settings->set_autowrap(true);
ask_update_settings->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_confirm_update_settings));
- full_convert_button = ask_update_settings->add_button("Perform Full Project Conversion", false);
+ full_convert_button = ask_update_settings->add_button("Convert Full Project", !GLOBAL_GET("gui/common/swap_cancel_ok"));
+ full_convert_button->connect("pressed", callable_mp(this, &ProjectManager::_full_convert_button_pressed));
add_child(ask_update_settings);
ask_full_convert_dialog = memnew(ConfirmationDialog);
ask_full_convert_dialog->set_autowrap(true);
- ask_full_convert_dialog->set_text(TTR(R"(This option will perform full project conversion, updating scenes and scripts from Godot 3.x to work in Godot 4.0. Note that this is a best-effort conversion, i.e. it makes upgrading the project easier, but it will not open out-of-the-box and will still require manual adjustments.
-
-IMPORTANT: Make sure to backup your project before converting, as this operation makes it impossible to open in older versions of Godot.)"));
+ ask_full_convert_dialog->set_text(TTR("This option will perform full project conversion, updating scenes, resources and scripts from Godot 3.x to work in Godot 4.0.\n\nNote that this is a best-effort conversion, i.e. it makes upgrading the project easier, but it will not open out-of-the-box and will still require manual adjustments.\n\nIMPORTANT: Make sure to backup your project before converting, as this operation makes it impossible to open it in older versions of Godot."));
ask_full_convert_dialog->connect("confirmed", callable_mp(this, &ProjectManager::_perform_full_project_conversion));
add_child(ask_full_convert_dialog);
- full_convert_button->connect("pressed", callable_mp((Window *)ask_update_settings, &ConfirmationDialog::hide));
- full_convert_button->connect("pressed", callable_mp((Window *)ask_full_convert_dialog, &ConfirmationDialog::popup_centered_ratio).bind(0.2));
-
npdialog = memnew(ProjectDialog);
npdialog->connect("projects_updated", callable_mp(this, &ProjectManager::_on_projects_updated));
npdialog->connect("project_created", callable_mp(this, &ProjectManager::_on_project_created));
diff --git a/editor/project_manager.h b/editor/project_manager.h
index 0831a63e68..7c05429dde 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -108,6 +108,7 @@ class ProjectManager : public Control {
void _run_project_confirm();
void _open_selected_projects();
void _open_selected_projects_ask();
+ void _full_convert_button_pressed();
void _perform_full_project_conversion();
void _import_project();
void _new_project();
diff --git a/editor/scene_create_dialog.cpp b/editor/scene_create_dialog.cpp
index 573e57ca04..4563dbb0f7 100644
--- a/editor/scene_create_dialog.cpp
+++ b/editor/scene_create_dialog.cpp
@@ -133,7 +133,7 @@ void SceneCreateDialog::update_dialog() {
root_name = scene_name.get_file().get_basename();
}
- if (!root_name.is_valid_identifier()) {
+ if (root_name.is_empty() || root_name.validate_node_name().size() != root_name.size()) {
update_error(node_error_label, MSG_ERROR, TTR("Invalid root node name."));
is_valid = false;
}
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index a437245c57..d1dc188be9 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -135,6 +135,8 @@ void SceneTreeDock::shortcut_input(const Ref<InputEvent> &p_event) {
_tool_selected(TOOL_ERASE, true);
} else if (ED_IS_SHORTCUT("scene_tree/copy_node_path", p_event)) {
_tool_selected(TOOL_COPY_NODE_PATH);
+ } else if (ED_IS_SHORTCUT("scene_tree/toggle_unique_name", p_event)) {
+ _tool_selected(TOOL_TOGGLE_SCENE_UNIQUE_NAME);
} else if (ED_IS_SHORTCUT("scene_tree/delete", p_event)) {
_tool_selected(TOOL_ERASE);
} else {
@@ -439,8 +441,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
}
- bool collapsed = _is_collapsed_recursive(selected_item);
- _set_collapsed_recursive(selected_item, !collapsed);
+ bool collapsed = selected_item->is_any_collapsed();
+ selected_item->set_collapsed_recursive(!collapsed);
tree->ensure_cursor_is_visible();
@@ -916,6 +918,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
String existing;
if (extensions.size()) {
String root_name(tocopy->get_name());
+ root_name = EditorNode::adjust_scene_name_casing(root_name);
existing = root_name + "." + extensions.front()->get().to_lower();
}
new_scene_from_dialog->set_current_path(existing);
@@ -1073,6 +1076,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (first_selected == nullptr) {
return;
}
+ if (first_selected->get() == EditorNode::get_singleton()->get_edited_scene()) {
+ // Exclude Root Node. It should never be unique name in its own scene!
+ editor_selection->remove_node(first_selected->get());
+ first_selected = editor_selection->get_selected_node_list().front();
+ if (first_selected == nullptr) {
+ return;
+ }
+ }
bool enabling = !first_selected->get()->is_unique_name_in_owner();
List<Node *> full_selection = editor_selection->get_full_selected_node_list();
@@ -1212,17 +1223,6 @@ void SceneTreeDock::add_root_node(Node *p_node) {
editor_data->get_undo_redo()->commit_action();
}
-void SceneTreeDock::_node_collapsed(Object *p_obj) {
- TreeItem *ti = Object::cast_to<TreeItem>(p_obj);
- if (!ti) {
- return;
- }
-
- if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
- _set_collapsed_recursive(ti, ti->is_collapsed());
- }
-}
-
void SceneTreeDock::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
@@ -1235,14 +1235,14 @@ void SceneTreeDock::_notification(int p_what) {
CanvasItemEditorPlugin *canvas_item_plugin = Object::cast_to<CanvasItemEditorPlugin>(editor_data->get_editor("2D"));
if (canvas_item_plugin) {
- canvas_item_plugin->get_canvas_item_editor()->connect("item_lock_status_changed", Callable(scene_tree, "_update_tree"));
- canvas_item_plugin->get_canvas_item_editor()->connect("item_group_status_changed", Callable(scene_tree, "_update_tree"));
+ canvas_item_plugin->get_canvas_item_editor()->connect("item_lock_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree));
+ canvas_item_plugin->get_canvas_item_editor()->connect("item_group_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree));
scene_tree->connect("node_changed", callable_mp((CanvasItem *)canvas_item_plugin->get_canvas_item_editor()->get_viewport_control(), &CanvasItem::queue_redraw));
}
Node3DEditorPlugin *spatial_editor_plugin = Object::cast_to<Node3DEditorPlugin>(editor_data->get_editor("3D"));
- spatial_editor_plugin->get_spatial_editor()->connect("item_lock_status_changed", Callable(scene_tree, "_update_tree"));
- spatial_editor_plugin->get_spatial_editor()->connect("item_group_status_changed", Callable(scene_tree, "_update_tree"));
+ spatial_editor_plugin->get_spatial_editor()->connect("item_lock_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree));
+ spatial_editor_plugin->get_spatial_editor()->connect("item_group_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree));
button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
button_instance->set_icon(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")));
@@ -1934,48 +1934,6 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
editor_data->get_undo_redo()->commit_action();
}
-bool SceneTreeDock::_is_collapsed_recursive(TreeItem *p_item) const {
- bool is_branch_collapsed = false;
-
- List<TreeItem *> needs_check;
- needs_check.push_back(p_item);
-
- while (!needs_check.is_empty()) {
- TreeItem *item = needs_check.back()->get();
- needs_check.pop_back();
-
- TreeItem *child = item->get_first_child();
- is_branch_collapsed = item->is_collapsed() && child;
-
- if (is_branch_collapsed) {
- break;
- }
- while (child) {
- needs_check.push_back(child);
- child = child->get_next();
- }
- }
- return is_branch_collapsed;
-}
-
-void SceneTreeDock::_set_collapsed_recursive(TreeItem *p_item, bool p_collapsed) {
- List<TreeItem *> to_collapse;
- to_collapse.push_back(p_item);
-
- while (!to_collapse.is_empty()) {
- TreeItem *item = to_collapse.back()->get();
- to_collapse.pop_back();
-
- item->set_collapsed(p_collapsed);
-
- TreeItem *child = item->get_first_child();
- while (child) {
- to_collapse.push_back(child);
- child = child->get_next();
- }
- }
-}
-
void SceneTreeDock::_script_created(Ref<Script> p_script) {
List<Node *> selected = editor_selection->get_selected_node_list();
@@ -2865,10 +2823,13 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
}
}
if (all_owned) {
- menu->add_separator();
- menu->add_icon_check_item(get_theme_icon(SNAME("SceneUniqueName"), SNAME("EditorIcons")), TTR("Access as Scene Unique Name"), TOOL_TOGGLE_SCENE_UNIQUE_NAME);
- // Checked based on `selection[0]` because `full_selection` has undesired ordering.
- menu->set_item_checked(menu->get_item_index(TOOL_TOGGLE_SCENE_UNIQUE_NAME), selection[0]->is_unique_name_in_owner());
+ // Group "toggle_unique_name" with "copy_node_path", if it is available.
+ if (menu->get_item_index(TOOL_COPY_NODE_PATH) == -1) {
+ menu->add_separator();
+ }
+ Node *node = full_selection[0];
+ menu->add_icon_shortcut(get_theme_icon(SNAME("SceneUniqueName"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/toggle_unique_name"), TOOL_TOGGLE_SCENE_UNIQUE_NAME);
+ menu->set_item_text(menu->get_item_index(TOOL_TOGGLE_SCENE_UNIQUE_NAME), node->is_unique_name_in_owner() ? TTR("Revoke Unique Name") : TTR("Access as Unique Name"));
}
}
@@ -3421,6 +3382,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
ED_SHORTCUT("scene_tree/make_root", TTR("Make Scene Root"));
ED_SHORTCUT("scene_tree/save_branch_as_scene", TTR("Save Branch as Scene"));
ED_SHORTCUT("scene_tree/copy_node_path", TTR("Copy Node Path"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::C);
+ ED_SHORTCUT("scene_tree/toggle_unique_name", TTR("Toggle Access as Unique Name"));
ED_SHORTCUT("scene_tree/delete_no_confirm", TTR("Delete (No Confirm)"), KeyModifierMask::SHIFT | Key::KEY_DELETE);
ED_SHORTCUT("scene_tree/delete", TTR("Delete"), Key::KEY_DELETE);
@@ -3517,7 +3479,6 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
scene_tree->connect("nodes_dragged", callable_mp(this, &SceneTreeDock::_nodes_drag_begin));
scene_tree->get_scene_tree()->connect("item_double_clicked", callable_mp(this, &SceneTreeDock::_focus_node));
- scene_tree->get_scene_tree()->connect("item_collapsed", callable_mp(this, &SceneTreeDock::_node_collapsed));
editor_selection->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed));
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index dc228e1c93..e48b518252 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -137,7 +137,6 @@ class SceneTreeDock : public VBoxContainer {
HBoxContainer *tool_hbc = nullptr;
void _tool_selected(int p_tool, bool p_confirm_override = false);
void _property_selected(int p_idx);
- void _node_collapsed(Object *p_obj);
Node *property_drop_node = nullptr;
String resource_drop_path;
@@ -188,9 +187,6 @@ class SceneTreeDock : public VBoxContainer {
void _node_reparent(NodePath p_path, bool p_keep_global_xform);
void _do_reparent(Node *p_new_parent, int p_position_in_parent, Vector<Node *> p_nodes, bool p_keep_global_xform);
- bool _is_collapsed_recursive(TreeItem *p_item) const;
- void _set_collapsed_recursive(TreeItem *p_item, bool p_collapsed);
-
void _set_owners(Node *p_owner, const Array &p_nodes);
enum ReplaceOwnerMode {
@@ -228,8 +224,6 @@ class SceneTreeDock : public VBoxContainer {
virtual void input(const Ref<InputEvent> &p_event) override;
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
- void _import_subscene();
-
void _new_scene_from(String p_file);
void _set_node_owner_recursive(Node *p_node, Node *p_owner);
@@ -292,7 +286,6 @@ public:
void _focus_node();
- void import_subscene();
void add_root_node(Node *p_node);
void set_edited_scene(Node *p_scene);
void instantiate(const String &p_file);
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index 137574640e..0b1e9719b7 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -30,6 +30,7 @@
#include "scene_tree_editor.h"
+#include "core/config/project_settings.h"
#include "core/object/message_queue.h"
#include "core/string/print_string.h"
#include "editor/editor_file_system.h"
@@ -835,7 +836,7 @@ void SceneTreeEditor::_notification(int p_what) {
get_tree()->connect("tree_process_mode_changed", callable_mp(this, &SceneTreeEditor::_tree_process_mode_changed));
get_tree()->connect("node_removed", callable_mp(this, &SceneTreeEditor::_node_removed));
get_tree()->connect("node_renamed", callable_mp(this, &SceneTreeEditor::_node_renamed));
- get_tree()->connect("node_configuration_warning_changed", callable_mp(this, &SceneTreeEditor::_warning_changed), CONNECT_DEFERRED);
+ get_tree()->connect("node_configuration_warning_changed", callable_mp(this, &SceneTreeEditor::_warning_changed));
tree->connect("item_collapsed", callable_mp(this, &SceneTreeEditor::_cell_collapsed));
@@ -942,14 +943,16 @@ void SceneTreeEditor::_renamed() {
Node *n = get_node(np);
ERR_FAIL_COND(!n);
- // Empty node names are not allowed, so resets it to previous text and show warning
- if (which->get_text(0).strip_edges().is_empty()) {
- which->set_text(0, n->get_name());
- EditorNode::get_singleton()->show_warning(TTR("No name provided."));
- return;
+ String raw_new_name = which->get_text(0);
+ if (raw_new_name.strip_edges().is_empty()) {
+ // If name is empty, fallback to class name.
+ if (GLOBAL_GET("editor/node_naming/name_casing").operator int() != NAME_CASING_PASCAL_CASE) {
+ raw_new_name = Node::adjust_name_casing(n->get_class());
+ } else {
+ raw_new_name = n->get_class();
+ }
}
- String raw_new_name = which->get_text(0);
String new_name = raw_new_name.validate_node_name();
if (new_name != raw_new_name) {
@@ -1332,7 +1335,7 @@ void SceneTreeEditor::set_connecting_signal(bool p_enable) {
}
void SceneTreeEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_update_tree"), &SceneTreeEditor::_update_tree, DEFVAL(false)); // Still used by some connect_compat.
+ ClassDB::bind_method(D_METHOD("_update_tree"), &SceneTreeEditor::_update_tree, DEFVAL(false)); // Still used by UndoRedo.
ClassDB::bind_method("_rename_node", &SceneTreeEditor::_rename_node);
ClassDB::bind_method("_test_update_tree", &SceneTreeEditor::_test_update_tree);
diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h
index 28ffa4b11b..8fbc3ab6d6 100644
--- a/editor/scene_tree_editor.h
+++ b/editor/scene_tree_editor.h
@@ -76,7 +76,6 @@ class SceneTreeEditor : public Control {
void _add_nodes(Node *p_node, TreeItem *p_parent);
void _test_update_tree();
- void _update_tree(bool p_scroll_to_selected = false);
bool _update_filter(TreeItem *p_parent = nullptr, bool p_scroll_to_selected = false);
bool _item_matches_all_terms(TreeItem *p_item, PackedStringArray p_terms);
void _tree_changed();
@@ -138,6 +137,9 @@ class SceneTreeEditor : public Control {
Vector<StringName> valid_types;
public:
+ // Public for use with callable_mp.
+ void _update_tree(bool p_scroll_to_selected = false);
+
void set_filter(const String &p_filter);
String get_filter() const;
diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp
index eef0f3eae1..473bbd69d9 100644
--- a/editor/shader_globals_editor.cpp
+++ b/editor/shader_globals_editor.cpp
@@ -483,7 +483,7 @@ ShaderGlobalsEditor::ShaderGlobalsEditor() {
inspector->connect("property_deleted", callable_mp(this, &ShaderGlobalsEditor::_variable_deleted), CONNECT_DEFERRED);
interface = memnew(ShaderGlobalsEditorInterface);
- interface->connect("var_changed", Callable(this, "_changed"));
+ interface->connect("var_changed", callable_mp(this, &ShaderGlobalsEditor::_changed));
}
ShaderGlobalsEditor::~ShaderGlobalsEditor() {