summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/doc_tools.cpp21
-rw-r--r--editor/editor_help.cpp64
-rw-r--r--editor/editor_help.h12
-rw-r--r--editor/editor_locale_dialog.cpp563
-rw-r--r--editor/editor_locale_dialog.h93
-rw-r--r--editor/editor_node.cpp37
-rw-r--r--editor/editor_node.h8
-rw-r--r--editor/editor_plugin.cpp30
-rw-r--r--editor/editor_properties.cpp62
-rw-r--r--editor/editor_properties.h21
-rw-r--r--editor/editor_run.cpp18
-rw-r--r--editor/editor_settings.cpp16
-rw-r--r--editor/editor_themes.cpp26
-rw-r--r--editor/editor_toaster.cpp8
-rw-r--r--editor/editor_toaster.h1
-rw-r--r--editor/icons/HFlowContainer.svg1
-rw-r--r--editor/icons/Notification.svg2
-rw-r--r--editor/icons/NotificationDisabled.svg2
-rw-r--r--editor/icons/VFlowContainer.svg1
-rw-r--r--editor/import/dynamicfont_import_settings.cpp425
-rw-r--r--editor/import/dynamicfont_import_settings.h7
-rw-r--r--editor/import/resource_importer_csv_translation.cpp3
-rw-r--r--editor/import/resource_importer_scene.cpp77
-rw-r--r--editor/import/resource_importer_scene.h2
-rw-r--r--editor/localization_editor.cpp251
-rw-r--r--editor/localization_editor.h17
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp74
-rw-r--r--editor/plugins/asset_library_editor_plugin.h14
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp34
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h10
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp56
-rw-r--r--editor/plugins/node_3d_editor_plugin.h13
-rw-r--r--editor/property_editor.cpp25
-rw-r--r--editor/property_editor.h3
-rw-r--r--editor/scene_tree_dock.cpp209
-rw-r--r--editor/scene_tree_dock.h3
36 files changed, 1305 insertions, 904 deletions
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index a71e16b66c..6acf654b04 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -350,7 +350,7 @@ void DocTools::generate(bool p_basic_types) {
List<PropertyInfo> properties;
List<PropertyInfo> own_properties;
if (name == "ProjectSettings") {
- //special case for project settings, so settings can be documented
+ // Special case for project settings, so settings can be documented.
ProjectSettings::get_singleton()->get_property_list(&properties);
own_properties = properties;
} else {
@@ -358,9 +358,12 @@ void DocTools::generate(bool p_basic_types) {
ClassDB::get_property_list(name, &own_properties, true);
}
+ properties.sort();
+ own_properties.sort();
+
List<PropertyInfo>::Element *EO = own_properties.front();
for (const PropertyInfo &E : properties) {
- bool inherited = EO == nullptr;
+ bool inherited = true;
if (EO && EO->get() == E) {
inherited = false;
EO = EO->next();
@@ -410,7 +413,7 @@ void DocTools::generate(bool p_basic_types) {
//used to track uninitialized values using valgrind
//print_line("getting default value for " + String(name) + "." + String(E.name));
if (default_value_valid && default_value.get_type() != Variant::OBJECT) {
- prop.default_value = default_value.get_construct_string().replace("\n", "");
+ prop.default_value = default_value.get_construct_string().replace("\n", " ");
}
StringName setter = ClassDB::get_property_setter(name, E.name);
@@ -522,7 +525,7 @@ void DocTools::generate(bool p_basic_types) {
int darg_idx = i - (E.arguments.size() - E.default_arguments.size());
if (darg_idx >= 0) {
Variant default_arg = E.default_arguments[darg_idx];
- argument.default_value = default_arg.get_construct_string();
+ argument.default_value = default_arg.get_construct_string().replace("\n", " ");
}
method.arguments.push_back(argument);
@@ -585,7 +588,7 @@ void DocTools::generate(bool p_basic_types) {
tid.name = E;
tid.type = "Color";
tid.data_type = "color";
- tid.default_value = Variant(Theme::get_default()->get_color(E, cname)).get_construct_string();
+ tid.default_value = Variant(Theme::get_default()->get_color(E, cname)).get_construct_string().replace("\n", " ");
c.theme_properties.push_back(tid);
}
@@ -757,7 +760,7 @@ void DocTools::generate(bool p_basic_types) {
int darg_idx = mi.default_arguments.size() - mi.arguments.size() + j;
if (darg_idx >= 0) {
Variant default_arg = mi.default_arguments[darg_idx];
- ad.default_value = default_arg.get_construct_string();
+ ad.default_value = default_arg.get_construct_string().replace("\n", " ");
}
method.arguments.push_back(ad);
@@ -801,7 +804,7 @@ void DocTools::generate(bool p_basic_types) {
DocData::PropertyDoc property;
property.name = pi.name;
property.type = Variant::get_type_name(pi.type);
- property.default_value = v.get(pi.name).get_construct_string();
+ property.default_value = v.get(pi.name).get_construct_string().replace("\n", " ");
c.properties.push_back(property);
}
@@ -813,7 +816,7 @@ void DocTools::generate(bool p_basic_types) {
DocData::ConstantDoc constant;
constant.name = E;
Variant value = Variant::get_constant_value(Variant::Type(i), E);
- constant.value = value.get_type() == Variant::INT ? itos(value) : value.get_construct_string();
+ constant.value = value.get_type() == Variant::INT ? itos(value) : value.get_construct_string().replace("\n", " ");
constant.is_value_valid = true;
c.constants.push_back(constant);
}
@@ -930,7 +933,7 @@ void DocTools::generate(bool p_basic_types) {
int darg_idx = j - (mi.arguments.size() - mi.default_arguments.size());
if (darg_idx >= 0) {
Variant default_arg = mi.default_arguments[darg_idx];
- ad.default_value = default_arg.get_construct_string();
+ ad.default_value = default_arg.get_construct_string().replace("\n", " ");
}
md.arguments.push_back(ad);
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 06e3a63f4a..28cf2ee75f 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -44,18 +44,25 @@
DocTools *EditorHelp::doc = nullptr;
-void EditorHelp::_init_colors() {
- title_color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
- text_color = get_theme_color(SNAME("default_color"), SNAME("RichTextLabel"));
- headline_color = get_theme_color(SNAME("headline_color"), SNAME("EditorHelp"));
- base_type_color = title_color.lerp(text_color, 0.5);
- comment_color = text_color * Color(1, 1, 1, 0.6);
- symbol_color = comment_color;
- value_color = text_color * Color(1, 1, 1, 0.6);
- qualifier_color = text_color * Color(1, 1, 1, 0.8);
- type_color = get_theme_color(SNAME("accent_color"), SNAME("Editor")).lerp(text_color, 0.5);
- class_desc->add_theme_color_override("selection_color", get_theme_color(SNAME("accent_color"), SNAME("Editor")) * Color(1, 1, 1, 0.4));
- class_desc->add_theme_constant_override("line_separation", Math::round(5 * EDSCALE));
+void EditorHelp::_update_theme() {
+ text_color = get_theme_color("text_color", "EditorHelp");
+ title_color = get_theme_color("title_color", "EditorHelp");
+ headline_color = get_theme_color("headline_color", "EditorHelp");
+ comment_color = get_theme_color("comment_color", "EditorHelp");
+ symbol_color = get_theme_color("symbol_color", "EditorHelp");
+ value_color = get_theme_color("value_color", "EditorHelp");
+ qualifier_color = get_theme_color("qualifier_color", "EditorHelp");
+ type_color = get_theme_color("type_color", "EditorHelp");
+
+ class_desc->add_theme_color_override("selection_color", get_theme_color("selection_color", "EditorHelp"));
+ class_desc->add_theme_constant_override("line_separation", get_theme_constant("line_separation", "EditorHelp"));
+ class_desc->add_theme_constant_override("table_hseparation", get_theme_constant("table_hseparation", "EditorHelp"));
+ class_desc->add_theme_constant_override("table_vseparation", get_theme_constant("table_vseparation", "EditorHelp"));
+
+ doc_font = get_theme_font(SNAME("doc"), SNAME("EditorFonts"));
+ doc_bold_font = get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts"));
+ doc_title_font = get_theme_font(SNAME("doc_title"), SNAME("EditorFonts"));
+ doc_code_font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
}
void EditorHelp::_search(bool p_search_previous) {
@@ -184,8 +191,7 @@ void EditorHelp::_add_type(const String &p_type, const String &p_enum) {
t = p_enum.get_slice(".", 0);
}
}
- const Color text_color = get_theme_color(SNAME("default_color"), SNAME("RichTextLabel"));
- const Color type_color = get_theme_color(SNAME("accent_color"), SNAME("Editor")).lerp(text_color, 0.5);
+
class_desc->push_color(type_color);
bool add_array = false;
if (can_ref) {
@@ -496,16 +502,11 @@ void EditorHelp::_update_doc() {
method_line.clear();
section_line.clear();
- _init_colors();
-
- DocData::ClassDoc cd = doc->class_list[edited_class]; //make a copy, so we can sort without worrying
-
- Ref<Font> doc_font = get_theme_font(SNAME("doc"), SNAME("EditorFonts"));
- Ref<Font> doc_bold_font = get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts"));
- Ref<Font> doc_title_font = get_theme_font(SNAME("doc_title"), SNAME("EditorFonts"));
- Ref<Font> doc_code_font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
+ _update_theme();
String link_color_text = title_color.to_html(false);
+ DocData::ClassDoc cd = doc->class_list[edited_class]; // Make a copy, so we can sort without worrying.
+
// Class name
section_line.push_back(Pair<String, int>(TTR("Top"), 0));
class_desc->push_font(doc_title_font);
@@ -1476,11 +1477,9 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
Ref<Font> doc_kbd_font = p_rt->get_theme_font(SNAME("doc_keyboard"), SNAME("EditorFonts"));
Color headline_color = p_rt->get_theme_color(SNAME("headline_color"), SNAME("EditorHelp"));
- Color accent_color = p_rt->get_theme_color(SNAME("accent_color"), SNAME("Editor"));
- Color property_color = p_rt->get_theme_color(SNAME("property_color"), SNAME("Editor"));
- Color link_color = accent_color.lerp(headline_color, 0.8);
- Color code_color = accent_color.lerp(headline_color, 0.6);
- Color kbd_color = accent_color.lerp(property_color, 0.6);
+ Color link_color = p_rt->get_theme_color(SNAME("link_color"), SNAME("EditorHelp"));
+ Color code_color = p_rt->get_theme_color(SNAME("code_color"), SNAME("EditorHelp"));
+ Color kbd_color = p_rt->get_theme_color(SNAME("kbd_color"), SNAME("EditorHelp"));
String bbcode = p_bbcode.dedent().replace("\t", "").replace("\r", "").strip_edges();
@@ -1941,16 +1940,16 @@ void EditorHelpBit::_bind_methods() {
void EditorHelpBit::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ rich_text->add_theme_color_override("selection_color", get_theme_color(SNAME("selection_color"), SNAME("EditorHelp")));
+ } break;
+
case NOTIFICATION_READY: {
rich_text->clear();
_add_text_to_rt(text, rich_text);
} break;
- case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- rich_text->add_theme_color_override("selection_color", get_theme_color(SNAME("accent_color"), SNAME("Editor")) * Color(1, 1, 1, 0.4));
- } break;
- default:
- break;
}
}
@@ -1964,7 +1963,6 @@ EditorHelpBit::EditorHelpBit() {
rich_text = memnew(RichTextLabel);
add_child(rich_text);
rich_text->connect("meta_clicked", callable_mp(this, &EditorHelpBit::_meta_clicked));
- rich_text->add_theme_color_override("selection_color", get_theme_color(SNAME("accent_color"), SNAME("Editor")) * Color(1, 1, 1, 0.4));
rich_text->set_override_selected_font_color(false);
set_custom_minimum_size(Size2(0, 70 * EDSCALE));
}
diff --git a/editor/editor_help.h b/editor/editor_help.h
index eb879c6d39..377ae05a08 100644
--- a/editor/editor_help.h
+++ b/editor/editor_help.h
@@ -126,17 +126,21 @@ class EditorHelp : public VBoxContainer {
String base_path;
- Color title_color;
Color text_color;
+ Color title_color;
Color headline_color;
- Color base_type_color;
- Color type_color;
Color comment_color;
Color symbol_color;
Color value_color;
Color qualifier_color;
+ Color type_color;
+
+ Ref<Font> doc_font;
+ Ref<Font> doc_bold_font;
+ Ref<Font> doc_title_font;
+ Ref<Font> doc_code_font;
- void _init_colors();
+ void _update_theme();
void _help_callback(const String &p_topic);
void _add_text(const String &p_bbcode);
diff --git a/editor/editor_locale_dialog.cpp b/editor/editor_locale_dialog.cpp
new file mode 100644
index 0000000000..5c4ece7065
--- /dev/null
+++ b/editor/editor_locale_dialog.cpp
@@ -0,0 +1,563 @@
+/*************************************************************************/
+/* editor_locale_dialog.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor_locale_dialog.h"
+
+#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+#include "scene/gui/check_button.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/tree.h"
+
+static _FORCE_INLINE_ bool is_upper_case(char32_t c) {
+ return (c >= 'A' && c <= 'Z');
+}
+
+static _FORCE_INLINE_ bool is_lower_case(char32_t c) {
+ return (c >= 'a' && c <= 'z');
+}
+
+void EditorLocaleDialog::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("locale_selected", PropertyInfo(Variant::STRING, "locale")));
+}
+
+void EditorLocaleDialog::ok_pressed() {
+ if (edit_filters->is_pressed()) {
+ return; // Do not update, if in filter edit mode.
+ }
+
+ String locale;
+ if (lang_code->get_text().is_empty()) {
+ return; // Language code is required.
+ }
+ locale = lang_code->get_text();
+
+ if (!script_code->get_text().is_empty()) {
+ locale += "_" + script_code->get_text();
+ }
+ if (!country_code->get_text().is_empty()) {
+ locale += "_" + country_code->get_text();
+ }
+ if (!variant_code->get_text().is_empty()) {
+ locale += "_" + variant_code->get_text();
+ }
+
+ emit_signal(SNAME("locale_selected"), TranslationServer::get_singleton()->standardize_locale(locale));
+ hide();
+}
+
+void EditorLocaleDialog::_item_selected() {
+ if (updating_lists) {
+ return;
+ }
+
+ if (edit_filters->is_pressed()) {
+ return; // Do not update, if in filter edit mode.
+ }
+
+ TreeItem *l = lang_list->get_selected();
+ if (l) {
+ lang_code->set_text(l->get_metadata(0).operator String());
+ }
+
+ TreeItem *s = script_list->get_selected();
+ if (s) {
+ script_code->set_text(s->get_metadata(0).operator String());
+ }
+
+ TreeItem *c = cnt_list->get_selected();
+ if (c) {
+ country_code->set_text(c->get_metadata(0).operator String());
+ }
+}
+
+void EditorLocaleDialog::_toggle_advanced(bool p_checked) {
+ if (!p_checked) {
+ script_code->set_text("");
+ variant_code->set_text("");
+ }
+ _update_tree();
+}
+
+void EditorLocaleDialog::_post_popup() {
+ ConfirmationDialog::_post_popup();
+
+ if (!locale_set) {
+ lang_code->set_text("");
+ script_code->set_text("");
+ country_code->set_text("");
+ variant_code->set_text("");
+ }
+ edit_filters->set_pressed(false);
+ _update_tree();
+}
+
+void EditorLocaleDialog::_filter_lang_option_changed() {
+ TreeItem *t = lang_list->get_edited();
+ String lang = t->get_metadata(0);
+ bool checked = t->is_checked(0);
+
+ Variant prev;
+ Array f_lang_all;
+
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/language_filter")) {
+ f_lang_all = ProjectSettings::get_singleton()->get("internationalization/locale/language_filter");
+ prev = f_lang_all;
+ }
+
+ int l_idx = f_lang_all.find(lang);
+
+ if (checked) {
+ if (l_idx == -1) {
+ f_lang_all.append(lang);
+ }
+ } else {
+ if (l_idx != -1) {
+ f_lang_all.remove_at(l_idx);
+ }
+ }
+
+ f_lang_all.sort();
+
+ undo_redo->create_action(TTR("Changed Locale Language Filter"));
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/language_filter", f_lang_all);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/language_filter", prev);
+ undo_redo->commit_action();
+}
+
+void EditorLocaleDialog::_filter_script_option_changed() {
+ TreeItem *t = script_list->get_edited();
+ String script = t->get_metadata(0);
+ bool checked = t->is_checked(0);
+
+ Variant prev;
+ Array f_script_all;
+
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/script_filter")) {
+ f_script_all = ProjectSettings::get_singleton()->get("internationalization/locale/script_filter");
+ prev = f_script_all;
+ }
+
+ int l_idx = f_script_all.find(script);
+
+ if (checked) {
+ if (l_idx == -1) {
+ f_script_all.append(script);
+ }
+ } else {
+ if (l_idx != -1) {
+ f_script_all.remove_at(l_idx);
+ }
+ }
+
+ f_script_all.sort();
+
+ undo_redo->create_action(TTR("Changed Locale Script Filter"));
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/script_filter", f_script_all);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/script_filter", prev);
+ undo_redo->commit_action();
+}
+
+void EditorLocaleDialog::_filter_cnt_option_changed() {
+ TreeItem *t = cnt_list->get_edited();
+ String cnt = t->get_metadata(0);
+ bool checked = t->is_checked(0);
+
+ Variant prev;
+ Array f_cnt_all;
+
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/country_filter")) {
+ f_cnt_all = ProjectSettings::get_singleton()->get("internationalization/locale/country_filter");
+ prev = f_cnt_all;
+ }
+
+ int l_idx = f_cnt_all.find(cnt);
+
+ if (checked) {
+ if (l_idx == -1) {
+ f_cnt_all.append(cnt);
+ }
+ } else {
+ if (l_idx != -1) {
+ f_cnt_all.remove_at(l_idx);
+ }
+ }
+
+ f_cnt_all.sort();
+
+ undo_redo->create_action(TTR("Changed Locale Country Filter"));
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/country_filter", f_cnt_all);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/country_filter", prev);
+ undo_redo->commit_action();
+}
+
+void EditorLocaleDialog::_filter_mode_changed(int p_mode) {
+ int f_mode = filter_mode->get_selected_id();
+ Variant prev;
+
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/locale_filter_mode")) {
+ prev = ProjectSettings::get_singleton()->get("internationalization/locale/locale_filter_mode");
+ }
+
+ undo_redo->create_action(TTR("Changed Locale Filter Mode"));
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/locale_filter_mode", f_mode);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/locale_filter_mode", prev);
+ undo_redo->commit_action();
+
+ _update_tree();
+}
+
+void EditorLocaleDialog::_edit_filters(bool p_checked) {
+ _update_tree();
+}
+
+void EditorLocaleDialog::_update_tree() {
+ updating_lists = true;
+
+ int filter = SHOW_ALL_LOCALES;
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/locale_filter_mode")) {
+ filter = ProjectSettings::get_singleton()->get("internationalization/locale/locale_filter_mode");
+ }
+ Array f_lang_all;
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/language_filter")) {
+ f_lang_all = ProjectSettings::get_singleton()->get("internationalization/locale/language_filter");
+ }
+ Array f_cnt_all;
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/country_filter")) {
+ f_cnt_all = ProjectSettings::get_singleton()->get("internationalization/locale/country_filter");
+ }
+ Array f_script_all;
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/script_filter")) {
+ f_script_all = ProjectSettings::get_singleton()->get("internationalization/locale/script_filter");
+ }
+ bool is_edit_mode = edit_filters->is_pressed();
+
+ filter_mode->select(filter);
+
+ // Hide text advanced edit and disable OK button if in filter edit mode.
+ advanced->set_visible(!is_edit_mode);
+ hb_locale->set_visible(!is_edit_mode && advanced->is_pressed());
+ vb_script_list->set_visible(advanced->is_pressed());
+ get_ok_button()->set_disabled(is_edit_mode);
+
+ // Update language list.
+ lang_list->clear();
+ TreeItem *l_root = lang_list->create_item(nullptr);
+ lang_list->set_hide_root(true);
+
+ Vector<String> languages = TranslationServer::get_singleton()->get_all_languages();
+ for (const String &E : languages) {
+ if (is_edit_mode || (filter == SHOW_ALL_LOCALES) || f_lang_all.has(E) || f_lang_all.is_empty()) {
+ const String &lang = TranslationServer::get_singleton()->get_language_name(E);
+ TreeItem *t = lang_list->create_item(l_root);
+ if (is_edit_mode) {
+ t->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ t->set_editable(0, true);
+ t->set_checked(0, f_lang_all.has(E));
+ } else if (lang_code->get_text() == E) {
+ t->select(0);
+ }
+ t->set_text(0, vformat("%s [%s]", lang, E));
+ t->set_metadata(0, E);
+ }
+ }
+
+ // Update script list.
+ script_list->clear();
+ TreeItem *s_root = script_list->create_item(nullptr);
+ script_list->set_hide_root(true);
+
+ if (!is_edit_mode) {
+ TreeItem *t = script_list->create_item(s_root);
+ t->set_text(0, "[Default]");
+ t->set_metadata(0, "");
+ }
+
+ Vector<String> scripts = TranslationServer::get_singleton()->get_all_scripts();
+ for (const String &E : scripts) {
+ if (is_edit_mode || (filter == SHOW_ALL_LOCALES) || f_script_all.has(E) || f_script_all.is_empty()) {
+ const String &script = TranslationServer::get_singleton()->get_script_name(E);
+ TreeItem *t = script_list->create_item(s_root);
+ if (is_edit_mode) {
+ t->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ t->set_editable(0, true);
+ t->set_checked(0, f_script_all.has(E));
+ } else if (script_code->get_text() == E) {
+ t->select(0);
+ }
+ t->set_text(0, vformat("%s [%s]", script, E));
+ t->set_metadata(0, E);
+ }
+ }
+
+ // Update country list.
+ cnt_list->clear();
+ TreeItem *c_root = cnt_list->create_item(nullptr);
+ cnt_list->set_hide_root(true);
+
+ if (!is_edit_mode) {
+ TreeItem *t = cnt_list->create_item(c_root);
+ t->set_text(0, "[Default]");
+ t->set_metadata(0, "");
+ }
+
+ Vector<String> countries = TranslationServer::get_singleton()->get_all_countries();
+ for (const String &E : countries) {
+ if (is_edit_mode || (filter == SHOW_ALL_LOCALES) || f_cnt_all.has(E) || f_cnt_all.is_empty()) {
+ const String &cnt = TranslationServer::get_singleton()->get_country_name(E);
+ TreeItem *t = cnt_list->create_item(c_root);
+ if (is_edit_mode) {
+ t->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ t->set_editable(0, true);
+ t->set_checked(0, f_cnt_all.has(E));
+ } else if (country_code->get_text() == E) {
+ t->select(0);
+ }
+ t->set_text(0, vformat("%s [%s]", cnt, E));
+ t->set_metadata(0, E);
+ }
+ }
+ updating_lists = false;
+}
+
+void EditorLocaleDialog::set_locale(const String &p_locale) {
+ const String &locale = TranslationServer::get_singleton()->standardize_locale(p_locale);
+ if (locale.is_empty()) {
+ locale_set = false;
+
+ lang_code->set_text("");
+ script_code->set_text("");
+ country_code->set_text("");
+ variant_code->set_text("");
+ } else {
+ locale_set = true;
+
+ Vector<String> locale_elements = p_locale.split("_");
+ lang_code->set_text(locale_elements[0]);
+ if (locale_elements.size() >= 2) {
+ if (locale_elements[1].length() == 4 && is_upper_case(locale_elements[1][0]) && is_lower_case(locale_elements[1][1]) && is_lower_case(locale_elements[1][2]) && is_lower_case(locale_elements[1][3])) {
+ script_code->set_text(locale_elements[1]);
+ advanced->set_pressed(true);
+ }
+ if (locale_elements[1].length() == 2 && is_upper_case(locale_elements[1][0]) && is_upper_case(locale_elements[1][1])) {
+ country_code->set_text(locale_elements[1]);
+ }
+ }
+ if (locale_elements.size() >= 3) {
+ if (locale_elements[2].length() == 2 && is_upper_case(locale_elements[2][0]) && is_upper_case(locale_elements[2][1])) {
+ country_code->set_text(locale_elements[2]);
+ } else {
+ variant_code->set_text(locale_elements[2].to_lower());
+ advanced->set_pressed(true);
+ }
+ }
+ if (locale_elements.size() >= 4) {
+ variant_code->set_text(locale_elements[3].to_lower());
+ advanced->set_pressed(true);
+ }
+ }
+}
+
+void EditorLocaleDialog::popup_locale_dialog() {
+ popup_centered_clamped(Size2(1050, 700) * EDSCALE, 0.8);
+}
+
+EditorLocaleDialog::EditorLocaleDialog() {
+ undo_redo = EditorNode::get_undo_redo();
+
+ set_title(TTR("Select a Locale"));
+
+ VBoxContainer *vb = memnew(VBoxContainer);
+ {
+ HBoxContainer *hb_filter = memnew(HBoxContainer);
+ {
+ filter_mode = memnew(OptionButton);
+ filter_mode->add_item(TTR("Show All Locales"), SHOW_ALL_LOCALES);
+ filter_mode->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ filter_mode->add_item(TTR("Show Selected Locales Only"), SHOW_ONLY_SELECTED_LOCALES);
+ filter_mode->select(0);
+ filter_mode->connect("item_selected", callable_mp(this, &EditorLocaleDialog::_filter_mode_changed));
+ hb_filter->add_child(filter_mode);
+ }
+ {
+ edit_filters = memnew(CheckButton);
+ edit_filters->set_text("Edit Filters");
+ edit_filters->set_toggle_mode(true);
+ edit_filters->set_pressed(false);
+ edit_filters->connect("toggled", callable_mp(this, &EditorLocaleDialog::_edit_filters));
+ hb_filter->add_child(edit_filters);
+ }
+ {
+ advanced = memnew(CheckButton);
+ advanced->set_text("Advanced");
+ advanced->set_toggle_mode(true);
+ advanced->set_pressed(false);
+ advanced->connect("toggled", callable_mp(this, &EditorLocaleDialog::_toggle_advanced));
+ hb_filter->add_child(advanced);
+ }
+ vb->add_child(hb_filter);
+ }
+ {
+ HBoxContainer *hb_lists = memnew(HBoxContainer);
+ hb_lists->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ {
+ VBoxContainer *vb_lang_list = memnew(VBoxContainer);
+ vb_lang_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ {
+ Label *lang_lbl = memnew(Label);
+ lang_lbl->set_text(TTR("Language:"));
+ vb_lang_list->add_child(lang_lbl);
+ }
+ {
+ lang_list = memnew(Tree);
+ lang_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ lang_list->connect("cell_selected", callable_mp(this, &EditorLocaleDialog::_item_selected));
+ lang_list->set_columns(1);
+ lang_list->connect("item_edited", callable_mp(this, &EditorLocaleDialog::_filter_lang_option_changed));
+ vb_lang_list->add_child(lang_list);
+ }
+ hb_lists->add_child(vb_lang_list);
+ }
+ {
+ vb_script_list = memnew(VBoxContainer);
+ vb_script_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ {
+ Label *script_lbl = memnew(Label);
+ script_lbl->set_text(TTR("Script:"));
+ vb_script_list->add_child(script_lbl);
+ }
+ {
+ script_list = memnew(Tree);
+ script_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ script_list->connect("cell_selected", callable_mp(this, &EditorLocaleDialog::_item_selected));
+ script_list->set_columns(1);
+ script_list->connect("item_edited", callable_mp(this, &EditorLocaleDialog::_filter_script_option_changed));
+ vb_script_list->add_child(script_list);
+ }
+ hb_lists->add_child(vb_script_list);
+ }
+ {
+ VBoxContainer *vb_cnt_list = memnew(VBoxContainer);
+ vb_cnt_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ {
+ Label *cnt_lbl = memnew(Label);
+ cnt_lbl->set_text(TTR("Country:"));
+ vb_cnt_list->add_child(cnt_lbl);
+ }
+ {
+ cnt_list = memnew(Tree);
+ cnt_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ cnt_list->connect("cell_selected", callable_mp(this, &EditorLocaleDialog::_item_selected));
+ cnt_list->set_columns(1);
+ cnt_list->connect("item_edited", callable_mp(this, &EditorLocaleDialog::_filter_cnt_option_changed));
+ vb_cnt_list->add_child(cnt_list);
+ }
+ hb_lists->add_child(vb_cnt_list);
+ }
+ vb->add_child(hb_lists);
+ }
+ {
+ hb_locale = memnew(HBoxContainer);
+ hb_locale->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ {
+ {
+ VBoxContainer *vb_language = memnew(VBoxContainer);
+ vb_language->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ {
+ Label *language_lbl = memnew(Label);
+ language_lbl->set_text(TTR("Language"));
+ vb_language->add_child(language_lbl);
+ }
+ {
+ lang_code = memnew(LineEdit);
+ lang_code->set_max_length(3);
+ lang_code->set_tooltip("Language");
+ vb_language->add_child(lang_code);
+ }
+ hb_locale->add_child(vb_language);
+ }
+ {
+ VBoxContainer *vb_script = memnew(VBoxContainer);
+ vb_script->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ {
+ Label *script_lbl = memnew(Label);
+ script_lbl->set_text(TTR("Script"));
+ vb_script->add_child(script_lbl);
+ }
+ {
+ script_code = memnew(LineEdit);
+ script_code->set_max_length(4);
+ script_code->set_tooltip("Script");
+ vb_script->add_child(script_code);
+ }
+ hb_locale->add_child(vb_script);
+ }
+ {
+ VBoxContainer *vb_country = memnew(VBoxContainer);
+ vb_country->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ {
+ Label *country_lbl = memnew(Label);
+ country_lbl->set_text(TTR("Country"));
+ vb_country->add_child(country_lbl);
+ }
+ {
+ country_code = memnew(LineEdit);
+ country_code->set_max_length(2);
+ country_code->set_tooltip("Country");
+ vb_country->add_child(country_code);
+ }
+ hb_locale->add_child(vb_country);
+ }
+ {
+ VBoxContainer *vb_variant = memnew(VBoxContainer);
+ vb_variant->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ {
+ Label *variant_lbl = memnew(Label);
+ variant_lbl->set_text(TTR("Variant"));
+ vb_variant->add_child(variant_lbl);
+ }
+ {
+ variant_code = memnew(LineEdit);
+ variant_code->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ variant_code->set_placeholder("Variant");
+ variant_code->set_tooltip("Variant");
+ vb_variant->add_child(variant_code);
+ }
+ hb_locale->add_child(vb_variant);
+ }
+ }
+ vb->add_child(hb_locale);
+ }
+ add_child(vb);
+ _update_tree();
+
+ get_ok_button()->set_text(TTR("Select"));
+}
diff --git a/editor/editor_locale_dialog.h b/editor/editor_locale_dialog.h
new file mode 100644
index 0000000000..7a4828e83a
--- /dev/null
+++ b/editor/editor_locale_dialog.h
@@ -0,0 +1,93 @@
+/*************************************************************************/
+/* editor_locale_dialog.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef EDITOR_LOCALE_DIALOG_H
+#define EDITOR_LOCALE_DIALOG_H
+
+#include "core/string/translation.h"
+#include "scene/gui/dialogs.h"
+
+class Button;
+class HBoxContainer;
+class VBoxContainer;
+class LineEdit;
+class Tree;
+class OptionButton;
+class UndoRedo;
+
+class EditorLocaleDialog : public ConfirmationDialog {
+ GDCLASS(EditorLocaleDialog, ConfirmationDialog);
+
+ enum LocaleFilter {
+ SHOW_ALL_LOCALES,
+ SHOW_ONLY_SELECTED_LOCALES,
+ };
+
+ HBoxContainer *hb_locale = nullptr;
+ VBoxContainer *vb_script_list = nullptr;
+ OptionButton *filter_mode = nullptr;
+ Button *edit_filters = nullptr;
+ Button *advanced = nullptr;
+ LineEdit *lang_code = nullptr;
+ LineEdit *script_code = nullptr;
+ LineEdit *country_code = nullptr;
+ LineEdit *variant_code = nullptr;
+ Tree *lang_list = nullptr;
+ Tree *script_list = nullptr;
+ Tree *cnt_list = nullptr;
+
+ UndoRedo *undo_redo = nullptr;
+
+ bool locale_set = false;
+ bool updating_lists = false;
+
+protected:
+ static void _bind_methods();
+ virtual void _post_popup() override;
+ virtual void ok_pressed() override;
+
+ void _item_selected();
+ void _filter_lang_option_changed();
+ void _filter_script_option_changed();
+ void _filter_cnt_option_changed();
+ void _filter_mode_changed(int p_mode);
+ void _edit_filters(bool p_checked);
+ void _toggle_advanced(bool p_checked);
+
+ void _update_tree();
+
+public:
+ EditorLocaleDialog();
+
+ void set_locale(const String &p_locale);
+ void popup_locale_dialog();
+};
+
+#endif // EDITOR_LOCALE_DIALOG_H
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 5d868777e7..cc92d391d9 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -957,9 +957,10 @@ void EditorNode::_fs_changed() {
if (!export_error.is_empty()) {
ERR_PRINT(export_error);
- OS::get_singleton()->set_exit_code(EXIT_FAILURE);
+ _exit_editor(EXIT_FAILURE);
+ } else {
+ _exit_editor(EXIT_SUCCESS);
}
- _exit_editor();
}
}
@@ -1775,7 +1776,7 @@ void EditorNode::restart_editor() {
to_reopen = get_tree()->get_edited_scene_root()->get_scene_file_path();
}
- _exit_editor();
+ _exit_editor(EXIT_SUCCESS);
List<String> args;
args.push_back("--path");
@@ -2593,13 +2594,21 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
file->set_current_path(path.replacen("." + ext, "." + extensions.front()->get()));
}
}
- } else {
- String existing;
- if (extensions.size()) {
- String root_name(scene->get_name());
- existing = root_name + "." + extensions.front()->get().to_lower();
+ } 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.capitalize().replace(" ", "");
+ } break;
+ case SCENE_NAME_CASING_SNAKE_CASE:
+ root_name = root_name.capitalize().replace(" ", "").replace("-", "_").camelcase_to_underscore();
+ break;
}
- file->set_current_path(existing);
+ file->set_current_path(root_name + "." + extensions.front()->get().to_lower());
}
file->popup_file_dialog();
file->set_title(TTR("Save Scene As..."));
@@ -2992,7 +3001,7 @@ int EditorNode::_next_unsaved_scene(bool p_valid_filename, int p_start) {
return -1;
}
-void EditorNode::_exit_editor() {
+void EditorNode::_exit_editor(int p_exit_code) {
exiting = true;
resource_preview->stop(); // stop early to avoid crashes
_save_docks();
@@ -3000,7 +3009,7 @@ void EditorNode::_exit_editor() {
// Dim the editor window while it's quitting to make it clearer that it's busy
dim_editor(true);
- get_tree()->quit();
+ get_tree()->quit(p_exit_code);
}
void EditorNode::_discard_changes(const String &p_str) {
@@ -3050,12 +3059,12 @@ void EditorNode::_discard_changes(const String &p_str) {
} break;
case FILE_QUIT: {
_menu_option_confirm(RUN_STOP, true);
- _exit_editor();
+ _exit_editor(EXIT_SUCCESS);
} break;
case RUN_PROJECT_MANAGER: {
_menu_option_confirm(RUN_STOP, true);
- _exit_editor();
+ _exit_editor(EXIT_SUCCESS);
String exec = OS::get_singleton()->get_executable_path();
List<String> args;
@@ -5673,6 +5682,8 @@ void EditorNode::_feature_profile_changed() {
}
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("_editor_select", &EditorNode::_editor_select);
ClassDB::bind_method("_node_renamed", &EditorNode::_node_renamed);
ClassDB::bind_method("edit_node", &EditorNode::edit_node);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index e315f1f4b3..ff56040297 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -216,6 +216,12 @@ private:
TOOL_MENU_BASE = 1000
};
+ enum ScriptNameCasing {
+ SCENE_NAME_CASING_AUTO,
+ SCENE_NAME_CASING_PASCAL_CASE,
+ SCENE_NAME_CASING_SNAKE_CASE
+ };
+
SubViewport *scene_root; // root of the scene being edited
PanelContainer *scene_root_parent;
@@ -529,7 +535,7 @@ private:
void _add_dropped_files_recursive(const Vector<String> &p_files, String to_path);
String _recent_scene;
- void _exit_editor();
+ void _exit_editor(int p_exit_code);
bool convert_old;
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index aeca340cb1..6579b1eb31 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -421,14 +421,10 @@ void EditorPlugin::add_control_to_container(CustomControlContainer p_location, C
} break;
case CONTAINER_SPATIAL_EDITOR_SIDE_LEFT: {
- Node3DEditor::get_singleton()->get_palette_split()->add_child(p_control);
- Node3DEditor::get_singleton()->get_palette_split()->move_child(p_control, 0);
-
+ Node3DEditor::get_singleton()->add_control_to_left_panel(p_control);
} break;
case CONTAINER_SPATIAL_EDITOR_SIDE_RIGHT: {
- Node3DEditor::get_singleton()->get_palette_split()->add_child(p_control);
- Node3DEditor::get_singleton()->get_palette_split()->move_child(p_control, 1);
-
+ Node3DEditor::get_singleton()->add_control_to_right_panel(p_control);
} break;
case CONTAINER_SPATIAL_EDITOR_BOTTOM: {
Node3DEditor::get_singleton()->get_shader_split()->add_child(p_control);
@@ -439,14 +435,10 @@ void EditorPlugin::add_control_to_container(CustomControlContainer p_location, C
} break;
case CONTAINER_CANVAS_EDITOR_SIDE_LEFT: {
- CanvasItemEditor::get_singleton()->get_palette_split()->add_child(p_control);
- CanvasItemEditor::get_singleton()->get_palette_split()->move_child(p_control, 0);
-
+ CanvasItemEditor::get_singleton()->add_control_to_left_panel(p_control);
} break;
case CONTAINER_CANVAS_EDITOR_SIDE_RIGHT: {
- CanvasItemEditor::get_singleton()->get_palette_split()->add_child(p_control);
- CanvasItemEditor::get_singleton()->get_palette_split()->move_child(p_control, 1);
-
+ CanvasItemEditor::get_singleton()->add_control_to_right_panel(p_control);
} break;
case CONTAINER_CANVAS_EDITOR_BOTTOM: {
CanvasItemEditor::get_singleton()->get_bottom_split()->add_child(p_control);
@@ -481,10 +473,11 @@ void EditorPlugin::remove_control_from_container(CustomControlContainer p_locati
Node3DEditor::get_singleton()->remove_control_from_menu_panel(p_control);
} break;
- case CONTAINER_SPATIAL_EDITOR_SIDE_LEFT:
+ case CONTAINER_SPATIAL_EDITOR_SIDE_LEFT: {
+ Node3DEditor::get_singleton()->remove_control_from_left_panel(p_control);
+ } break;
case CONTAINER_SPATIAL_EDITOR_SIDE_RIGHT: {
- Node3DEditor::get_singleton()->get_palette_split()->remove_child(p_control);
-
+ Node3DEditor::get_singleton()->remove_control_from_right_panel(p_control);
} break;
case CONTAINER_SPATIAL_EDITOR_BOTTOM: {
Node3DEditor::get_singleton()->get_shader_split()->remove_child(p_control);
@@ -494,10 +487,11 @@ void EditorPlugin::remove_control_from_container(CustomControlContainer p_locati
CanvasItemEditor::get_singleton()->remove_control_from_menu_panel(p_control);
} break;
- case CONTAINER_CANVAS_EDITOR_SIDE_LEFT:
+ case CONTAINER_CANVAS_EDITOR_SIDE_LEFT: {
+ CanvasItemEditor::get_singleton()->remove_control_from_left_panel(p_control);
+ } break;
case CONTAINER_CANVAS_EDITOR_SIDE_RIGHT: {
- CanvasItemEditor::get_singleton()->get_palette_split()->remove_child(p_control);
-
+ CanvasItemEditor::get_singleton()->remove_control_from_right_panel(p_control);
} break;
case CONTAINER_CANVAS_EDITOR_BOTTOM: {
CanvasItemEditor::get_singleton()->get_bottom_split()->remove_child(p_control);
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 97a38b9200..6bb4b5e81b 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -343,6 +343,64 @@ EditorPropertyTextEnum::EditorPropertyTextEnum() {
add_focusable(cancel_button);
}
+//////////////////// LOCALE ////////////////////////
+
+void EditorPropertyLocale::_locale_selected(const String &p_locale) {
+ emit_changed(get_edited_property(), p_locale);
+ update_property();
+}
+
+void EditorPropertyLocale::_locale_pressed() {
+ if (!dialog) {
+ dialog = memnew(EditorLocaleDialog);
+ dialog->connect("locale_selected", callable_mp(this, &EditorPropertyLocale::_locale_selected));
+ add_child(dialog);
+ }
+
+ String locale_code = get_edited_object()->get(get_edited_property());
+ dialog->set_locale(locale_code);
+ dialog->popup_locale_dialog();
+}
+
+void EditorPropertyLocale::update_property() {
+ String locale_code = get_edited_object()->get(get_edited_property());
+ locale->set_text(locale_code);
+ locale->set_tooltip(locale_code);
+}
+
+void EditorPropertyLocale::setup(const String &p_hint_text) {
+}
+
+void EditorPropertyLocale::_notification(int p_what) {
+ if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
+ locale_edit->set_icon(get_theme_icon(SNAME("Translation"), SNAME("EditorIcons")));
+ }
+}
+
+void EditorPropertyLocale::_locale_focus_exited() {
+ _locale_selected(locale->get_text());
+}
+
+void EditorPropertyLocale::_bind_methods() {
+}
+
+EditorPropertyLocale::EditorPropertyLocale() {
+ HBoxContainer *locale_hb = memnew(HBoxContainer);
+ add_child(locale_hb);
+ locale = memnew(LineEdit);
+ locale_hb->add_child(locale);
+ locale->connect("text_submitted", callable_mp(this, &EditorPropertyLocale::_locale_selected));
+ locale->connect("focus_exited", callable_mp(this, &EditorPropertyLocale::_locale_focus_exited));
+ locale->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ locale_edit = memnew(Button);
+ locale_edit->set_clip_text(true);
+ locale_hb->add_child(locale_edit);
+ add_focusable(locale);
+ dialog = nullptr;
+ locale_edit->connect("pressed", callable_mp(this, &EditorPropertyLocale::_locale_pressed));
+}
+
///////////////////// PATH /////////////////////////
void EditorPropertyPath::_set_read_only(bool p_read_only) {
@@ -3379,6 +3437,10 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
EditorPropertyClassName *editor = memnew(EditorPropertyClassName);
editor->setup("Object", p_hint_text);
return editor;
+ } else if (p_hint == PROPERTY_HINT_LOCALE_ID) {
+ EditorPropertyLocale *editor = memnew(EditorPropertyLocale);
+ editor->setup(p_hint_text);
+ return editor;
} else if (p_hint == PROPERTY_HINT_DIR || p_hint == PROPERTY_HINT_FILE || p_hint == PROPERTY_HINT_SAVE_FILE || p_hint == PROPERTY_HINT_GLOBAL_DIR || p_hint == PROPERTY_HINT_GLOBAL_FILE) {
Vector<String> extensions = p_hint_text.split(",");
bool global = p_hint == PROPERTY_HINT_GLOBAL_DIR || p_hint == PROPERTY_HINT_GLOBAL_FILE;
diff --git a/editor/editor_properties.h b/editor/editor_properties.h
index e62f6823a3..fdb0360d6b 100644
--- a/editor/editor_properties.h
+++ b/editor/editor_properties.h
@@ -33,6 +33,7 @@
#include "editor/create_dialog.h"
#include "editor/editor_inspector.h"
+#include "editor/editor_locale_dialog.h"
#include "editor/editor_resource_picker.h"
#include "editor/editor_spin_slider.h"
#include "editor/property_selector.h"
@@ -153,6 +154,26 @@ public:
EditorPropertyPath();
};
+class EditorPropertyLocale : public EditorProperty {
+ GDCLASS(EditorPropertyLocale, EditorProperty);
+ EditorLocaleDialog *dialog;
+ LineEdit *locale;
+ Button *locale_edit;
+
+ void _locale_selected(const String &p_locale);
+ void _locale_pressed();
+ void _locale_focus_exited();
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+ void setup(const String &p_hit_string);
+ virtual void update_property() override;
+ EditorPropertyLocale();
+};
+
class EditorPropertyClassName : public EditorProperty {
GDCLASS(EditorPropertyClassName, EditorProperty);
diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp
index 3c1799d80c..574abf85ea 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -98,15 +98,15 @@ Error EditorRun::run(const String &p_scene) {
screen_rect.position = DisplayServer::get_singleton()->screen_get_position(screen);
screen_rect.size = DisplayServer::get_singleton()->screen_get_size(screen);
+ Size2 window_size;
+ window_size.x = ProjectSettings::get_singleton()->get("display/window/size/viewport_width");
+ window_size.y = ProjectSettings::get_singleton()->get("display/window/size/viewport_height");
+
Size2 desired_size;
- desired_size.x = ProjectSettings::get_singleton()->get("display/window/size/width");
- desired_size.y = ProjectSettings::get_singleton()->get("display/window/size/height");
-
- Size2 test_size;
- test_size.x = ProjectSettings::get_singleton()->get("display/window/size/test_width");
- test_size.y = ProjectSettings::get_singleton()->get("display/window/size/test_height");
- if (test_size.x > 0 && test_size.y > 0) {
- desired_size = test_size;
+ desired_size.x = ProjectSettings::get_singleton()->get("display/window/size/window_width_override");
+ desired_size.y = ProjectSettings::get_singleton()->get("display/window/size/window_height_override");
+ if (desired_size.x > 0 && desired_size.y > 0) {
+ window_size = desired_size;
}
int window_placement = EditorSettings::get_singleton()->get("run/window_placement/rect");
@@ -136,7 +136,7 @@ Error EditorRun::run(const String &p_scene) {
args.push_back(itos(screen_rect.position.x) + "," + itos(screen_rect.position.y));
} break;
case 1: { // centered
- Vector2 pos = (screen_rect.position) + ((screen_rect.size - desired_size) / 2).floor();
+ Vector2 pos = (screen_rect.position) + ((screen_rect.size - window_size) / 2).floor();
args.push_back("--position");
args.push_back(itos(pos.x) + "," + itos(pos.y));
} break;
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index b662eb8b1c..b9291bcd0f 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -339,7 +339,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
{
String lang_hint = "en";
String host_lang = OS::get_singleton()->get_locale();
- host_lang = TranslationServer::standardize_locale(host_lang);
// Skip locales if Text server lack required features.
Vector<String> locales_to_skip;
@@ -365,6 +364,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
}
String best;
+ int best_score = 0;
for (const String &locale : get_editor_locales()) {
// Skip locales which we can't render properly (see above comment).
// Test against language code without regional variants (e.g. ur_PK).
@@ -376,16 +376,16 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
lang_hint += ",";
lang_hint += locale;
- if (host_lang == locale) {
- best = locale;
- }
-
- if (best.is_empty() && host_lang.begins_with(locale)) {
+ int score = TranslationServer::get_singleton()->compare_locales(host_lang, locale);
+ if (score >= best_score) {
best = locale;
+ best_score = score;
+ if (score == 10) {
+ break; // Exact match, skip the rest.
+ }
}
}
-
- if (best.is_empty()) {
+ if (best_score == 0) {
best = "en";
}
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 5b7ea65b04..8e87ddee80 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -1123,6 +1123,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_constant("margin_bottom", "MarginContainer", 0);
theme->set_constant("hseparation", "GridContainer", default_margin_size * EDSCALE);
theme->set_constant("vseparation", "GridContainer", default_margin_size * EDSCALE);
+ theme->set_constant("hseparation", "FlowContainer", default_margin_size * EDSCALE);
+ theme->set_constant("vseparation", "FlowContainer", default_margin_size * EDSCALE);
+ theme->set_constant("hseparation", "HFlowContainer", default_margin_size * EDSCALE);
+ theme->set_constant("vseparation", "HFlowContainer", default_margin_size * EDSCALE);
+ theme->set_constant("hseparation", "VFlowContainer", default_margin_size * EDSCALE);
+ theme->set_constant("vseparation", "VFlowContainer", default_margin_size * EDSCALE);
// Window
@@ -1213,7 +1219,22 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("focus", "RichTextLabel", make_empty_stylebox());
theme->set_stylebox("normal", "RichTextLabel", style_tree_bg);
+ // Editor help.
+ theme->set_color("title_color", "EditorHelp", accent_color);
theme->set_color("headline_color", "EditorHelp", mono_color);
+ theme->set_color("text_color", "EditorHelp", font_color);
+ theme->set_color("comment_color", "EditorHelp", font_color * Color(1, 1, 1, 0.6));
+ theme->set_color("symbol_color", "EditorHelp", font_color * Color(1, 1, 1, 0.6));
+ theme->set_color("value_color", "EditorHelp", font_color * Color(1, 1, 1, 0.6));
+ theme->set_color("qualifier_color", "EditorHelp", font_color * Color(1, 1, 1, 0.8));
+ theme->set_color("type_color", "EditorHelp", accent_color.lerp(font_color, 0.5));
+ theme->set_color("selection_color", "EditorHelp", accent_color * Color(1, 1, 1, 0.4));
+ theme->set_color("link_color", "EditorHelp", accent_color.lerp(mono_color, 0.8));
+ theme->set_color("code_color", "EditorHelp", accent_color.lerp(mono_color, 0.6));
+ theme->set_color("kbd_color", "EditorHelp", accent_color.lerp(property_color, 0.6));
+ theme->set_constant("line_separation", "EditorHelp", Math::round(6 * EDSCALE));
+ theme->set_constant("table_hseparation", "EditorHelp", 16 * EDSCALE);
+ theme->set_constant("table_vseparation", "EditorHelp", 6 * EDSCALE);
// Panel
theme->set_stylebox("panel", "Panel", make_flat_stylebox(dark_color_1, 6, 4, 6, 4, corner_width));
@@ -1421,6 +1442,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_info_3d_viewport->set_border_width_all(0);
theme->set_stylebox("Information3dViewport", "EditorStyles", style_info_3d_viewport);
+ // Asset Library.
+ theme->set_stylebox("panel", "AssetLib", style_content_panel);
+ theme->set_color("status_color", "AssetLib", Color(0.5, 0.5, 0.5));
+ theme->set_icon("dismiss", "AssetLib", theme->get_icon("Close", "EditorIcons"));
+
// Theme editor.
theme->set_color("preview_picker_overlay_color", "ThemeEditor", Color(0.1, 0.1, 0.1, 0.25));
Color theme_preview_picker_bg_color = accent_color;
diff --git a/editor/editor_toaster.cpp b/editor/editor_toaster.cpp
index df0588c641..6c9e4ab0fc 100644
--- a/editor/editor_toaster.cpp
+++ b/editor/editor_toaster.cpp
@@ -362,6 +362,7 @@ Control *EditorToaster::popup(Control *p_control, Severity p_severity, double p_
close_button->set_flat(true);
close_button->set_icon(get_theme_icon("Close", "EditorIcons"));
close_button->connect("pressed", callable_bind(callable_mp(this, &EditorToaster::close), panel));
+ close_button->connect("theme_changed", callable_bind(callable_mp(this, &EditorToaster::_close_button_theme_changed), close_button));
hbox_container->add_child(close_button);
}
@@ -438,6 +439,13 @@ void EditorToaster::close(Control *p_control) {
toasts[p_control].popped = false;
}
+void EditorToaster::_close_button_theme_changed(Control *p_close_button) {
+ Button *close_button = Object::cast_to<Button>(p_close_button);
+ if (close_button) {
+ close_button->set_icon(get_theme_icon("Close", "EditorIcons"));
+ }
+}
+
EditorToaster *EditorToaster::get_singleton() {
return singleton;
}
diff --git a/editor/editor_toaster.h b/editor/editor_toaster.h
index b626a47d0c..5f220e98c4 100644
--- a/editor/editor_toaster.h
+++ b/editor/editor_toaster.h
@@ -95,6 +95,7 @@ private:
void _set_notifications_enabled(bool p_enabled);
void _repop_old();
void _popup_str(String p_message, Severity p_severity, String p_tooltip);
+ void _close_button_theme_changed(Control *p_close_button);
protected:
static EditorToaster *singleton;
diff --git a/editor/icons/HFlowContainer.svg b/editor/icons/HFlowContainer.svg
new file mode 100644
index 0000000000..0ab03f686e
--- /dev/null
+++ b/editor/icons/HFlowContainer.svg
@@ -0,0 +1 @@
+<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M3 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3zm0 2h10v10H3V3zm2 1c-.554 0-1 .446-1 1s.446 1 1 1h2c.554 0 1-.446 1-1s-.446-1-1-1H5zm4.996 0c-.554 0-1 .446-1 1s.446 1 1 1H11c.554 0 1-.446 1-1s-.446-1-1-1H9.996zM5 7c-.554 0-1 .446-1 1s.446 1 1 1 1-.446 1-1-.446-1-1-1zm3 0c-.554 0-1 .446-1 1s.446 1 1 1h3c.554 0 1-.446 1-1s-.446-1-1-1H8zm-3.004 3c-.554 0-1 .446-1 1s.446 1 1 1H9c.554 0 1-.446 1-1s-.446-1-1-1H4.996z" style="fill:#8eef97;fill-opacity:1"/></svg>
diff --git a/editor/icons/Notification.svg b/editor/icons/Notification.svg
index 1f1f9c3e15..15695e22a8 100644
--- a/editor/icons/Notification.svg
+++ b/editor/icons/Notification.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12.089506 1.2353795c-.498141-.2384823-1.095292-.027987-1.333775.4701537-.01372.028981-.02341.059557-.03428.089693-.01467.023016-.02777.046925-.04071.071459-.04899-.00527-.09728-.00862-.146087-.011473-1.4730257-.6255101-3.1777024.0153376-3.8738627 1.4563251l-1.7272425 3.6078572s-.3364181.7034345-.8079671 1.1268133c-.00105.0009371-.00239.00174-.00344.00268-.2721193.1337295-.5707545.185826-.8605632.0470816-.4981411-.2384824-1.0952924-.0279876-1.3337749.4701537-.01605.033526-.029907.066894-.041944.1011828-.018769.030371-.036749.06319-.052515.096122-.2384825.4981412-.027988 1.0952923.4701537 1.3337751l9.0196437 4.318106c.498141.238482 1.095292.02799 1.333775-.470154.01577-.03293.0301-.0675.04191-.1012.0192-.03086.0365-.06257.05255-.0961.238483-.498141.02799-1.095292-.470153-1.333775-.901965-.43181-.03834-2.235739-.03834-2.235739l1.727237-3.6078618c.715447-1.4944233.08396-3.2858776-1.410461-4.0013247.238482-.4981411.02799-1.0952926-.470154-1.333775zm-5.5145786 11.3714015c-.322341.673306-.037829 1.480435.6354753 1.802775.6733031.32234 1.4804334.03783 1.8027749-.635476z" fill="#e6e6e6"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12.089506 1.2353795c-.498141-.2384823-1.095292-.027987-1.333775.4701537-.01372.028981-.02341.059557-.03428.089693-.01467.023016-.02777.046925-.04071.071459-.04899-.00527-.09728-.00862-.146087-.011473-1.4730257-.6255101-3.1777024.0153376-3.8738627 1.4563251l-1.7272425 3.6078572s-.3364181.7034345-.8079671 1.1268133c-.00105.0009371-.00239.00174-.00344.00268-.2721193.1337295-.5707545.185826-.8605632.0470816-.4981411-.2384824-1.0952924-.0279876-1.3337749.4701537-.01605.033526-.029907.066894-.041944.1011828-.018769.030371-.036749.06319-.052515.096122-.2384825.4981412-.027988 1.0952923.4701537 1.3337751l9.0196437 4.318106c.498141.238482 1.095292.02799 1.333775-.470154.01577-.03293.0301-.0675.04191-.1012.0192-.03086.0365-.06257.05255-.0961.238483-.498141.02799-1.095292-.470153-1.333775-.901965-.43181-.03834-2.235739-.03834-2.235739l1.727237-3.6078618c.715447-1.4944233.08396-3.2858776-1.410461-4.0013247.238482-.4981411.02799-1.0952926-.470154-1.333775zm-5.5145786 11.3714015c-.322341.673306-.037829 1.480435.6354753 1.802775.6733031.32234 1.4804334.03783 1.8027749-.635476z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/NotificationDisabled.svg b/editor/icons/NotificationDisabled.svg
index 0e4465bee8..294682a42c 100644
--- a/editor/icons/NotificationDisabled.svg
+++ b/editor/icons/NotificationDisabled.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m11.705078 1.1386719c-.389281-.0180576-.770356.1928007-.949219.5664062-.01372.028981-.024286.0597078-.035156.0898438-.01467.023016-.026122.0477316-.039062.0722656-.04899-.00527-.097678-.0088657-.146485-.0117187-1.4730253-.6255102-3.1788394.0160437-3.8749998 1.4570312l-1.7265624 3.6074219s-.3370448.7035743-.8085938 1.1269531l-.0019531.0019531c-.2721193.1337295-.5715196.1856194-.8613281.046875-.4981413-.2384824-1.0955019-.0274382-1.3339844.4707031-.01605.0335262-.0289787.0672737-.0410156.1015626-.0187691.0303709-.0369684.0627711-.0527344.0957031-.2384825.4981412-.0293917 1.0955019.46875 1.3339841l.3398437.16211 10.8984379-6.9394535c-.263272-.3070418-.592225-.5660832-.980469-.7519531.238482-.4981411.027441-1.0935489-.470703-1.3320313-.124536-.0596206-.255006-.091637-.384766-.0976562zm2.435547 2.8652343a.94188849 1 0 0 0 -.566406.1386719l-12.1171878 7.7148439a.94188849 1 0 0 0 -.3222656 1.373047.94188849 1 0 0 0 1.2910156.341797l12.1171878-7.7148441a.94188849 1 0 0 0 .322265-1.3710938.94188849 1 0 0 0 -.724609-.4824219zm-.509766 3.2753907-7.3867184 4.7050781 5.0781254 2.431641c.498141.238482 1.095501.027442 1.333984-.470704.01577-.03293.031159-.067862.042969-.101562.0192-.03086.036684-.062173.052734-.095703.238483-.498141.02744-1.095501-.470703-1.333985-.901965-.431809-.039063-2.236328-.039062-2.236328zm-7.0566402 5.3281251c-.322341.673306-.0365856 1.480394.6367187 1.802734.6733031.32234 1.4803929.036588 1.8027344-.636718z" fill="#e6e6e6"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m11.705078 1.1386719c-.389281-.0180576-.770356.1928007-.949219.5664062-.01372.028981-.024286.0597078-.035156.0898438-.01467.023016-.026122.0477316-.039062.0722656-.04899-.00527-.097678-.0088657-.146485-.0117187-1.4730253-.6255102-3.1788394.0160437-3.8749998 1.4570312l-1.7265624 3.6074219s-.3370448.7035743-.8085938 1.1269531l-.0019531.0019531c-.2721193.1337295-.5715196.1856194-.8613281.046875-.4981413-.2384824-1.0955019-.0274382-1.3339844.4707031-.01605.0335262-.0289787.0672737-.0410156.1015626-.0187691.0303709-.0369684.0627711-.0527344.0957031-.2384825.4981412-.0293917 1.0955019.46875 1.3339841l.3398437.16211 10.8984379-6.9394535c-.263272-.3070418-.592225-.5660832-.980469-.7519531.238482-.4981411.027441-1.0935489-.470703-1.3320313-.124536-.0596206-.255006-.091637-.384766-.0976562zm2.435547 2.8652343a.94188849 1 0 0 0 -.566406.1386719l-12.1171878 7.7148439a.94188849 1 0 0 0 -.3222656 1.373047.94188849 1 0 0 0 1.2910156.341797l12.1171878-7.7148441a.94188849 1 0 0 0 .322265-1.3710938.94188849 1 0 0 0 -.724609-.4824219zm-.509766 3.2753907-7.3867184 4.7050781 5.0781254 2.431641c.498141.238482 1.095501.027442 1.333984-.470704.01577-.03293.031159-.067862.042969-.101562.0192-.03086.036684-.062173.052734-.095703.238483-.498141.02744-1.095501-.470703-1.333985-.901965-.431809-.039063-2.236328-.039062-2.236328zm-7.0566402 5.3281251c-.322341.673306-.0365856 1.480394.6367187 1.802734.6733031.32234 1.4803929.036588 1.8027344-.636718z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/VFlowContainer.svg b/editor/icons/VFlowContainer.svg
new file mode 100644
index 0000000000..9023bf2245
--- /dev/null
+++ b/editor/icons/VFlowContainer.svg
@@ -0,0 +1 @@
+<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M3 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2H3zm0 2h10v10H3V3zm7.998.998c-.554 0-1 .446-1 1v4.004c0 .554.446 1 1 1s1-.446 1-1V4.998c0-.554-.446-1-1-1zm-6 .004c-.554 0-1 .446-1 1v2c0 .554.446 1 1 1s1-.446 1-1v-2c0-.554-.446-1-1-1zm3 0c-.554 0-1 .446-1 1s.446 1 1 1 1-.446 1-1-.446-1-1-1zm0 3c-.554 0-1 .446-1 1v3c0 .554.446 1 1 1s1-.446 1-1v-3c0-.554-.446-1-1-1zm-3 1.996c-.554 0-1 .446-1 1v1.004c0 .554.446 1 1 1s1-.446 1-1V9.998c0-.554-.446-1-1-1z" style="fill:#8eef97;fill-opacity:1"/></svg>
diff --git a/editor/import/dynamicfont_import_settings.cpp b/editor/import/dynamicfont_import_settings.cpp
index 3151496bec..f4b1468314 100644
--- a/editor/import/dynamicfont_import_settings.cpp
+++ b/editor/import/dynamicfont_import_settings.cpp
@@ -442,398 +442,6 @@ void DynamicFontImportSettings::_add_glyph_range_item(int32_t p_start, int32_t p
}
/*************************************************************************/
-/* Languages and scripts */
-/*************************************************************************/
-
-struct CodeInfo {
- String name;
- String code;
-};
-
-static CodeInfo langs[] = {
- { U"Custom", U"xx" },
- { U"-", U"-" },
- { U"Abkhazian", U"ab" },
- { U"Afar", U"aa" },
- { U"Afrikaans", U"af" },
- { U"Akan", U"ak" },
- { U"Albanian", U"sq" },
- { U"Amharic", U"am" },
- { U"Arabic", U"ar" },
- { U"Aragonese", U"an" },
- { U"Armenian", U"hy" },
- { U"Assamese", U"as" },
- { U"Avaric", U"av" },
- { U"Avestan", U"ae" },
- { U"Aymara", U"ay" },
- { U"Azerbaijani", U"az" },
- { U"Bambara", U"bm" },
- { U"Bashkir", U"ba" },
- { U"Basque", U"eu" },
- { U"Belarusian", U"be" },
- { U"Bengali", U"bn" },
- { U"Bihari", U"bh" },
- { U"Bislama", U"bi" },
- { U"Bosnian", U"bs" },
- { U"Breton", U"br" },
- { U"Bulgarian", U"bg" },
- { U"Burmese", U"my" },
- { U"Catalan", U"ca" },
- { U"Chamorro", U"ch" },
- { U"Chechen", U"ce" },
- { U"Chichewa", U"ny" },
- { U"Chinese", U"zh" },
- { U"Chuvash", U"cv" },
- { U"Cornish", U"kw" },
- { U"Corsican", U"co" },
- { U"Cree", U"cr" },
- { U"Croatian", U"hr" },
- { U"Czech", U"cs" },
- { U"Danish", U"da" },
- { U"Divehi", U"dv" },
- { U"Dutch", U"nl" },
- { U"Dzongkha", U"dz" },
- { U"English", U"en" },
- { U"Esperanto", U"eo" },
- { U"Estonian", U"et" },
- { U"Ewe", U"ee" },
- { U"Faroese", U"fo" },
- { U"Fijian", U"fj" },
- { U"Finnish", U"fi" },
- { U"French", U"fr" },
- { U"Fulah", U"ff" },
- { U"Galician", U"gl" },
- { U"Georgian", U"ka" },
- { U"German", U"de" },
- { U"Greek", U"el" },
- { U"Guarani", U"gn" },
- { U"Gujarati", U"gu" },
- { U"Haitian", U"ht" },
- { U"Hausa", U"ha" },
- { U"Hebrew", U"he" },
- { U"Herero", U"hz" },
- { U"Hindi", U"hi" },
- { U"Hiri Motu", U"ho" },
- { U"Hungarian", U"hu" },
- { U"Interlingua", U"ia" },
- { U"Indonesian", U"id" },
- { U"Interlingue", U"ie" },
- { U"Irish", U"ga" },
- { U"Igbo", U"ig" },
- { U"Inupiaq", U"ik" },
- { U"Ido", U"io" },
- { U"Icelandic", U"is" },
- { U"Italian", U"it" },
- { U"Inuktitut", U"iu" },
- { U"Japanese", U"ja" },
- { U"Javanese", U"jv" },
- { U"Kalaallisut", U"kl" },
- { U"Kannada", U"kn" },
- { U"Kanuri", U"kr" },
- { U"Kashmiri", U"ks" },
- { U"Kazakh", U"kk" },
- { U"Central Khmer", U"km" },
- { U"Kikuyu", U"ki" },
- { U"Kinyarwanda", U"rw" },
- { U"Kirghiz", U"ky" },
- { U"Komi", U"kv" },
- { U"Kongo", U"kg" },
- { U"Korean", U"ko" },
- { U"Kurdish", U"ku" },
- { U"Kuanyama", U"kj" },
- { U"Latin", U"la" },
- { U"Luxembourgish", U"lb" },
- { U"Ganda", U"lg" },
- { U"Limburgan", U"li" },
- { U"Lingala", U"ln" },
- { U"Lao", U"lo" },
- { U"Lithuanian", U"lt" },
- { U"Luba-Katanga", U"lu" },
- { U"Latvian", U"lv" },
- { U"Man", U"gv" },
- { U"Macedonian", U"mk" },
- { U"Malagasy", U"mg" },
- { U"Malay", U"ms" },
- { U"Malayalam", U"ml" },
- { U"Maltese", U"mt" },
- { U"Maori", U"mi" },
- { U"Marathi", U"mr" },
- { U"Marshallese", U"mh" },
- { U"Mongolian", U"mn" },
- { U"Nauru", U"na" },
- { U"Navajo", U"nv" },
- { U"North Ndebele", U"nd" },
- { U"Nepali", U"ne" },
- { U"Ndonga", U"ng" },
- { U"Norwegian Bokmål", U"nb" },
- { U"Norwegian Nynorsk", U"nn" },
- { U"Norwegian", U"no" },
- { U"Sichuan Yi, Nuosu", U"ii" },
- { U"South Ndebele", U"nr" },
- { U"Occitan", U"oc" },
- { U"Ojibwa", U"oj" },
- { U"Church Slavic", U"cu" },
- { U"Oromo", U"om" },
- { U"Oriya", U"or" },
- { U"Ossetian", U"os" },
- { U"Punjabi", U"pa" },
- { U"Pali", U"pi" },
- { U"Persian", U"fa" },
- { U"Polish", U"pl" },
- { U"Pashto", U"ps" },
- { U"Portuguese", U"pt" },
- { U"Quechua", U"qu" },
- { U"Romansh", U"rm" },
- { U"Rundi", U"rn" },
- { U"Romanian", U"ro" },
- { U"Russian", U"ru" },
- { U"Sanskrit", U"sa" },
- { U"Sardinian", U"sc" },
- { U"Sindhi", U"sd" },
- { U"Northern Sami", U"se" },
- { U"Samoan", U"sm" },
- { U"Sango", U"sg" },
- { U"Serbian", U"sr" },
- { U"Gaelic", U"gd" },
- { U"Shona", U"sn" },
- { U"Sinhala", U"si" },
- { U"Slovak", U"sk" },
- { U"Slovenian", U"sl" },
- { U"Somali", U"so" },
- { U"Southern Sotho", U"st" },
- { U"Spanish", U"es" },
- { U"Sundanese", U"su" },
- { U"Swahili", U"sw" },
- { U"Swati", U"ss" },
- { U"Swedish", U"sv" },
- { U"Tamil", U"ta" },
- { U"Telugu", U"te" },
- { U"Tajik", U"tg" },
- { U"Thai", U"th" },
- { U"Tigrinya", U"ti" },
- { U"Tibetan", U"bo" },
- { U"Turkmen", U"tk" },
- { U"Tagalog", U"tl" },
- { U"Tswana", U"tn" },
- { U"Tonga", U"to" },
- { U"Turkish", U"tr" },
- { U"Tsonga", U"ts" },
- { U"Tatar", U"tt" },
- { U"Twi", U"tw" },
- { U"Tahitian", U"ty" },
- { U"Uighur", U"ug" },
- { U"Ukrainian", U"uk" },
- { U"Urdu", U"ur" },
- { U"Uzbek", U"uz" },
- { U"Venda", U"ve" },
- { U"Vietnamese", U"vi" },
- { U"Volapük", U"vo" },
- { U"Walloon", U"wa" },
- { U"Welsh", U"cy" },
- { U"Wolof", U"wo" },
- { U"Western Frisian", U"fy" },
- { U"Xhosa", U"xh" },
- { U"Yiddish", U"yi" },
- { U"Yoruba", U"yo" },
- { U"Zhuang", U"za" },
- { U"Zulu", U"zu" },
- { String(), String() }
-};
-
-static CodeInfo scripts[] = {
- { U"Custom", U"Qaaa" },
- { U"-", U"-" },
- { U"Adlam", U"Adlm" },
- { U"Afaka", U"Afak" },
- { U"Caucasian Albanian", U"Aghb" },
- { U"Ahom", U"Ahom" },
- { U"Arabic", U"Arab" },
- { U"Imperial Aramaic", U"Armi" },
- { U"Armenian", U"Armn" },
- { U"Avestan", U"Avst" },
- { U"Balinese", U"Bali" },
- { U"Bamum", U"Bamu" },
- { U"Bassa Vah", U"Bass" },
- { U"Batak", U"Batk" },
- { U"Bengali", U"Beng" },
- { U"Bhaiksuki", U"Bhks" },
- { U"Blissymbols", U"Blis" },
- { U"Bopomofo", U"Bopo" },
- { U"Brahmi", U"Brah" },
- { U"Braille", U"Brai" },
- { U"Buginese", U"Bugi" },
- { U"Buhid", U"Buhd" },
- { U"Chakma", U"Cakm" },
- { U"Unified Canadian Aboriginal", U"Cans" },
- { U"Carian", U"Cari" },
- { U"Cham", U"Cham" },
- { U"Cherokee", U"Cher" },
- { U"Chorasmian", U"Chrs" },
- { U"Cirth", U"Cirt" },
- { U"Coptic", U"Copt" },
- { U"Cypro-Minoan", U"Cpmn" },
- { U"Cypriot", U"Cprt" },
- { U"Cyrillic", U"Cyrl" },
- { U"Devanagari", U"Deva" },
- { U"Dives Akuru", U"Diak" },
- { U"Dogra", U"Dogr" },
- { U"Deseret", U"Dsrt" },
- { U"Duployan", U"Dupl" },
- { U"Egyptian demotic", U"Egyd" },
- { U"Egyptian hieratic", U"Egyh" },
- { U"Egyptian hieroglyphs", U"Egyp" },
- { U"Elbasan", U"Elba" },
- { U"Elymaic", U"Elym" },
- { U"Ethiopic", U"Ethi" },
- { U"Khutsuri", U"Geok" },
- { U"Georgian", U"Geor" },
- { U"Glagolitic", U"Glag" },
- { U"Gunjala Gondi", U"Gong" },
- { U"Masaram Gondi", U"Gonm" },
- { U"Gothic", U"Goth" },
- { U"Grantha", U"Gran" },
- { U"Greek", U"Grek" },
- { U"Gujarati", U"Gujr" },
- { U"Gurmukhi", U"Guru" },
- { U"Hangul", U"Hang" },
- { U"Han", U"Hani" },
- { U"Hanunoo", U"Hano" },
- { U"Hatran", U"Hatr" },
- { U"Hebrew", U"Hebr" },
- { U"Hiragana", U"Hira" },
- { U"Anatolian Hieroglyphs", U"Hluw" },
- { U"Pahawh Hmong", U"Hmng" },
- { U"Nyiakeng Puachue Hmong", U"Hmnp" },
- { U"Old Hungarian", U"Hung" },
- { U"Indus", U"Inds" },
- { U"Old Italic", U"Ital" },
- { U"Javanese", U"Java" },
- { U"Jurchen", U"Jurc" },
- { U"Kayah Li", U"Kali" },
- { U"Katakana", U"Kana" },
- { U"Kharoshthi", U"Khar" },
- { U"Khmer", U"Khmr" },
- { U"Khojki", U"Khoj" },
- { U"Khitan large script", U"Kitl" },
- { U"Khitan small script", U"Kits" },
- { U"Kannada", U"Knda" },
- { U"Kpelle", U"Kpel" },
- { U"Kaithi", U"Kthi" },
- { U"Tai Tham", U"Lana" },
- { U"Lao", U"Laoo" },
- { U"Latin", U"Latn" },
- { U"Leke", U"Leke" },
- { U"Lepcha", U"Lepc" },
- { U"Limbu", U"Limb" },
- { U"Linear A", U"Lina" },
- { U"Linear B", U"Linb" },
- { U"Lisu", U"Lisu" },
- { U"Loma", U"Loma" },
- { U"Lycian", U"Lyci" },
- { U"Lydian", U"Lydi" },
- { U"Mahajani", U"Mahj" },
- { U"Makasar", U"Maka" },
- { U"Mandaic", U"Mand" },
- { U"Manichaean", U"Mani" },
- { U"Marchen", U"Marc" },
- { U"Mayan Hieroglyphs", U"Maya" },
- { U"Medefaidrin", U"Medf" },
- { U"Mende Kikakui", U"Mend" },
- { U"Meroitic Cursive", U"Merc" },
- { U"Meroitic Hieroglyphs", U"Mero" },
- { U"Malayalam", U"Mlym" },
- { U"Modi", U"Modi" },
- { U"Mongolian", U"Mong" },
- { U"Moon", U"Moon" },
- { U"Mro", U"Mroo" },
- { U"Meitei Mayek", U"Mtei" },
- { U"Multani", U"Mult" },
- { U"Myanmar (Burmese)", U"Mymr" },
- { U"Nandinagari", U"Nand" },
- { U"Old North Arabian", U"Narb" },
- { U"Nabataean", U"Nbat" },
- { U"Newa", U"Newa" },
- { U"Naxi Dongba", U"Nkdb" },
- { U"Nakhi Geba", U"Nkgb" },
- { U"N’Ko", U"Nkoo" },
- { U"Nüshu", U"Nshu" },
- { U"Ogham", U"Ogam" },
- { U"Ol Chiki", U"Olck" },
- { U"Old Turkic", U"Orkh" },
- { U"Oriya", U"Orya" },
- { U"Osage", U"Osge" },
- { U"Osmanya", U"Osma" },
- { U"Old Uyghur", U"Ougr" },
- { U"Palmyrene", U"Palm" },
- { U"Pau Cin Hau", U"Pauc" },
- { U"Proto-Cuneiform", U"Pcun" },
- { U"Proto-Elamite", U"Pelm" },
- { U"Old Permic", U"Perm" },
- { U"Phags-pa", U"Phag" },
- { U"Inscriptional Pahlavi", U"Phli" },
- { U"Psalter Pahlavi", U"Phlp" },
- { U"Book Pahlavi", U"Phlv" },
- { U"Phoenician", U"Phnx" },
- { U"Klingon", U"Piqd" },
- { U"Miao", U"Plrd" },
- { U"Inscriptional Parthian", U"Prti" },
- { U"Proto-Sinaitic", U"Psin" },
- { U"Ranjana", U"Ranj" },
- { U"Rejang", U"Rjng" },
- { U"Hanifi Rohingya", U"Rohg" },
- { U"Rongorongo", U"Roro" },
- { U"Runic", U"Runr" },
- { U"Samaritan", U"Samr" },
- { U"Sarati", U"Sara" },
- { U"Old South Arabian", U"Sarb" },
- { U"Saurashtra", U"Saur" },
- { U"SignWriting", U"Sgnw" },
- { U"Shavian", U"Shaw" },
- { U"Sharada", U"Shrd" },
- { U"Shuishu", U"Shui" },
- { U"Siddham", U"Sidd" },
- { U"Khudawadi", U"Sind" },
- { U"Sinhala", U"Sinh" },
- { U"Sogdian", U"Sogd" },
- { U"Old Sogdian", U"Sogo" },
- { U"Sora Sompeng", U"Sora" },
- { U"Soyombo", U"Soyo" },
- { U"Sundanese", U"Sund" },
- { U"Syloti Nagri", U"Sylo" },
- { U"Syriac", U"Syrc" },
- { U"Tagbanwa", U"Tagb" },
- { U"Takri", U"Takr" },
- { U"Tai Le", U"Tale" },
- { U"New Tai Lue", U"Talu" },
- { U"Tamil", U"Taml" },
- { U"Tangut", U"Tang" },
- { U"Tai Viet", U"Tavt" },
- { U"Telugu", U"Telu" },
- { U"Tengwar", U"Teng" },
- { U"Tifinagh", U"Tfng" },
- { U"Tagalog", U"Tglg" },
- { U"Thaana", U"Thaa" },
- { U"Thai", U"Thai" },
- { U"Tibetan", U"Tibt" },
- { U"Tirhuta", U"Tirh" },
- { U"Tangsa", U"Tnsa" },
- { U"Toto", U"Toto" },
- { U"Ugaritic", U"Ugar" },
- { U"Vai", U"Vaii" },
- { U"Visible Speech", U"Visp" },
- { U"Vithkuqi", U"Vith" },
- { U"Warang Citi", U"Wara" },
- { U"Wancho", U"Wcho" },
- { U"Woleai", U"Wole" },
- { U"Old Persian", U"Xpeo" },
- { U"Cuneiform", U"Xsux" },
- { U"Yezidi", U"Yezi" },
- { U"Yi", U"Yiii" },
- { U"Zanabazar Square", U"Zanb" },
- { String(), String() }
-};
-
-/*************************************************************************/
/* Page 1 callbacks: Rendering Options */
/*************************************************************************/
@@ -1159,19 +767,17 @@ void DynamicFontImportSettings::_range_update(int32_t p_start, int32_t p_end) {
/*************************************************************************/
void DynamicFontImportSettings::_lang_add() {
- menu_langs->set_position(lang_list->get_screen_position() + lang_list->get_local_mouse_position());
- menu_langs->reset_size();
- menu_langs->popup();
+ locale_select->popup_locale_dialog();
}
-void DynamicFontImportSettings::_lang_add_item(int p_option) {
+void DynamicFontImportSettings::_lang_add_item(const String &p_locale) {
TreeItem *lang_item = lang_list->create_item(lang_list_root);
ERR_FAIL_NULL(lang_item);
lang_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
lang_item->set_editable(0, true);
lang_item->set_checked(0, false);
- lang_item->set_text(1, langs[p_option].code);
+ lang_item->set_text(1, p_locale);
lang_item->set_editable(1, true);
lang_item->add_button(2, lang_list->get_theme_icon("Remove", "EditorIcons"), BUTTON_REMOVE_VAR, false, TTR("Remove"));
lang_item->set_button_color(2, 0, Color(1, 1, 1, 0.75));
@@ -1230,7 +836,7 @@ void DynamicFontImportSettings::_script_add_item(int p_option) {
script_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
script_item->set_editable(0, true);
script_item->set_checked(0, false);
- script_item->set_text(1, scripts[p_option].code);
+ script_item->set_text(1, script_codes[p_option]);
script_item->set_editable(1, true);
script_item->add_button(2, lang_list->get_theme_icon("Remove", "EditorIcons"), BUTTON_REMOVE_VAR, false, TTR("Remove"));
script_item->set_button_color(2, 0, Color(1, 1, 1, 0.75));
@@ -1688,26 +1294,15 @@ DynamicFontImportSettings::DynamicFontImportSettings() {
// Popup menus
- menu_langs = memnew(PopupMenu);
- menu_langs->set_name("Language");
- for (int i = 0; !langs[i].name.is_empty(); i++) {
- if (langs[i].name == "-") {
- menu_langs->add_separator();
- } else {
- menu_langs->add_item(langs[i].name + " (" + langs[i].code + ")", i);
- }
- }
- add_child(menu_langs);
- menu_langs->connect("id_pressed", callable_mp(this, &DynamicFontImportSettings::_lang_add_item));
+ locale_select = memnew(EditorLocaleDialog);
+ locale_select->connect("locale_selected", callable_mp(this, &DynamicFontImportSettings::_lang_add_item));
+ add_child(locale_select);
menu_scripts = memnew(PopupMenu);
menu_scripts->set_name("Script");
- for (int i = 0; !scripts[i].name.is_empty(); i++) {
- if (scripts[i].name == "-") {
- menu_scripts->add_separator();
- } else {
- menu_scripts->add_item(scripts[i].name + " (" + scripts[i].code + ")", i);
- }
+ script_codes = TranslationServer::get_singleton()->get_all_scripts();
+ for (int i = 0; i < script_codes.size(); i++) {
+ menu_scripts->add_item(TranslationServer::get_singleton()->get_script_name(script_codes[i]) + " (" + script_codes[i] + ")", i);
}
add_child(menu_scripts);
menu_scripts->connect("id_pressed", callable_mp(this, &DynamicFontImportSettings::_script_add_item));
diff --git a/editor/import/dynamicfont_import_settings.h b/editor/import/dynamicfont_import_settings.h
index 89665ae476..5d37f58b9b 100644
--- a/editor/import/dynamicfont_import_settings.h
+++ b/editor/import/dynamicfont_import_settings.h
@@ -33,6 +33,7 @@
#include "editor/editor_file_dialog.h"
#include "editor/editor_inspector.h"
+#include "editor/editor_locale_dialog.h"
#include "editor/import/resource_importer_dynamicfont.h"
@@ -67,6 +68,9 @@ class DynamicFontImportSettings : public ConfirmationDialog {
List<ResourceImporter::ImportOption> options_variations;
List<ResourceImporter::ImportOption> options_general;
+ EditorLocaleDialog *locale_select;
+ Vector<String> script_codes;
+
// Root layout
Label *label_warn = nullptr;
TabContainer *main_pages = nullptr;
@@ -122,7 +126,6 @@ class DynamicFontImportSettings : public ConfirmationDialog {
Button *add_script = nullptr;
Button *add_ot = nullptr;
- PopupMenu *menu_langs = nullptr;
PopupMenu *menu_scripts = nullptr;
PopupMenu *menu_ot = nullptr;
PopupMenu *menu_ot_ss = nullptr;
@@ -142,7 +145,7 @@ class DynamicFontImportSettings : public ConfirmationDialog {
Label *label_ot = nullptr;
void _lang_add();
- void _lang_add_item(int p_option);
+ void _lang_add_item(const String &p_locale);
void _lang_remove(Object *p_item, int p_column, int p_id);
void _script_add();
diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp
index 448b318c64..f0ee14bdcb 100644
--- a/editor/import/resource_importer_csv_translation.cpp
+++ b/editor/import/resource_importer_csv_translation.cpp
@@ -99,8 +99,7 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const
Vector<Ref<Translation>> translations;
for (int i = 1; i < line.size(); i++) {
- String locale = line[i];
- ERR_FAIL_COND_V_MSG(!TranslationServer::is_locale_valid(locale), ERR_PARSE_ERROR, "Error importing CSV translation: '" + locale + "' is not a valid locale.");
+ String locale = TranslationServer::get_singleton()->standardize_locale(line[i]);
locales.push_back(locale);
Ref<Translation> translation;
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index e801cd4553..b6624a8cfa 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -370,16 +370,17 @@ static void _pre_gen_shape_list(Ref<ImporterMesh> &mesh, Vector<Ref<Shape3D>> &r
}
}
-Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map) {
- // children first
+Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, List<Pair<NodePath, Node *>> &r_node_renames) {
+ // Children first.
for (int i = 0; i < p_node->get_child_count(); i++) {
- Node *r = _pre_fix_node(p_node->get_child(i), p_root, collision_map);
+ Node *r = _pre_fix_node(p_node->get_child(i), p_root, collision_map, r_node_renames);
if (!r) {
- i--; //was erased
+ i--; // Was erased.
}
}
String name = p_node->get_name();
+ NodePath original_path = p_root->get_path_to(p_node); // Used to detect renames due to import hints.
bool isroot = p_node == p_root;
@@ -414,14 +415,21 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I
}
if (Object::cast_to<AnimationPlayer>(p_node)) {
- //remove animations referencing non-importable nodes
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
+ // Node paths in animation tracks are relative to the following path (this is used to fix node paths below).
+ Node *ap_root = ap->get_node(ap->get_root());
+ NodePath path_prefix = p_root->get_path_to(ap_root);
+
+ bool nodes_were_renamed = r_node_renames.size() != 0;
+
List<StringName> anims;
ap->get_animation_list(&anims);
for (const StringName &E : anims) {
Ref<Animation> anim = ap->get_animation(E);
ERR_CONTINUE(anim.is_null());
+
+ // Remove animation tracks referencing non-importable nodes.
for (int i = 0; i < anim->get_track_count(); i++) {
NodePath path = anim->track_get_path(i);
@@ -435,6 +443,27 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I
}
}
+ // Fix node paths in animations, in case nodes were renamed earlier due to import hints.
+ if (nodes_were_renamed) {
+ for (int i = 0; i < anim->get_track_count(); i++) {
+ NodePath path = anim->track_get_path(i);
+ // Convert track path to absolute node path without subnames (some manual work because we are not in the scene tree).
+ Vector<StringName> absolute_path_names = path_prefix.get_names();
+ absolute_path_names.append_array(path.get_names());
+ NodePath absolute_path(absolute_path_names, false);
+ absolute_path.simplify();
+ // Fix paths to renamed nodes.
+ for (const Pair<NodePath, Node *> &F : r_node_renames) {
+ if (F.first == absolute_path) {
+ NodePath new_path(ap_root->get_path_to(F.second).get_names(), path.get_subnames(), false);
+ print_verbose(vformat("Fix: Correcting node path in animation track: %s should be %s", path, new_path));
+ anim->track_set_path(i, new_path);
+ break; // Only one match is possible.
+ }
+ }
+ }
+ }
+
String animname = E;
const int loop_string_count = 3;
static const char *loop_strings[loop_string_count] = { "loop_mode", "loop", "cycle" };
@@ -452,13 +481,22 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I
if (isroot) {
return p_node;
}
+
+ String fixed_name;
+ if (_teststr(name, "colonly")) {
+ fixed_name = _fixstr(name, "colonly");
+ } else if (_teststr(name, "convcolonly")) {
+ fixed_name = _fixstr(name, "convcolonly");
+ }
+
+ ERR_FAIL_COND_V(fixed_name.is_empty(), nullptr);
+
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
if (mi) {
Ref<ImporterMesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
Vector<Ref<Shape3D>> shapes;
- String fixed_name;
if (collision_map.has(mesh)) {
shapes = collision_map[mesh];
} else if (_teststr(name, "colonly")) {
@@ -469,14 +507,6 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I
collision_map[mesh] = shapes;
}
- if (_teststr(name, "colonly")) {
- fixed_name = _fixstr(name, "colonly");
- } else if (_teststr(name, "convcolonly")) {
- fixed_name = _fixstr(name, "convcolonly");
- }
-
- ERR_FAIL_COND_V(fixed_name.is_empty(), nullptr);
-
if (shapes.size()) {
StaticBody3D *col = memnew(StaticBody3D);
col->set_transform(mi->get_transform());
@@ -492,11 +522,11 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I
} else if (p_node->has_meta("empty_draw_type")) {
String empty_draw_type = String(p_node->get_meta("empty_draw_type"));
StaticBody3D *sb = memnew(StaticBody3D);
- sb->set_name(_fixstr(name, "colonly"));
+ sb->set_name(fixed_name);
Object::cast_to<Node3D>(sb)->set_transform(Object::cast_to<Node3D>(p_node)->get_transform());
p_node->replace_by(sb);
memdelete(p_node);
- p_node = nullptr;
+ p_node = sb;
CollisionShape3D *colshape = memnew(CollisionShape3D);
if (empty_draw_type == "CUBE") {
BoxShape3D *boxShape = memnew(BoxShape3D);
@@ -635,6 +665,14 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I
}
}
+ if (p_node) {
+ NodePath new_path = p_root->get_path_to(p_node);
+ if (new_path != original_path) {
+ print_verbose(vformat("Fix: Renamed %s to %s", original_path, new_path));
+ r_node_renames.push_back({ original_path, p_node });
+ }
+ }
+
return p_node;
}
@@ -1828,8 +1866,8 @@ Node *ResourceImporterScene::pre_import(const String &p_source_file) {
}
Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> collision_map;
-
- _pre_fix_node(scene, scene, collision_map);
+ List<Pair<NodePath, Node *>> node_renames;
+ _pre_fix_node(scene, scene, collision_map, node_renames);
return scene;
}
@@ -1904,8 +1942,9 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
Set<Ref<ImporterMesh>> scanned_meshes;
Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> collision_map;
+ List<Pair<NodePath, Node *>> node_renames;
- _pre_fix_node(scene, scene, collision_map);
+ _pre_fix_node(scene, scene, collision_map, node_renames);
for (int i = 0; i < post_importer_plugins.size(); i++) {
post_importer_plugins.write[i]->pre_process(scene, p_options);
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index 00d095eac1..066e8b603b 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -261,7 +261,7 @@ public:
// Import scenes *after* everything else (such as textures).
virtual int get_import_order() const override { return ResourceImporter::IMPORT_ORDER_SCENE; }
- Node *_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map);
+ Node *_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, List<Pair<NodePath, Node *>> &r_node_renames);
Node *_post_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Set<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps);
Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks);
diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp
index a902b070f4..1e9e2fc09b 100644
--- a/editor/localization_editor.cpp
+++ b/editor/localization_editor.cpp
@@ -32,6 +32,7 @@
#include "core/string/translation.h"
#include "editor_node.h"
+#include "editor_scale.h"
#include "editor_translation_parser.h"
#include "pot_generator.h"
#include "scene/gui/control.h"
@@ -175,10 +176,27 @@ void LocalizationEditor::_translation_res_select() {
if (updating_translations) {
return;
}
-
call_deferred(SNAME("update_translations"));
}
+void LocalizationEditor::_translation_res_option_popup(bool p_arrow_clicked) {
+ TreeItem *ed = translation_remap_options->get_edited();
+ ERR_FAIL_COND(!ed);
+
+ locale_select->set_locale(ed->get_tooltip(1));
+ locale_select->popup_locale_dialog();
+}
+
+void LocalizationEditor::_translation_res_option_selected(const String &p_locale) {
+ TreeItem *ed = translation_remap_options->get_edited();
+ ERR_FAIL_COND(!ed);
+
+ ed->set_text(1, TranslationServer::get_singleton()->get_locale_name(p_locale));
+ ed->set_tooltip(1, p_locale);
+
+ LocalizationEditor::_translation_res_option_changed();
+}
+
void LocalizationEditor::_translation_res_option_changed() {
if (updating_translations) {
return;
@@ -198,20 +216,11 @@ void LocalizationEditor::_translation_res_option_changed() {
String key = k->get_metadata(0);
int idx = ed->get_metadata(0);
String path = ed->get_metadata(1);
- int which = ed->get_range(1);
-
- Vector<String> langs = TranslationServer::get_all_locales();
-
- ERR_FAIL_INDEX(which, langs.size());
+ String locale = ed->get_tooltip(1);
ERR_FAIL_COND(!remaps.has(key));
PackedStringArray r = remaps[key];
- ERR_FAIL_INDEX(idx, r.size());
- if (translation_locales_idxs_remap.size() > which) {
- r.set(idx, path + ":" + langs[translation_locales_idxs_remap[which]]);
- } else {
- r.set(idx, path + ":" + langs[which]);
- }
+ r.set(idx, path + ":" + locale);
remaps[key] = r;
updating_translations = true;
@@ -289,86 +298,6 @@ void LocalizationEditor::_translation_res_option_delete(Object *p_item, int p_co
undo_redo->commit_action();
}
-void LocalizationEditor::_translation_filter_option_changed() {
- int sel_id = translation_locale_filter_mode->get_selected_id();
- TreeItem *t = translation_filter->get_edited();
- String locale = t->get_tooltip(0);
- bool checked = t->is_checked(0);
-
- Variant prev;
- Array f_locales_all;
-
- if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/locale_filter")) {
- f_locales_all = ProjectSettings::get_singleton()->get("internationalization/locale/locale_filter");
- prev = f_locales_all;
-
- if (f_locales_all.size() != 2) {
- f_locales_all.clear();
- f_locales_all.append(sel_id);
- f_locales_all.append(Array());
- }
- } else {
- f_locales_all.append(sel_id);
- f_locales_all.append(Array());
- }
-
- Array f_locales = f_locales_all[1];
- int l_idx = f_locales.find(locale);
-
- if (checked) {
- if (l_idx == -1) {
- f_locales.append(locale);
- }
- } else {
- if (l_idx != -1) {
- f_locales.remove_at(l_idx);
- }
- }
-
- f_locales.sort();
-
- undo_redo->create_action(TTR("Changed Locale Filter"));
- undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/locale_filter", f_locales_all);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/locale_filter", prev);
- undo_redo->add_do_method(this, "update_translations");
- undo_redo->add_undo_method(this, "update_translations");
- undo_redo->add_do_method(this, "emit_signal", localization_changed);
- undo_redo->add_undo_method(this, "emit_signal", localization_changed);
- undo_redo->commit_action();
-}
-
-void LocalizationEditor::_translation_filter_mode_changed(int p_mode) {
- int sel_id = translation_locale_filter_mode->get_selected_id();
-
- Variant prev;
- Array f_locales_all;
-
- if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/locale_filter")) {
- f_locales_all = ProjectSettings::get_singleton()->get("internationalization/locale/locale_filter");
- prev = f_locales_all;
-
- if (f_locales_all.size() != 2) {
- f_locales_all.clear();
- f_locales_all.append(sel_id);
- f_locales_all.append(Array());
- } else {
- f_locales_all[0] = sel_id;
- }
- } else {
- f_locales_all.append(sel_id);
- f_locales_all.append(Array());
- }
-
- undo_redo->create_action(TTR("Changed Locale Filter Mode"));
- undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/locale_filter", f_locales_all);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/locale_filter", prev);
- undo_redo->add_do_method(this, "update_translations");
- undo_redo->add_undo_method(this, "update_translations");
- undo_redo->add_do_method(this, "emit_signal", localization_changed);
- undo_redo->add_undo_method(this, "emit_signal", localization_changed);
- undo_redo->commit_action();
-}
-
void LocalizationEditor::_pot_add(const PackedStringArray &p_paths) {
PackedStringArray pot_translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations_pot_files");
for (int i = 0; i < p_paths.size(); i++) {
@@ -452,64 +381,6 @@ void LocalizationEditor::update_translations() {
}
}
- Vector<String> langs = TranslationServer::get_all_locales();
- Vector<String> names = TranslationServer::get_all_locale_names();
-
- // Update filter tab
- Array l_filter_all;
-
- bool is_arr_empty = true;
- if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/locale_filter")) {
- l_filter_all = ProjectSettings::get_singleton()->get("internationalization/locale/locale_filter");
-
- if (l_filter_all.size() == 2) {
- translation_locale_filter_mode->select(l_filter_all[0]);
- is_arr_empty = false;
- }
- }
- if (is_arr_empty) {
- l_filter_all.append(0);
- l_filter_all.append(Array());
- translation_locale_filter_mode->select(0);
- }
-
- int filter_mode = l_filter_all[0];
- Array l_filter = l_filter_all[1];
-
- int s = names.size();
- bool is_short_list_when_show_all_selected = filter_mode == SHOW_ALL_LOCALES && translation_filter_treeitems.size() < s;
- bool is_full_list_when_show_only_selected = filter_mode == SHOW_ONLY_SELECTED_LOCALES && translation_filter_treeitems.size() == s;
- bool should_recreate_locales_list = is_short_list_when_show_all_selected || is_full_list_when_show_only_selected;
-
- if (!translation_locales_list_created || should_recreate_locales_list) {
- translation_locales_list_created = true;
- translation_filter->clear();
- root = translation_filter->create_item(nullptr);
- translation_filter->set_hide_root(true);
- translation_filter_treeitems.clear();
- for (int i = 0; i < s; i++) {
- String n = names[i];
- String l = langs[i];
- bool is_checked = l_filter.has(l);
- if (filter_mode == SHOW_ONLY_SELECTED_LOCALES && !is_checked) {
- continue;
- }
-
- TreeItem *t = translation_filter->create_item(root);
- t->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
- t->set_text(0, vformat("[%s] %s", l, n));
- t->set_editable(0, true);
- t->set_tooltip(0, l);
- t->set_checked(0, is_checked);
- translation_filter_treeitems.push_back(t);
- }
- } else {
- for (int i = 0; i < translation_filter_treeitems.size(); i++) {
- TreeItem *t = translation_filter_treeitems[i];
- t->set_checked(0, l_filter.has(t->get_tooltip(0)));
- }
- }
-
// Update translation remaps.
String remap_selected;
if (translation_remap->get_selected()) {
@@ -524,32 +395,6 @@ void LocalizationEditor::update_translations() {
translation_remap_options->set_hide_root(true);
translation_res_option_add_button->set_disabled(true);
- translation_locales_idxs_remap.clear();
- translation_locales_idxs_remap.resize(l_filter.size());
- int fl_idx_count = translation_locales_idxs_remap.size();
-
- String langnames = "";
- int l_idx = 0;
- for (int i = 0; i < names.size(); i++) {
- if (filter_mode == SHOW_ONLY_SELECTED_LOCALES && fl_idx_count != 0) {
- if (l_filter.size() > 0) {
- if (l_filter.find(langs[i]) != -1) {
- if (langnames.length() > 0) {
- langnames += ",";
- }
- langnames += vformat("[%s] %s", langs[i], names[i]);
- translation_locales_idxs_remap.write[l_idx] = i;
- l_idx++;
- }
- }
- } else {
- if (i > 0) {
- langnames += ",";
- }
- langnames += vformat("[%s] %s", langs[i], names[i]);
- }
- }
-
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
List<Variant> rk;
@@ -584,21 +429,11 @@ void LocalizationEditor::update_translations() {
t2->set_tooltip(0, path);
t2->set_metadata(0, j);
t2->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove"));
- t2->set_cell_mode(1, TreeItem::CELL_MODE_RANGE);
- t2->set_text(1, langnames);
+ t2->set_cell_mode(1, TreeItem::CELL_MODE_CUSTOM);
+ t2->set_text(1, TranslationServer::get_singleton()->get_locale_name(locale));
t2->set_editable(1, true);
t2->set_metadata(1, path);
- int idx = langs.find(locale);
- if (idx < 0) {
- idx = 0;
- }
-
- int f_idx = translation_locales_idxs_remap.find(idx);
- if (f_idx != -1 && fl_idx_count > 0 && filter_mode == SHOW_ONLY_SELECTED_LOCALES) {
- t2->set_range(1, f_idx);
- } else {
- t2->set_range(1, idx);
- }
+ t2->set_tooltip(1, locale);
}
}
}
@@ -637,9 +472,6 @@ LocalizationEditor::LocalizationEditor() {
updating_translations = false;
localization_changed = "localization_changed";
- translation_locales_idxs_remap = Vector<int>();
- translation_locales_list_created = false;
-
TabContainer *translations = memnew(TabContainer);
translations->set_tab_alignment(TabContainer::ALIGNMENT_LEFT);
translations->set_v_size_flags(Control::SIZE_EXPAND_FILL);
@@ -669,6 +501,10 @@ LocalizationEditor::LocalizationEditor() {
translation_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
tmc->add_child(translation_list);
+ locale_select = memnew(EditorLocaleDialog);
+ locale_select->connect("locale_selected", callable_mp(this, &LocalizationEditor::_translation_res_option_selected));
+ add_child(locale_select);
+
translation_file_open = memnew(EditorFileDialog);
translation_file_open->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILES);
translation_file_open->connect("files_selected", callable_mp(this, &LocalizationEditor::_translation_add));
@@ -731,10 +567,11 @@ LocalizationEditor::LocalizationEditor() {
translation_remap_options->set_column_expand(0, true);
translation_remap_options->set_column_clip_content(0, true);
translation_remap_options->set_column_expand(1, false);
- translation_remap_options->set_column_clip_content(1, true);
- translation_remap_options->set_column_custom_minimum_width(1, 200);
+ translation_remap_options->set_column_clip_content(1, false);
+ translation_remap_options->set_column_custom_minimum_width(1, 250);
translation_remap_options->connect("item_edited", callable_mp(this, &LocalizationEditor::_translation_res_option_changed));
translation_remap_options->connect("button_pressed", callable_mp(this, &LocalizationEditor::_translation_res_option_delete));
+ translation_remap_options->connect("custom_popup_edited", callable_mp(this, &LocalizationEditor::_translation_res_option_popup));
tmc->add_child(translation_remap_options);
translation_res_option_file_open_dialog = memnew(EditorFileDialog);
@@ -745,32 +582,6 @@ LocalizationEditor::LocalizationEditor() {
{
VBoxContainer *tvb = memnew(VBoxContainer);
- tvb->set_name(TTR("Locales Filter"));
- translations->add_child(tvb);
-
- VBoxContainer *tmc = memnew(VBoxContainer);
- tmc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- tvb->add_child(tmc);
-
- translation_locale_filter_mode = memnew(OptionButton);
- translation_locale_filter_mode->add_item(TTR("Show All Locales"), SHOW_ALL_LOCALES);
- translation_locale_filter_mode->add_item(TTR("Show Selected Locales Only"), SHOW_ONLY_SELECTED_LOCALES);
- translation_locale_filter_mode->select(0);
- translation_locale_filter_mode->connect("item_selected", callable_mp(this, &LocalizationEditor::_translation_filter_mode_changed));
- tmc->add_margin_child(TTR("Filter mode:"), translation_locale_filter_mode);
-
- Label *l = memnew(Label(TTR("Locales:")));
- l->set_theme_type_variation("HeaderSmall");
- tmc->add_child(l);
- translation_filter = memnew(Tree);
- translation_filter->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- translation_filter->set_columns(1);
- translation_filter->connect("item_edited", callable_mp(this, &LocalizationEditor::_translation_filter_option_changed));
- tmc->add_child(translation_filter);
- }
-
- {
- VBoxContainer *tvb = memnew(VBoxContainer);
tvb->set_name(TTR("POT Generation"));
translations->add_child(tvb);
diff --git a/editor/localization_editor.h b/editor/localization_editor.h
index 4c77aca397..cad07dd336 100644
--- a/editor/localization_editor.h
+++ b/editor/localization_editor.h
@@ -33,18 +33,15 @@
#include "core/object/undo_redo.h"
#include "editor_file_dialog.h"
+#include "editor_locale_dialog.h"
#include "scene/gui/tree.h"
class LocalizationEditor : public VBoxContainer {
GDCLASS(LocalizationEditor, VBoxContainer);
- enum LocaleFilter {
- SHOW_ALL_LOCALES,
- SHOW_ONLY_SELECTED_LOCALES,
- };
-
Tree *translation_list;
+ EditorLocaleDialog *locale_select;
EditorFileDialog *translation_file_open;
Button *translation_res_option_add_button;
@@ -52,11 +49,6 @@ class LocalizationEditor : public VBoxContainer {
EditorFileDialog *translation_res_option_file_open_dialog;
Tree *translation_remap;
Tree *translation_remap_options;
- Tree *translation_filter;
- bool translation_locales_list_created;
- OptionButton *translation_locale_filter_mode;
- Vector<TreeItem *> translation_filter_treeitems;
- Vector<int> translation_locales_idxs_remap;
Tree *translation_pot_list;
EditorFileDialog *pot_file_open_dialog;
@@ -78,9 +70,8 @@ class LocalizationEditor : public VBoxContainer {
void _translation_res_option_add(const PackedStringArray &p_paths);
void _translation_res_option_changed();
void _translation_res_option_delete(Object *p_item, int p_column, int p_button);
-
- void _translation_filter_option_changed();
- void _translation_filter_mode_changed(int p_mode);
+ void _translation_res_option_popup(bool p_arrow_clicked);
+ void _translation_res_option_selected(const String &p_locale);
void _pot_add(const PackedStringArray &p_paths);
void _pot_delete(Object *p_item, int p_column, int p_button);
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 31ef13a2eb..5fb3040b75 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -369,11 +369,11 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int
download_error->set_text(TTR("Asset Download Error:") + "\n" + error_text);
download_error->popup_centered();
// Let the user retry the download.
- retry->show();
+ retry_button->show();
return;
}
- install->set_disabled(false);
+ install_button->set_disabled(false);
status->set_text(TTR("Success!"));
// Make the progress bar invisible but don't reflow other Controls around it.
progress->set_modulate(Color(0, 0, 0, 0));
@@ -381,7 +381,7 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int
set_process(false);
// Automatically prompt for installation once the download is completed.
- _install();
+ install();
}
void EditorAssetLibraryItemDownload::configure(const String &p_title, int p_asset_id, const Ref<Texture2D> &p_preview, const String &p_download_url, const String &p_sha256_hash) {
@@ -400,8 +400,9 @@ void EditorAssetLibraryItemDownload::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
- dismiss->set_normal_texture(get_theme_icon(SNAME("Close"), SNAME("EditorIcons")));
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("AssetLib")));
+ status->add_theme_color_override("font_color", get_theme_color(SNAME("status_color"), SNAME("AssetLib")));
+ dismiss_button->set_normal_texture(get_theme_icon(SNAME("dismiss"), SNAME("AssetLib")));
} break;
case NOTIFICATION_PROCESS: {
// Make the progress bar visible again when retrying the download.
@@ -461,7 +462,7 @@ void EditorAssetLibraryItemDownload::_close() {
queue_delete();
}
-void EditorAssetLibraryItemDownload::_install() {
+void EditorAssetLibraryItemDownload::install() {
String file = download->get_download_file();
if (external_install) {
@@ -475,7 +476,7 @@ void EditorAssetLibraryItemDownload::_install() {
void EditorAssetLibraryItemDownload::_make_request() {
// Hide the Retry button if we've just pressed it.
- retry->hide();
+ retry_button->hide();
download->cancel_request();
download->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_asset_" + itos(asset_id)) + ".zip");
@@ -499,6 +500,8 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() {
HBoxContainer *hb = memnew(HBoxContainer);
panel->add_child(hb);
icon = memnew(TextureRect);
+ icon->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
+ icon->set_v_size_flags(0);
hb->add_child(icon);
VBoxContainer *vb = memnew(VBoxContainer);
@@ -511,9 +514,9 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() {
title_hb->add_child(title);
title->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- dismiss = memnew(TextureButton);
- dismiss->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::_close));
- title_hb->add_child(dismiss);
+ dismiss_button = memnew(TextureButton);
+ dismiss_button->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::_close));
+ title_hb->add_child(dismiss_button);
title->set_clip_text(true);
@@ -521,7 +524,6 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() {
status = memnew(Label(TTR("Idle")));
vb->add_child(status);
- status->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5));
progress = memnew(ProgressBar);
vb->add_child(progress);
@@ -529,19 +531,19 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() {
vb->add_child(hb2);
hb2->add_spacer();
- install = memnew(Button);
- install->set_text(TTR("Install..."));
- install->set_disabled(true);
- install->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::_install));
+ install_button = memnew(Button);
+ install_button->set_text(TTR("Install..."));
+ install_button->set_disabled(true);
+ install_button->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::install));
- retry = memnew(Button);
- retry->set_text(TTR("Retry"));
- retry->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::_make_request));
+ retry_button = memnew(Button);
+ retry_button->set_text(TTR("Retry"));
+ retry_button->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::_make_request));
// Only show the Retry button in case of a failure.
- retry->hide();
+ retry_button->hide();
- hb2->add_child(retry);
- hb2->add_child(install);
+ hb2->add_child(retry_button);
+ hb2->add_child(install_button);
set_custom_minimum_size(Size2(310, 0) * EDSCALE);
download = memnew(HTTPRequest);
@@ -640,14 +642,10 @@ void EditorAssetLibrary::unhandled_key_input(const Ref<InputEvent> &p_event) {
void EditorAssetLibrary::_install_asset() {
ERR_FAIL_COND(!description);
- for (int i = 0; i < downloads_hb->get_child_count(); i++) {
- EditorAssetLibraryItemDownload *d = Object::cast_to<EditorAssetLibraryItemDownload>(downloads_hb->get_child(i));
- if (d && d->get_asset_id() == description->get_asset_id()) {
- if (EditorNode::get_singleton() != nullptr) {
- EditorNode::get_singleton()->show_warning(TTR("Download for this asset is already in progress!"));
- }
- return;
- }
+ EditorAssetLibraryItemDownload *d = _get_asset_in_progress(description->get_asset_id());
+ if (d) {
+ d->install();
+ return;
}
EditorAssetLibraryItemDownload *download = memnew(EditorAssetLibraryItemDownload);
@@ -1265,6 +1263,13 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
description->configure(r["title"], r["asset_id"], category_map[r["category_id"]], r["category_id"], r["author"], r["author_id"], r["cost"], r["version"], r["version_string"], r["description"], r["download_url"], r["browse_url"], r["download_hash"]);
+ EditorAssetLibraryItemDownload *download_item = _get_asset_in_progress(description->get_asset_id());
+ if (download_item) {
+ description->get_ok_button()->set_text(TTR("Install"));
+ } else {
+ description->get_ok_button()->set_text(TTR("Download"));
+ }
+
if (r.has("icon_url") && !r["icon_url"].operator String().is_empty()) {
_request_image(description->get_instance_id(), r["icon_url"], IMAGE_QUEUE_ICON, 0);
}
@@ -1322,6 +1327,17 @@ void EditorAssetLibrary::_manage_plugins() {
ProjectSettingsEditor::get_singleton()->set_plugins_page();
}
+EditorAssetLibraryItemDownload *EditorAssetLibrary::_get_asset_in_progress(int p_asset_id) const {
+ for (int i = 0; i < downloads_hb->get_child_count(); i++) {
+ EditorAssetLibraryItemDownload *d = Object::cast_to<EditorAssetLibraryItemDownload>(downloads_hb->get_child(i));
+ if (d && d->get_asset_id() == p_asset_id) {
+ return d;
+ }
+ }
+
+ return nullptr;
+}
+
void EditorAssetLibrary::_install_external_asset(String p_zip_path, String p_title) {
emit_signal(SNAME("install_asset"), p_zip_path, p_title);
}
diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h
index 8d6c0eb76e..058aafc221 100644
--- a/editor/plugins/asset_library_editor_plugin.h
+++ b/editor/plugins/asset_library_editor_plugin.h
@@ -39,6 +39,7 @@
#include "scene/gui/grid_container.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/link_button.h"
+#include "scene/gui/margin_container.h"
#include "scene/gui/option_button.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/progress_bar.h"
@@ -126,16 +127,16 @@ public:
EditorAssetLibraryItemDescription();
};
-class EditorAssetLibraryItemDownload : public Control {
- GDCLASS(EditorAssetLibraryItemDownload, Control);
+class EditorAssetLibraryItemDownload : public MarginContainer {
+ GDCLASS(EditorAssetLibraryItemDownload, MarginContainer);
PanelContainer *panel;
TextureRect *icon;
Label *title;
ProgressBar *progress;
- Button *install;
- Button *retry;
- TextureButton *dismiss;
+ Button *install_button;
+ Button *retry_button;
+ TextureButton *dismiss_button;
AcceptDialog *download_error;
HTTPRequest *download;
@@ -152,7 +153,6 @@ class EditorAssetLibraryItemDownload : public Control {
EditorAssetInstaller *asset_installer;
void _close();
- void _install();
void _make_request();
void _http_download_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data);
@@ -164,6 +164,7 @@ public:
void set_external_install(bool p_enable) { external_install = p_enable; }
int get_asset_id() { return asset_id; }
void configure(const String &p_title, int p_asset_id, const Ref<Texture2D> &p_preview, const String &p_download_url, const String &p_sha256_hash);
+ void install();
EditorAssetLibraryItemDownload();
};
@@ -287,6 +288,7 @@ class EditorAssetLibrary : public PanelContainer {
void _api_request(const String &p_request, RequestType p_request_type, const String &p_arguments = "");
void _http_request_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data);
void _filter_debounce_timer_timeout();
+ EditorAssetLibraryItemDownload *_get_asset_in_progress(int p_asset_id) const;
void _repository_changed(int p_repository_id);
void _support_toggled(int p_support);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index cb84e7ea65..14f488f096 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -3517,7 +3517,7 @@ void CanvasItemEditor::_draw_axis() {
Color area_axis_color = EditorSettings::get_singleton()->get("editors/2d/viewport_border_color");
- Size2 screen_size = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
+ Size2 screen_size = Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
Vector2 screen_endpoints[4] = {
transform.xform(Vector2(0, 0)),
@@ -4010,7 +4010,7 @@ void CanvasItemEditor::_update_scrollbars() {
Size2 vmin = v_scroll->get_minimum_size();
// Get the visible frame.
- Size2 screen_rect = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
+ Size2 screen_rect = Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
Rect2 local_rect = Rect2(Point2(), viewport->get_size() - Size2(vmin.width, hmin.height));
// Calculate scrollable area.
@@ -5129,8 +5129,22 @@ void CanvasItemEditor::remove_control_from_menu_panel(Control *p_control) {
hbc_context_menu->remove_child(p_control);
}
-HSplitContainer *CanvasItemEditor::get_palette_split() {
- return palette_split;
+void CanvasItemEditor::add_control_to_left_panel(Control *p_control) {
+ left_panel_split->add_child(p_control);
+ left_panel_split->move_child(p_control, 0);
+}
+
+void CanvasItemEditor::add_control_to_right_panel(Control *p_control) {
+ right_panel_split->add_child(p_control);
+ right_panel_split->move_child(p_control, 1);
+}
+
+void CanvasItemEditor::remove_control_from_left_panel(Control *p_control) {
+ left_panel_split->remove_child(p_control);
+}
+
+void CanvasItemEditor::remove_control_from_right_panel(Control *p_control) {
+ right_panel_split->remove_child(p_control);
}
VSplitContainer *CanvasItemEditor::get_bottom_split() {
@@ -5221,12 +5235,16 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
add_child(bottom_split);
bottom_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- palette_split = memnew(HSplitContainer);
- bottom_split->add_child(palette_split);
- palette_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ left_panel_split = memnew(HSplitContainer);
+ bottom_split->add_child(left_panel_split);
+ left_panel_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+
+ right_panel_split = memnew(HSplitContainer);
+ left_panel_split->add_child(right_panel_split);
+ right_panel_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
viewport_scrollable = memnew(Control);
- palette_split->add_child(viewport_scrollable);
+ right_panel_split->add_child(viewport_scrollable);
viewport_scrollable->set_mouse_filter(MOUSE_FILTER_PASS);
viewport_scrollable->set_clip_contents(true);
viewport_scrollable->set_v_size_flags(Control::SIZE_EXPAND_FILL);
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 8bba5130d4..d58fb17356 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -527,7 +527,8 @@ private:
void _update_override_camera_button(bool p_game_running);
- HSplitContainer *palette_split;
+ HSplitContainer *left_panel_split;
+ HSplitContainer *right_panel_split;
VSplitContainer *bottom_split;
void _update_context_menu_stylebox();
@@ -571,7 +572,12 @@ public:
void add_control_to_menu_panel(Control *p_control);
void remove_control_from_menu_panel(Control *p_control);
- HSplitContainer *get_palette_split();
+ void add_control_to_left_panel(Control *p_control);
+ void remove_control_from_left_panel(Control *p_control);
+
+ void add_control_to_right_panel(Control *p_control);
+ void remove_control_from_right_panel(Control *p_control);
+
VSplitContainer *get_bottom_split();
Control *get_viewport_control() { return viewport; }
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 6ea8fba9b5..20f86c6a81 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -3064,7 +3064,7 @@ void Node3DEditorViewport::_draw() {
Math::round(2 * EDSCALE));
}
if (previewing) {
- Size2 ss = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
+ Size2 ss = Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
float aspect = ss.aspect();
Size2 s = get_size();
@@ -6880,8 +6880,46 @@ VSplitContainer *Node3DEditor::get_shader_split() {
return shader_split;
}
-HSplitContainer *Node3DEditor::get_palette_split() {
- return palette_split;
+void Node3DEditor::add_control_to_left_panel(Control *p_control) {
+ left_panel_split->add_child(p_control);
+ left_panel_split->move_child(p_control, 0);
+}
+
+void Node3DEditor::add_control_to_right_panel(Control *p_control) {
+ right_panel_split->add_child(p_control);
+ right_panel_split->move_child(p_control, 1);
+}
+
+void Node3DEditor::remove_control_from_left_panel(Control *p_control) {
+ left_panel_split->remove_child(p_control);
+}
+
+void Node3DEditor::remove_control_from_right_panel(Control *p_control) {
+ right_panel_split->remove_child(p_control);
+}
+
+void Node3DEditor::move_control_to_left_panel(Control *p_control) {
+ ERR_FAIL_NULL(p_control);
+ if (p_control->get_parent() == left_panel_split) {
+ return;
+ }
+
+ ERR_FAIL_COND(p_control->get_parent() != right_panel_split);
+ right_panel_split->remove_child(p_control);
+
+ add_control_to_left_panel(p_control);
+}
+
+void Node3DEditor::move_control_to_right_panel(Control *p_control) {
+ ERR_FAIL_NULL(p_control);
+ if (p_control->get_parent() == right_panel_split) {
+ return;
+ }
+
+ ERR_FAIL_COND(p_control->get_parent() != left_panel_split);
+ left_panel_split->remove_child(p_control);
+
+ add_control_to_right_panel(p_control);
}
void Node3DEditor::_request_gizmo(Object *p_obj) {
@@ -7534,13 +7572,17 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
/* REST OF MENU */
- palette_split = memnew(HSplitContainer);
- palette_split->set_v_size_flags(SIZE_EXPAND_FILL);
- vbc->add_child(palette_split);
+ left_panel_split = memnew(HSplitContainer);
+ left_panel_split->set_v_size_flags(SIZE_EXPAND_FILL);
+ vbc->add_child(left_panel_split);
+
+ right_panel_split = memnew(HSplitContainer);
+ right_panel_split->set_v_size_flags(SIZE_EXPAND_FILL);
+ left_panel_split->add_child(right_panel_split);
shader_split = memnew(VSplitContainer);
shader_split->set_h_size_flags(SIZE_EXPAND_FILL);
- palette_split->add_child(shader_split);
+ right_panel_split->add_child(shader_split);
viewport_base = memnew(Node3DEditorViewportContainer);
shader_split->add_child(viewport_base);
viewport_base->set_v_size_flags(SIZE_EXPAND_FILL);
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index da560f4d83..20a782c8a8 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -527,7 +527,8 @@ private:
Node3DEditorViewportContainer *viewport_base;
Node3DEditorViewport *viewports[VIEWPORTS_COUNT];
VSplitContainer *shader_split;
- HSplitContainer *palette_split;
+ HSplitContainer *left_panel_split;
+ HSplitContainer *right_panel_split;
/////
@@ -801,8 +802,16 @@ public:
void add_control_to_menu_panel(Control *p_control);
void remove_control_from_menu_panel(Control *p_control);
+ void add_control_to_left_panel(Control *p_control);
+ void remove_control_from_left_panel(Control *p_control);
+
+ void add_control_to_right_panel(Control *p_control);
+ void remove_control_from_right_panel(Control *p_control);
+
+ void move_control_to_left_panel(Control *p_control);
+ void move_control_to_right_panel(Control *p_control);
+
VSplitContainer *get_shader_split();
- HSplitContainer *get_palette_split();
Node3D *get_single_selected_node() { return selected; }
bool is_current_selected_gizmo(const EditorNode3DGizmo *p_gizmo);
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index 481ff1a781..c971bb6473 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -506,12 +506,16 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
} break;
case Variant::STRING: {
- if (hint == PROPERTY_HINT_FILE || hint == PROPERTY_HINT_GLOBAL_FILE) {
+ if (hint == PROPERTY_HINT_LOCALE_ID) {
+ List<String> names;
+ names.push_back(TTR("Locale..."));
+ names.push_back(TTR("Clear"));
+ config_action_buttons(names);
+ } else if (hint == PROPERTY_HINT_FILE || hint == PROPERTY_HINT_GLOBAL_FILE) {
List<String> names;
names.push_back(TTR("File..."));
names.push_back(TTR("Clear"));
config_action_buttons(names);
-
} else if (hint == PROPERTY_HINT_DIR || hint == PROPERTY_HINT_GLOBAL_DIR) {
List<String> names;
names.push_back(TTR("Dir..."));
@@ -1034,6 +1038,14 @@ void CustomPropertyEditor::_file_selected(String p_file) {
}
}
+void CustomPropertyEditor::_locale_selected(String p_locale) {
+ if (type == Variant::STRING && hint == PROPERTY_HINT_LOCALE_ID) {
+ v = p_locale;
+ emit_signal(SNAME("variant_changed"));
+ hide();
+ }
+}
+
void CustomPropertyEditor::_type_create_selected(int p_idx) {
if (type == Variant::INT || type == Variant::FLOAT) {
float newval = 0;
@@ -1177,7 +1189,8 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
case Variant::STRING: {
if (hint == PROPERTY_HINT_MULTILINE_TEXT) {
hide();
-
+ } else if (hint == PROPERTY_HINT_LOCALE_ID) {
+ locale->popup_locale_dialog();
} else if (hint == PROPERTY_HINT_FILE || hint == PROPERTY_HINT_GLOBAL_FILE) {
if (p_which == 0) {
if (hint == PROPERTY_HINT_FILE) {
@@ -1821,6 +1834,12 @@ CustomPropertyEditor::CustomPropertyEditor() {
file->connect("file_selected", callable_mp(this, &CustomPropertyEditor::_file_selected));
file->connect("dir_selected", callable_mp(this, &CustomPropertyEditor::_file_selected));
+ locale = memnew(EditorLocaleDialog);
+ value_vbox->add_child(locale);
+ locale->hide();
+
+ locale->connect("locale_selected", callable_mp(this, &CustomPropertyEditor::_locale_selected));
+
error = memnew(ConfirmationDialog);
error->set_title(TTR("Error!"));
value_vbox->add_child(error);
diff --git a/editor/property_editor.h b/editor/property_editor.h
index 9d88aaf26d..298acb3c01 100644
--- a/editor/property_editor.h
+++ b/editor/property_editor.h
@@ -32,6 +32,7 @@
#define PROPERTY_EDITOR_H
#include "editor/editor_file_dialog.h"
+#include "editor/editor_locale_dialog.h"
#include "editor/scene_tree_editor.h"
#include "scene/gui/button.h"
#include "scene/gui/check_box.h"
@@ -97,6 +98,7 @@ class CustomPropertyEditor : public PopupPanel {
PopupMenu *menu;
SceneTreeDialog *scene_tree;
EditorFileDialog *file;
+ EditorLocaleDialog *locale;
ConfirmationDialog *error;
String name;
Variant::Type type;
@@ -136,6 +138,7 @@ class CustomPropertyEditor : public PopupPanel {
void _text_edit_changed();
void _file_selected(String p_file);
+ void _locale_selected(String p_locale);
void _modified(String p_string);
real_t _parse_real_expression(String text);
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 2e72b17651..c9acb7b668 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -361,8 +361,12 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
tree->edit_selected();
}
} break;
- case TOOL_NEW:
- case TOOL_REPARENT_TO_NEW_NODE: {
+ case TOOL_REPARENT_TO_NEW_NODE:
+ if (!_validate_no_foreign()) {
+ break;
+ }
+ [[fallthrough]];
+ case TOOL_NEW: {
if (!profile_allow_editing) {
break;
}
@@ -441,8 +445,11 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
+ bool was_empty = false;
if (!node_clipboard.is_empty()) {
_clear_clipboard();
+ } else {
+ was_empty = true;
}
clipboard_source_scene = editor->get_edited_scene()->get_scene_file_path();
@@ -460,81 +467,13 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (p_tool == TOOL_CUT) {
_delete_confirm(true);
}
- } break;
- case TOOL_PASTE: {
- if (node_clipboard.is_empty() || !edited_scene) {
- break;
- }
-
- bool has_cycle = false;
- if (!edited_scene->get_scene_file_path().is_empty()) {
- for (Node *E : node_clipboard) {
- if (edited_scene->get_scene_file_path() == E->get_scene_file_path()) {
- has_cycle = true;
- break;
- }
- }
- }
-
- if (has_cycle) {
- current_option = -1;
- accept->set_text(TTR("Can't paste root node into the same scene."));
- accept->popup_centered();
- break;
- }
-
- Node *paste_parent = edited_scene;
- List<Node *> selection = editor_selection->get_selected_node_list();
- if (selection.size() > 0) {
- paste_parent = selection.back()->get();
- }
-
- Node *owner = paste_parent->get_owner();
- if (!owner) {
- owner = paste_parent;
- }
- editor_data->get_undo_redo().create_action(TTR("Paste Node(s)"));
- editor_data->get_undo_redo().add_do_method(editor_selection, "clear");
-
- Map<RES, RES> resource_remap;
- String target_scene = editor->get_edited_scene()->get_scene_file_path();
- if (target_scene != clipboard_source_scene) {
- if (!clipboard_resource_remap.has(target_scene)) {
- Map<RES, RES> remap;
- for (Node *E : node_clipboard) {
- _create_remap_for_node(E, remap);
- }
- clipboard_resource_remap[target_scene] = remap;
- }
- resource_remap = clipboard_resource_remap[target_scene];
+ if (was_empty) {
+ _update_create_root_dialog();
}
-
- for (Node *node : node_clipboard) {
- Map<const Node *, Node *> duplimap;
-
- Node *dup = node->duplicate_from_editor(duplimap, resource_remap);
-
- ERR_CONTINUE(!dup);
-
- editor_data->get_undo_redo().add_do_method(paste_parent, "add_child", dup, true);
-
- for (KeyValue<const Node *, Node *> &E2 : duplimap) {
- Node *d = E2.value;
- editor_data->get_undo_redo().add_do_method(d, "set_owner", owner);
- }
-
- editor_data->get_undo_redo().add_do_method(dup, "set_owner", owner);
- editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", dup);
- editor_data->get_undo_redo().add_undo_method(paste_parent, "remove_child", dup);
- editor_data->get_undo_redo().add_do_reference(dup);
-
- if (node_clipboard.size() == 1) {
- editor_data->get_undo_redo().add_do_method(editor, "push_item", dup);
- }
- }
-
- editor_data->get_undo_redo().commit_action();
+ } break;
+ case TOOL_PASTE: {
+ paste_nodes();
} break;
case TOOL_REPLACE: {
if (!profile_allow_editing) {
@@ -1302,6 +1241,12 @@ void SceneTreeDock::_notification(int p_what) {
button_custom->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
button_custom->connect("pressed", callable_bind(callable_mp(this, &SceneTreeDock::_tool_selected), TOOL_NEW, false));
+ button_clipboard = memnew(Button);
+ node_shortcuts->add_child(button_clipboard);
+ button_clipboard->set_text(TTR("Paste From Clipboard"));
+ button_clipboard->set_icon(get_theme_icon(SNAME("ActionPaste"), SNAME("EditorIcons")));
+ button_clipboard->connect("pressed", callable_bind(callable_mp(this, &SceneTreeDock::_tool_selected), TOOL_PASTE, false));
+
node_shortcuts->add_spacer();
create_root_dialog->add_child(node_shortcuts);
_update_create_root_dialog();
@@ -1326,6 +1271,7 @@ void SceneTreeDock::_notification(int p_what) {
button_3d->set_icon(get_theme_icon(SNAME("Node3D"), SNAME("EditorIcons")));
button_ui->set_icon(get_theme_icon(SNAME("Control"), SNAME("EditorIcons")));
button_custom->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
+ button_clipboard->set_icon(get_theme_icon(SNAME("ActionPaste"), SNAME("EditorIcons")));
filter->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
filter->set_clear_button_enabled(true);
@@ -2621,6 +2567,10 @@ void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) {
}
void SceneTreeDock::_nodes_dragged(Array p_nodes, NodePath p_to, int p_type) {
+ if (!_validate_no_foreign()) {
+ return;
+ }
+
List<Node *> selection = editor_selection->get_selected_node_list();
if (selection.is_empty()) {
@@ -2732,10 +2682,10 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
}
if (profile_allow_editing) {
- menu->add_shortcut(ED_GET_SHORTCUT("scene_tree/cut_node"), TOOL_CUT);
- menu->add_shortcut(ED_GET_SHORTCUT("scene_tree/copy_node"), TOOL_COPY);
+ menu->add_icon_shortcut(get_theme_icon(SNAME("ActionCut"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/cut_node"), TOOL_CUT);
+ menu->add_icon_shortcut(get_theme_icon(SNAME("ActionCopy"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/copy_node"), TOOL_COPY);
if (selection.size() == 1 && !node_clipboard.is_empty()) {
- menu->add_shortcut(ED_GET_SHORTCUT("scene_tree/paste_node"), TOOL_PASTE);
+ menu->add_icon_shortcut(get_theme_icon(SNAME("ActionPaste"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/paste_node"), TOOL_PASTE);
}
menu->add_separator();
}
@@ -3014,6 +2964,108 @@ void SceneTreeDock::open_instance_child_dialog() {
_tool_selected(TOOL_INSTANTIATE, true);
}
+List<Node *> SceneTreeDock::paste_nodes() {
+ List<Node *> pasted_nodes;
+
+ if (node_clipboard.is_empty()) {
+ return pasted_nodes;
+ }
+
+ bool has_cycle = false;
+ if (edited_scene && !edited_scene->get_scene_file_path().is_empty()) {
+ for (Node *E : node_clipboard) {
+ if (edited_scene->get_scene_file_path() == E->get_scene_file_path()) {
+ has_cycle = true;
+ break;
+ }
+ }
+ }
+
+ if (has_cycle) {
+ current_option = -1;
+ accept->set_text(TTR("Can't paste root node into the same scene."));
+ accept->popup_centered();
+ return pasted_nodes;
+ }
+
+ Node *paste_parent = edited_scene;
+ List<Node *> selection = editor_selection->get_selected_node_list();
+ if (selection.size() > 0) {
+ paste_parent = selection.back()->get();
+ }
+
+ Node *owner = nullptr;
+ if (paste_parent) {
+ owner = paste_parent->get_owner();
+ }
+ if (!owner) {
+ owner = paste_parent;
+ }
+
+ UndoRedo &ur = editor_data->get_undo_redo();
+ ur.create_action(TTR("Paste Node(s)"));
+ ur.add_do_method(editor_selection, "clear");
+
+ Map<RES, RES> resource_remap;
+ String target_scene;
+ if (edited_scene) {
+ target_scene = edited_scene->get_scene_file_path();
+ }
+ if (target_scene != clipboard_source_scene) {
+ if (!clipboard_resource_remap.has(target_scene)) {
+ Map<RES, RES> remap;
+ for (Node *E : node_clipboard) {
+ _create_remap_for_node(E, remap);
+ }
+ clipboard_resource_remap[target_scene] = remap;
+ }
+ resource_remap = clipboard_resource_remap[target_scene];
+ }
+
+ for (Node *node : node_clipboard) {
+ Map<const Node *, Node *> duplimap;
+
+ Node *dup = node->duplicate_from_editor(duplimap, resource_remap);
+ ERR_CONTINUE(!dup);
+
+ pasted_nodes.push_back(dup);
+
+ if (!paste_parent) {
+ paste_parent = dup;
+ owner = dup;
+ ur.add_do_method(editor, "set_edited_scene", dup);
+ } else {
+ ur.add_do_method(paste_parent, "add_child", dup, true);
+ }
+
+ for (KeyValue<const Node *, Node *> &E2 : duplimap) {
+ Node *d = E2.value;
+ if (d != dup) {
+ ur.add_do_method(d, "set_owner", owner);
+ }
+ }
+
+ if (dup != owner) {
+ ur.add_do_method(dup, "set_owner", owner);
+ }
+ ur.add_do_method(editor_selection, "add_node", dup);
+
+ if (dup == paste_parent) {
+ ur.add_undo_method(editor, "set_edited_scene", (Object *)nullptr);
+ } else {
+ ur.add_undo_method(paste_parent, "remove_child", dup);
+ }
+ ur.add_do_reference(dup);
+
+ if (node_clipboard.size() == 1) {
+ ur.add_do_method(editor, "push_item", dup);
+ }
+ }
+
+ ur.commit_action();
+ return pasted_nodes;
+}
+
void SceneTreeDock::add_remote_tree_editor(Control *p_remote) {
ERR_FAIL_COND(remote_tree != nullptr);
add_child(p_remote);
@@ -3113,6 +3165,7 @@ void SceneTreeDock::_update_create_root_dialog() {
beginner_nodes->show();
favorite_nodes->hide();
}
+ button_clipboard->set_visible(!node_clipboard.is_empty());
}
}
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index ffaf34cfdc..f442d3fc6b 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -123,6 +123,7 @@ class SceneTreeDock : public VBoxContainer {
Button *button_3d;
Button *button_ui;
Button *button_custom;
+ Button *button_clipboard;
HBoxContainer *button_hb;
Button *edit_local, *edit_remote;
@@ -308,6 +309,8 @@ public:
void open_add_child_dialog();
void open_instance_child_dialog();
+ List<Node *> paste_nodes();
+
ScriptCreateDialog *get_script_create_dialog() { return script_create_dialog; }
SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSelection *p_editor_selection, EditorData &p_editor_data);