diff options
Diffstat (limited to 'editor')
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); |