diff options
author | Rémi Verschelde <remi@verschelde.fr> | 2022-07-07 12:22:49 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-07 12:22:49 +0200 |
commit | 1e553e34fbc74e16fbecc59406c97e3a0f4a5698 (patch) | |
tree | 7d78357fcb55f776ebb5ff9ee72139bc2ea27198 /editor | |
parent | bc419e1c5ee3a0cd8c4156b2e65d94f6f46c7543 (diff) | |
parent | 344ba0ffaf3f7d39bd5a1304ba6a6070d442a963 (diff) |
Merge pull request #62108 from bruvzg/font_config_v3
Diffstat (limited to 'editor')
40 files changed, 1983 insertions, 2619 deletions
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index e612130041..500a3df127 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -1577,10 +1577,10 @@ void AnimationTimelineEdit::_notification(int p_what) { int decimals = 2; bool step_found = false; - const float period_width = font->get_char_size('.', 0, font_size).width; - float max_digit_width = font->get_char_size('0', 0, font_size).width; + const float period_width = font->get_char_size('.', font_size).width; + float max_digit_width = font->get_char_size('0', font_size).width; for (int i = 1; i <= 9; i++) { - const float digit_width = font->get_char_size('0' + i, 0, font_size).width; + const float digit_width = font->get_char_size('0' + i, font_size).width; max_digit_width = MAX(digit_width, max_digit_width); } const int max_sc = int(Math::ceil(zoomw / scale)); @@ -1628,7 +1628,7 @@ void AnimationTimelineEdit::_notification(int p_what) { draw_line(Point2(get_name_limit() + i, 0), Point2(get_name_limit() + i, h), linecolor, Math::round(EDSCALE)); draw_string(font, Point2(get_name_limit() + i + 3 * EDSCALE, (h - font->get_height(font_size)) / 2 + font->get_ascent(font_size)).floor(), itos(frame), HORIZONTAL_ALIGNMENT_LEFT, zoomw - i, font_size, sub ? color_time_dec : color_time_sec); - prev_frame_ofs = i + font->get_string_size(itos(frame), font_size).x + 5 * EDSCALE; + prev_frame_ofs = i + font->get_string_size(itos(frame), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x + 5 * EDSCALE; } } } diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 272de725c8..73059464be 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1636,31 +1636,39 @@ void CodeTextEditor::_apply_settings_change() { _update_text_editor_theme(); font_size = EditorSettings::get_singleton()->get("interface/editor/code_font_size"); - int ot_mode = EditorSettings::get_singleton()->get("interface/editor/code_font_contextual_ligatures"); + + Ref<Font> fb = text_editor->get_theme_font(SNAME("font")); + Ref<FontVariation> fc = fb; + if (fc.is_null()) { + fc.instantiate(); + fc->set_base_font(fb); + } + switch (ot_mode) { case 1: { // Disable ligatures. - text_editor->clear_opentype_features(); - text_editor->set_opentype_feature("calt", 0); + fc->set_opentype_features(Dictionary()); } break; case 2: { // Custom. - text_editor->clear_opentype_features(); Vector<String> subtag = String(EditorSettings::get_singleton()->get("interface/editor/code_font_custom_opentype_features")).split(","); Dictionary ftrs; for (int i = 0; i < subtag.size(); i++) { Vector<String> subtag_a = subtag[i].split("="); if (subtag_a.size() == 2) { - text_editor->set_opentype_feature(subtag_a[0], subtag_a[1].to_int()); + ftrs[TS->name_to_tag(subtag_a[0])] = subtag_a[1].to_int(); } else if (subtag_a.size() == 1) { - text_editor->set_opentype_feature(subtag_a[0], 1); + ftrs[TS->name_to_tag(subtag_a[0])] = 1; } } + fc->set_opentype_features(ftrs); } break; default: { // Default. - text_editor->clear_opentype_features(); - text_editor->set_opentype_feature("calt", 1); + Dictionary ftrs; + ftrs[TS->name_to_tag("calt")] = 1; + fc->set_opentype_features(ftrs); } break; } + text_editor->add_theme_font_override("font", fc); text_editor->set_code_hint_draw_below(EDITOR_GET("text_editor/completion/put_callhint_tooltip_below_current_line")); @@ -1862,29 +1870,36 @@ CodeTextEditor::CodeTextEditor() { text_editor->set_v_size_flags(SIZE_EXPAND_FILL); int ot_mode = EditorSettings::get_singleton()->get("interface/editor/code_font_contextual_ligatures"); + Ref<Font> fb = text_editor->get_theme_font(SNAME("font")); + Ref<FontVariation> fc = fb; + if (fc.is_null()) { + fc.instantiate(); + fc->set_base_font(fb); + } switch (ot_mode) { case 1: { // Disable ligatures. - text_editor->clear_opentype_features(); - text_editor->set_opentype_feature("calt", 0); + fc->set_opentype_features(Dictionary()); } break; case 2: { // Custom. - text_editor->clear_opentype_features(); Vector<String> subtag = String(EditorSettings::get_singleton()->get("interface/editor/code_font_custom_opentype_features")).split(","); Dictionary ftrs; for (int i = 0; i < subtag.size(); i++) { Vector<String> subtag_a = subtag[i].split("="); if (subtag_a.size() == 2) { - text_editor->set_opentype_feature(subtag_a[0], subtag_a[1].to_int()); + ftrs[TS->name_to_tag(subtag_a[0])] = subtag_a[1].to_int(); } else if (subtag_a.size() == 1) { - text_editor->set_opentype_feature(subtag_a[0], 1); + ftrs[TS->name_to_tag(subtag_a[0])] = 1; } } + fc->set_opentype_features(ftrs); } break; default: { // Default. - text_editor->clear_opentype_features(); - text_editor->set_opentype_feature("calt", 1); + Dictionary ftrs; + ftrs[TS->name_to_tag("calt")] = 1; + fc->set_opentype_features(ftrs); } break; } + text_editor->add_theme_font_override("font", fc); text_editor->set_draw_line_numbers(true); text_editor->set_highlight_matching_braces_enabled(true); diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp index 764e842539..50eef7b8b8 100644 --- a/editor/debugger/editor_performance_profiler.cpp +++ b/editor/debugger/editor_performance_profiler.cpp @@ -136,7 +136,7 @@ void EditorPerformanceProfiler::_monitor_draw() { monitor_draw->draw_string(graph_font, rect.position + Point2(0, graph_font->get_ascent(font_size)), current.item->get_text(0), HORIZONTAL_ALIGNMENT_LEFT, rect.size.x, font_size, draw_color); draw_color.a = 0.9f; - float value_position = rect.size.width - graph_font->get_string_size(current.item->get_text(1), font_size).width; + float value_position = rect.size.width - graph_font->get_string_size(current.item->get_text(1), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width; if (value_position < 0) { value_position = 0; } @@ -184,7 +184,7 @@ void EditorPerformanceProfiler::_monitor_draw() { monitor_draw->draw_line(rect.position + Point2(from, 0), rect.position + Point2(from, rect.size.y), line_color, Math::round(EDSCALE)); String label = _create_label(e->get(), current.type); - Size2 size = graph_font->get_string_size(label, font_size); + Size2 size = graph_font->get_string_size(label, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size); Vector2 text_top_left_position = Vector2(from, h2) - (size + Vector2(MARKER_MARGIN, MARKER_MARGIN)); if (text_top_left_position.x < 0) { text_top_left_position.x = from + MARKER_MARGIN; diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp index 9def646f3f..59482db674 100644 --- a/editor/debugger/editor_visual_profiler.cpp +++ b/editor/debugger/editor_visual_profiler.cpp @@ -469,7 +469,7 @@ void EditorVisualProfiler::_graph_tex_draw() { graph->draw_line(Vector2(0, frame_y), Vector2(half_width, frame_y), color * Color(1, 1, 1, 0.5)); const String limit_str = String::num(graph_limit, 2) + " ms"; - graph->draw_string(font, Vector2(half_width - font->get_string_size(limit_str, font_size).x - 2, frame_y - 2), limit_str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color * Color(1, 1, 1, 0.75)); + graph->draw_string(font, Vector2(half_width - font->get_string_size(limit_str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x - 2, frame_y - 2), limit_str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color * Color(1, 1, 1, 0.75)); } if (graph_height_gpu > 0) { @@ -480,11 +480,11 @@ void EditorVisualProfiler::_graph_tex_draw() { graph->draw_line(Vector2(half_width, frame_y), Vector2(graph->get_size().x, frame_y), color * Color(1, 1, 1, 0.5)); const String limit_str = String::num(graph_limit, 2) + " ms"; - graph->draw_string(font, Vector2(half_width * 2 - font->get_string_size(limit_str, font_size).x - 2, frame_y - 2), limit_str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color * Color(1, 1, 1, 0.75)); + graph->draw_string(font, Vector2(half_width * 2 - font->get_string_size(limit_str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x - 2, frame_y - 2), limit_str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color * Color(1, 1, 1, 0.75)); } - graph->draw_string(font, Vector2(font->get_string_size("X", font_size).x, font->get_ascent(font_size) + 2), "CPU:", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color * Color(1, 1, 1)); - graph->draw_string(font, Vector2(font->get_string_size("X", font_size).x + graph->get_size().width / 2, font->get_ascent(font_size) + 2), "GPU:", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color * Color(1, 1, 1)); + graph->draw_string(font, Vector2(font->get_string_size("X", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x, font->get_ascent(font_size) + 2), "CPU:", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color * Color(1, 1, 1)); + graph->draw_string(font, Vector2(font->get_string_size("X", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x + graph->get_size().width / 2, font->get_ascent(font_size) + 2), "GPU:", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color * Color(1, 1, 1)); } void EditorVisualProfiler::_graph_tex_mouse_exit() { diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index 89dc106717..fd121e73ab 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -1394,7 +1394,7 @@ Size2 EditorAudioMeterNotches::get_minimum_size() const { for (int i = 0; i < notches.size(); i++) { if (notches[i].render_db_value) { - width = MAX(width, font->get_string_size(String::num(Math::abs(notches[i].db_value)) + "dB", font_size).x); + width = MAX(width, font->get_string_size(String::num(Math::abs(notches[i].db_value)) + "dB", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x); height += font_height; } } diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp index 51d4d474c5..8deee57dc9 100644 --- a/editor/editor_fonts.cpp +++ b/editor/editor_fonts.cpp @@ -37,212 +37,8 @@ #include "scene/resources/default_theme/default_theme.h" #include "scene/resources/font.h" -#define MAKE_FALLBACKS(m_name) \ - m_name->add_data(FontArabic); \ - m_name->add_data(FontBengali); \ - m_name->add_data(FontDevanagari); \ - m_name->add_data(FontGeorgian); \ - m_name->add_data(FontHebrew); \ - m_name->add_data(FontMalayalam); \ - m_name->add_data(FontOriya); \ - m_name->add_data(FontSinhala); \ - m_name->add_data(FontTamil); \ - m_name->add_data(FontTelugu); \ - m_name->add_data(FontThai); \ - m_name->add_data(FontJapanese); \ - m_name->add_data(FontFallback); - -// Note: In some languages, the use of italic/slanted fonts is controversial. Therefore, we are limiting simulated slant to the main font (Latin, Cyrillic, and Greek) and using bold fonts for the rest. - -#define MAKE_FALLBACKS_SLANTED(m_name) \ - m_name->add_data(FontArabicBold); \ - m_name->add_data(FontBengaliBold); \ - m_name->add_data(FontDevanagariBold); \ - m_name->add_data(FontGeorgianBold); \ - m_name->add_data(FontHebrewBold); \ - m_name->add_data(FontMalayalamBold); \ - m_name->add_data(FontOriyaBold); \ - m_name->add_data(FontSinhalaBold); \ - m_name->add_data(FontTamilBold); \ - m_name->add_data(FontTeluguBold); \ - m_name->add_data(FontThaiBold); \ - m_name->add_data(FontJapaneseBold); \ - m_name->add_data(FontFallbackBold); - -#define MAKE_FALLBACKS_BOLD(m_name) \ - m_name->add_data(FontArabicBold); \ - m_name->add_data(FontBengaliBold); \ - m_name->add_data(FontDevanagariBold); \ - m_name->add_data(FontGeorgianBold); \ - m_name->add_data(FontHebrewBold); \ - m_name->add_data(FontMalayalamBold); \ - m_name->add_data(FontOriyaBold); \ - m_name->add_data(FontSinhalaBold); \ - m_name->add_data(FontTamilBold); \ - m_name->add_data(FontTeluguBold); \ - m_name->add_data(FontThaiBold); \ - m_name->add_data(FontJapaneseBold); \ - m_name->add_data(FontFallbackBold); - -#define MAKE_DEFAULT_FONT(m_name, m_variations) \ - Ref<Font> m_name; \ - m_name.instantiate(); \ - if (CustomFont.is_valid()) { \ - m_name->add_data(CustomFont); \ - m_name->add_data(DefaultFont); \ - } else { \ - m_name->add_data(DefaultFont); \ - } \ - { \ - Dictionary variations; \ - if (!m_variations.is_empty()) { \ - Vector<String> variation_tags = m_variations.split(","); \ - for (int i = 0; i < variation_tags.size(); i++) { \ - Vector<String> tokens = variation_tags[i].split("="); \ - if (tokens.size() == 2) { \ - variations[tokens[0]] = tokens[1].to_float(); \ - } \ - } \ - } \ - m_name->set_variation_coordinates(variations); \ - } \ - m_name->set_spacing(TextServer::SPACING_TOP, -EDSCALE); \ - m_name->set_spacing(TextServer::SPACING_BOTTOM, -EDSCALE); \ - MAKE_FALLBACKS(m_name); - -#define MAKE_DEFAULT_FONT_MSDF(m_name, m_variations) \ - Ref<Font> m_name; \ - m_name.instantiate(); \ - if (CustomFont.is_valid()) { \ - m_name->add_data(CustomFontMSDF); \ - m_name->add_data(DefaultFontMSDF); \ - } else { \ - m_name->add_data(DefaultFontMSDF); \ - } \ - { \ - Dictionary variations; \ - if (!m_variations.is_empty()) { \ - Vector<String> variation_tags = m_variations.split(","); \ - for (int i = 0; i < variation_tags.size(); i++) { \ - Vector<String> tokens = variation_tags[i].split("="); \ - if (tokens.size() == 2) { \ - variations[tokens[0]] = tokens[1].to_float(); \ - } \ - } \ - } \ - m_name->set_variation_coordinates(variations); \ - } \ - m_name->set_spacing(TextServer::SPACING_TOP, -EDSCALE); \ - m_name->set_spacing(TextServer::SPACING_BOTTOM, -EDSCALE); \ - MAKE_FALLBACKS(m_name); - -#define MAKE_SLANTED_FONT(m_name, m_variations) \ - Ref<Font> m_name; \ - m_name.instantiate(); \ - m_name.instantiate(); \ - if (CustomFontSlanted.is_valid()) { \ - m_name->add_data(CustomFontSlanted); \ - m_name->add_data(DefaultFontSlanted); \ - } else { \ - m_name->add_data(DefaultFontSlanted); \ - } \ - { \ - Dictionary variations; \ - if (!m_variations.is_empty()) { \ - Vector<String> variation_tags = m_variations.split(","); \ - for (int i = 0; i < variation_tags.size(); i++) { \ - Vector<String> tokens = variation_tags[i].split("="); \ - if (tokens.size() == 2) { \ - variations[tokens[0]] = tokens[1].to_float(); \ - } \ - } \ - } \ - m_name->set_variation_coordinates(variations); \ - } \ - m_name->set_spacing(TextServer::SPACING_TOP, -EDSCALE); \ - m_name->set_spacing(TextServer::SPACING_BOTTOM, -EDSCALE); \ - MAKE_FALLBACKS_SLANTED(m_name); - -#define MAKE_BOLD_FONT(m_name, m_variations) \ - Ref<Font> m_name; \ - m_name.instantiate(); \ - if (CustomFontBold.is_valid()) { \ - m_name->add_data(CustomFontBold); \ - m_name->add_data(DefaultFontBold); \ - } else { \ - m_name->add_data(DefaultFontBold); \ - } \ - { \ - Dictionary variations; \ - if (!m_variations.is_empty()) { \ - Vector<String> variation_tags = m_variations.split(","); \ - for (int i = 0; i < variation_tags.size(); i++) { \ - Vector<String> tokens = variation_tags[i].split("="); \ - if (tokens.size() == 2) { \ - variations[tokens[0]] = tokens[1].to_float(); \ - } \ - } \ - } \ - m_name->set_variation_coordinates(variations); \ - } \ - m_name->set_spacing(TextServer::SPACING_TOP, -EDSCALE); \ - m_name->set_spacing(TextServer::SPACING_BOTTOM, -EDSCALE); \ - MAKE_FALLBACKS_BOLD(m_name); - -#define MAKE_BOLD_FONT_MSDF(m_name, m_variations) \ - Ref<Font> m_name; \ - m_name.instantiate(); \ - if (CustomFontBold.is_valid()) { \ - m_name->add_data(CustomFontBoldMSDF); \ - m_name->add_data(DefaultFontBoldMSDF); \ - } else { \ - m_name->add_data(DefaultFontBoldMSDF); \ - } \ - { \ - Dictionary variations; \ - if (!m_variations.is_empty()) { \ - Vector<String> variation_tags = m_variations.split(","); \ - for (int i = 0; i < variation_tags.size(); i++) { \ - Vector<String> tokens = variation_tags[i].split("="); \ - if (tokens.size() == 2) { \ - variations[tokens[0]] = tokens[1].to_float(); \ - } \ - } \ - } \ - m_name->set_variation_coordinates(variations); \ - } \ - m_name->set_spacing(TextServer::SPACING_TOP, -EDSCALE); \ - m_name->set_spacing(TextServer::SPACING_BOTTOM, -EDSCALE); \ - MAKE_FALLBACKS_BOLD(m_name); - -#define MAKE_SOURCE_FONT(m_name, m_variations) \ - Ref<Font> m_name; \ - m_name.instantiate(); \ - if (CustomFontSource.is_valid()) { \ - m_name->add_data(CustomFontSource); \ - m_name->add_data(dfmono); \ - } else { \ - m_name->add_data(dfmono); \ - } \ - { \ - Dictionary variations; \ - if (!m_variations.is_empty()) { \ - Vector<String> variation_tags = m_variations.split(","); \ - for (int i = 0; i < variation_tags.size(); i++) { \ - Vector<String> tokens = variation_tags[i].split("="); \ - if (tokens.size() == 2) { \ - variations[tokens[0]] = tokens[1].to_float(); \ - } \ - } \ - } \ - m_name->set_variation_coordinates(variations); \ - } \ - m_name->set_spacing(TextServer::SPACING_TOP, -EDSCALE); \ - m_name->set_spacing(TextServer::SPACING_BOTTOM, -EDSCALE); \ - MAKE_FALLBACKS(m_name); - -Ref<FontData> load_cached_external_font(const String &p_path, TextServer::Hinting p_hinting, bool p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false) { - Ref<FontData> font; +Ref<FontFile> load_external_font(const String &p_path, TextServer::Hinting p_hinting, bool p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false, TypedArray<Font> *r_fallbacks = nullptr) { + Ref<FontFile> font; font.instantiate(); Vector<uint8_t> data = FileAccess::get_file_as_array(p_path); @@ -254,11 +50,15 @@ Ref<FontData> load_cached_external_font(const String &p_path, TextServer::Hintin font->set_force_autohinter(p_autohint); font->set_subpixel_positioning(p_font_subpixel_positioning); + if (r_fallbacks != nullptr) { + r_fallbacks->push_back(font); + } + return font; } -Ref<FontData> load_cached_internal_font(const uint8_t *p_data, size_t p_size, TextServer::Hinting p_hinting, bool p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false) { - Ref<FontData> font; +Ref<FontFile> load_internal_font(const uint8_t *p_data, size_t p_size, TextServer::Hinting p_hinting, bool p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false, TypedArray<Font> *r_fallbacks = nullptr) { + Ref<FontFile> font; font.instantiate(); font->set_data_ptr(p_data, p_size); @@ -268,14 +68,29 @@ Ref<FontData> load_cached_internal_font(const uint8_t *p_data, size_t p_size, Te font->set_force_autohinter(p_autohint); font->set_subpixel_positioning(p_font_subpixel_positioning); + if (r_fallbacks != nullptr) { + r_fallbacks->push_back(font); + } + return font; } +Ref<FontVariation> make_bold_font(const Ref<Font> &p_font, double p_embolden, TypedArray<Font> *r_fallbacks = nullptr) { + Ref<FontVariation> font_var; + font_var.instantiate(); + font_var->set_base_font(p_font); + font_var->set_variation_embolden(p_embolden); + + if (r_fallbacks != nullptr) { + r_fallbacks->push_back(font_var); + } + + return font_var; +} + void editor_register_fonts(Ref<Theme> p_theme) { Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - /* Custom font */ - bool font_antialiased = (bool)EditorSettings::get_singleton()->get("interface/editor/font_antialiased"); int font_hinting_setting = (int)EditorSettings::get_singleton()->get("interface/editor/font_hinting"); TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)EditorSettings::get_singleton()->get("interface/editor/font_subpixel_positioning"); @@ -304,184 +119,251 @@ void editor_register_fonts(Ref<Theme> p_theme) { break; } + // Load built-in fonts. const int default_font_size = int(EDITOR_GET("interface/editor/main_font_size")) * EDSCALE; const float embolden_strength = 0.6; + Ref<Font> default_font = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false); + Ref<Font> default_font_msdf = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, true); + + TypedArray<Font> fallbacks; + Ref<FontFile> arabic_font = load_internal_font(_font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); + Ref<FontFile> bengali_font = load_internal_font(_font_NotoSansBengaliUI_Regular, _font_NotoSansBengaliUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); + Ref<FontFile> devanagari_font = load_internal_font(_font_NotoSansDevanagariUI_Regular, _font_NotoSansDevanagariUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); + Ref<FontFile> georgian_font = load_internal_font(_font_NotoSansGeorgian_Regular, _font_NotoSansGeorgian_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); + Ref<FontFile> hebrew_font = load_internal_font(_font_NotoSansHebrew_Regular, _font_NotoSansHebrew_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); + Ref<FontFile> malayalam_font = load_internal_font(_font_NotoSansMalayalamUI_Regular, _font_NotoSansMalayalamUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); + Ref<FontFile> oriya_font = load_internal_font(_font_NotoSansOriyaUI_Regular, _font_NotoSansOriyaUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); + Ref<FontFile> sinhala_font = load_internal_font(_font_NotoSansSinhalaUI_Regular, _font_NotoSansSinhalaUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); + Ref<FontFile> tamil_font = load_internal_font(_font_NotoSansTamilUI_Regular, _font_NotoSansTamilUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); + Ref<FontFile> telugu_font = load_internal_font(_font_NotoSansTeluguUI_Regular, _font_NotoSansTeluguUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); + Ref<FontFile> thai_font = load_internal_font(_font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); + Ref<FontFile> fallback_font = load_internal_font(_font_DroidSansFallback, _font_DroidSansFallback_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); + Ref<FontFile> japanese_font = load_internal_font(_font_DroidSansJapanese, _font_DroidSansJapanese_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks); + default_font->set_fallbacks(fallbacks); + default_font_msdf->set_fallbacks(fallbacks); + + Ref<FontFile> default_font_bold = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false); + Ref<FontFile> default_font_bold_msdf = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, true); + + TypedArray<Font> fallbacks_bold; + Ref<FontFile> arabic_font_bold = load_internal_font(_font_NotoNaskhArabicUI_Bold, _font_NotoNaskhArabicUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref<FontFile> bengali_font_bold = load_internal_font(_font_NotoSansBengaliUI_Bold, _font_NotoSansBengaliUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref<FontFile> devanagari_font_bold = load_internal_font(_font_NotoSansDevanagariUI_Bold, _font_NotoSansDevanagariUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref<FontFile> georgian_font_bold = load_internal_font(_font_NotoSansGeorgian_Bold, _font_NotoSansGeorgian_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref<FontFile> hebrew_font_bold = load_internal_font(_font_NotoSansHebrew_Bold, _font_NotoSansHebrew_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref<FontFile> malayalam_font_bold = load_internal_font(_font_NotoSansMalayalamUI_Bold, _font_NotoSansMalayalamUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref<FontFile> oriya_font_bold = load_internal_font(_font_NotoSansOriyaUI_Bold, _font_NotoSansOriyaUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref<FontFile> sinhala_font_bold = load_internal_font(_font_NotoSansSinhalaUI_Bold, _font_NotoSansSinhalaUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref<FontFile> tamil_font_bold = load_internal_font(_font_NotoSansTamilUI_Bold, _font_NotoSansTamilUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref<FontFile> telugu_font_bold = load_internal_font(_font_NotoSansTeluguUI_Bold, _font_NotoSansTeluguUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref<FontFile> thai_font_bold = load_internal_font(_font_NotoSansThaiUI_Bold, _font_NotoSansThaiUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold); + Ref<FontVariation> fallback_font_bold = make_bold_font(fallback_font, embolden_strength, &fallbacks_bold); + Ref<FontVariation> japanese_font_bold = make_bold_font(japanese_font, embolden_strength, &fallbacks_bold); + default_font_bold->set_fallbacks(fallbacks_bold); + default_font_bold_msdf->set_fallbacks(fallbacks_bold); + + Ref<FontFile> default_font_mono = load_internal_font(_font_JetBrainsMono_Regular, _font_JetBrainsMono_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning); + { + Dictionary opentype_features_mono; + opentype_features_mono["calt"] = 0; + default_font_mono->set_opentype_feature_overrides(opentype_features_mono); // Disable contextual alternates (coding ligatures). + } + default_font_mono->set_fallbacks(fallbacks); + + // Init base font configs and load custom fonts. String custom_font_path = EditorSettings::get_singleton()->get("interface/editor/main_font"); - Ref<FontData> CustomFont; + String custom_font_path_bold = EditorSettings::get_singleton()->get("interface/editor/main_font_bold"); + String custom_font_path_source = EditorSettings::get_singleton()->get("interface/editor/code_font"); + + Ref<FontVariation> default_fc; + default_fc.instantiate(); if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) { - CustomFont = load_cached_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning); + Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning); + { + TypedArray<Font> fallback_custom; + fallback_custom.push_back(default_font); + custom_font->set_fallbacks(fallback_custom); + } + default_fc->set_base_font(custom_font); } else { EditorSettings::get_singleton()->set_manually("interface/editor/main_font", ""); + default_fc->set_base_font(default_font); } + default_fc->set_spacing(TextServer::SPACING_TOP, -EDSCALE); + default_fc->set_spacing(TextServer::SPACING_BOTTOM, -EDSCALE); - Ref<FontData> CustomFontMSDF; + Ref<FontVariation> default_fc_msdf; + default_fc_msdf.instantiate(); if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) { - CustomFontMSDF = load_cached_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning, true); + Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning); + { + TypedArray<Font> fallback_custom; + fallback_custom.push_back(default_font_msdf); + custom_font->set_fallbacks(fallback_custom); + } + default_fc_msdf->set_base_font(custom_font); } else { EditorSettings::get_singleton()->set_manually("interface/editor/main_font", ""); + default_fc_msdf->set_base_font(default_font_msdf); } + default_fc_msdf->set_spacing(TextServer::SPACING_TOP, -EDSCALE); + default_fc_msdf->set_spacing(TextServer::SPACING_BOTTOM, -EDSCALE); - Ref<FontData> CustomFontSlanted; - if (CustomFont.is_valid()) { - CustomFontSlanted = CustomFont->duplicate(); - CustomFontSlanted->set_transform(Transform2D(1.0, 0.4, 0.0, 1.0, 0.0, 0.0)); - } - - /* Custom Bold font */ - - String custom_font_path_bold = EditorSettings::get_singleton()->get("interface/editor/main_font_bold"); - Ref<FontData> CustomFontBold; + Ref<FontVariation> bold_fc; + bold_fc.instantiate(); if (custom_font_path_bold.length() > 0 && dir->file_exists(custom_font_path_bold)) { - CustomFontBold = load_cached_external_font(custom_font_path_bold, font_hinting, font_antialiased, true, font_subpixel_positioning); + Ref<FontFile> custom_font = load_external_font(custom_font_path_bold, font_hinting, font_antialiased, true, font_subpixel_positioning); + { + TypedArray<Font> fallback_custom; + fallback_custom.push_back(default_font_bold); + custom_font->set_fallbacks(fallback_custom); + } + bold_fc->set_base_font(custom_font); + } else if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) { + Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning); + { + TypedArray<Font> fallback_custom; + fallback_custom.push_back(default_font_bold); + custom_font->set_fallbacks(fallback_custom); + } + bold_fc->set_base_font(custom_font); + bold_fc->set_variation_embolden(embolden_strength); } else { EditorSettings::get_singleton()->set_manually("interface/editor/main_font_bold", ""); + bold_fc->set_base_font(default_font_bold); } + bold_fc->set_spacing(TextServer::SPACING_TOP, -EDSCALE); + bold_fc->set_spacing(TextServer::SPACING_BOTTOM, -EDSCALE); - if (CustomFont.is_valid() && !CustomFontBold.is_valid()) { - CustomFontBold = CustomFont->duplicate(); - CustomFontBold->set_embolden(embolden_strength); - } - - Ref<FontData> CustomFontBoldMSDF; - if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) { - CustomFontBoldMSDF = load_cached_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning, true); + Ref<FontVariation> bold_fc_msdf; + bold_fc_msdf.instantiate(); + if (custom_font_path_bold.length() > 0 && dir->file_exists(custom_font_path_bold)) { + Ref<FontFile> custom_font = load_external_font(custom_font_path_bold, font_hinting, font_antialiased, true, font_subpixel_positioning); + { + TypedArray<Font> fallback_custom; + fallback_custom.push_back(default_font_bold_msdf); + custom_font->set_fallbacks(fallback_custom); + } + bold_fc_msdf->set_base_font(custom_font); + } else if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) { + Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning); + { + TypedArray<Font> fallback_custom; + fallback_custom.push_back(default_font_bold_msdf); + custom_font->set_fallbacks(fallback_custom); + } + bold_fc_msdf->set_base_font(custom_font); + bold_fc_msdf->set_variation_embolden(embolden_strength); } else { EditorSettings::get_singleton()->set_manually("interface/editor/main_font_bold", ""); + bold_fc_msdf->set_base_font(default_font_bold_msdf); } + bold_fc_msdf->set_spacing(TextServer::SPACING_TOP, -EDSCALE); + bold_fc_msdf->set_spacing(TextServer::SPACING_BOTTOM, -EDSCALE); - /* Custom source code font */ - - String custom_font_path_source = EditorSettings::get_singleton()->get("interface/editor/code_font"); - Ref<FontData> CustomFontSource; + Ref<FontVariation> mono_fc; + mono_fc.instantiate(); if (custom_font_path_source.length() > 0 && dir->file_exists(custom_font_path_source)) { - CustomFontSource = load_cached_external_font(custom_font_path_source, font_hinting, font_antialiased, true, font_subpixel_positioning); + Ref<FontFile> custom_font = load_external_font(custom_font_path_source, font_hinting, font_antialiased, true, font_subpixel_positioning); + { + TypedArray<Font> fallback_custom; + fallback_custom.push_back(default_font_mono); + custom_font->set_fallbacks(fallback_custom); + } + mono_fc->set_base_font(custom_font); } else { EditorSettings::get_singleton()->set_manually("interface/editor/code_font", ""); + mono_fc->set_base_font(default_font_mono); } - /* Noto Sans */ - - Ref<FontData> DefaultFont = load_cached_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> DefaultFontMSDF = load_cached_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, true); - Ref<FontData> DefaultFontBold = load_cached_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> DefaultFontBoldMSDF = load_cached_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, true); - Ref<FontData> FontArabic = load_cached_internal_font(_font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontArabicBold = load_cached_internal_font(_font_NotoNaskhArabicUI_Bold, _font_NotoNaskhArabicUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontBengali = load_cached_internal_font(_font_NotoSansBengaliUI_Regular, _font_NotoSansBengaliUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontBengaliBold = load_cached_internal_font(_font_NotoSansBengaliUI_Bold, _font_NotoSansBengaliUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontDevanagari = load_cached_internal_font(_font_NotoSansDevanagariUI_Regular, _font_NotoSansDevanagariUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontDevanagariBold = load_cached_internal_font(_font_NotoSansDevanagariUI_Bold, _font_NotoSansDevanagariUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontGeorgian = load_cached_internal_font(_font_NotoSansGeorgian_Regular, _font_NotoSansGeorgian_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontGeorgianBold = load_cached_internal_font(_font_NotoSansGeorgian_Bold, _font_NotoSansGeorgian_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontHebrew = load_cached_internal_font(_font_NotoSansHebrew_Regular, _font_NotoSansHebrew_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontHebrewBold = load_cached_internal_font(_font_NotoSansHebrew_Bold, _font_NotoSansHebrew_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontMalayalam = load_cached_internal_font(_font_NotoSansMalayalamUI_Regular, _font_NotoSansMalayalamUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontMalayalamBold = load_cached_internal_font(_font_NotoSansMalayalamUI_Bold, _font_NotoSansMalayalamUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontOriya = load_cached_internal_font(_font_NotoSansOriyaUI_Regular, _font_NotoSansOriyaUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontOriyaBold = load_cached_internal_font(_font_NotoSansOriyaUI_Bold, _font_NotoSansOriyaUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontSinhala = load_cached_internal_font(_font_NotoSansSinhalaUI_Regular, _font_NotoSansSinhalaUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontSinhalaBold = load_cached_internal_font(_font_NotoSansSinhalaUI_Bold, _font_NotoSansSinhalaUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontTamil = load_cached_internal_font(_font_NotoSansTamilUI_Regular, _font_NotoSansTamilUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontTamilBold = load_cached_internal_font(_font_NotoSansTamilUI_Bold, _font_NotoSansTamilUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontTelugu = load_cached_internal_font(_font_NotoSansTeluguUI_Regular, _font_NotoSansTeluguUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontTeluguBold = load_cached_internal_font(_font_NotoSansTeluguUI_Bold, _font_NotoSansTeluguUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontThai = load_cached_internal_font(_font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontThaiBold = load_cached_internal_font(_font_NotoSansThaiUI_Bold, _font_NotoSansThaiUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - - Ref<FontData> DefaultFontSlanted = DefaultFont->duplicate(); - DefaultFontSlanted->set_transform(Transform2D(1.0, 0.3, 0.0, 1.0, 0.0, 0.0)); - - /* Droid Sans */ - - Ref<FontData> FontFallback = load_cached_internal_font(_font_DroidSansFallback, _font_DroidSansFallback_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Ref<FontData> FontJapanese = load_cached_internal_font(_font_DroidSansJapanese, _font_DroidSansJapanese_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - - Ref<FontData> FontFallbackBold = FontFallback->duplicate(); - FontFallbackBold->set_embolden(embolden_strength); - Ref<FontData> FontJapaneseBold = FontJapanese->duplicate(); - FontJapaneseBold->set_embolden(embolden_strength); - - /* Hack */ - - Ref<FontData> dfmono = load_cached_internal_font(_font_JetBrainsMono_Regular, _font_JetBrainsMono_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning); - Dictionary opentype_features; - opentype_features["calt"] = 0; - dfmono->set_opentype_feature_overrides(opentype_features); // Disable contextual alternates (coding ligatures). - - // Default font - MAKE_DEFAULT_FONT(df, String()); - p_theme->set_default_font(df); // Default theme font + String code_font_custom_variations = EditorSettings::get_singleton()->get("interface/editor/code_font_custom_variations"); + Dictionary variations_mono; + if (!code_font_custom_variations.is_empty()) { + Vector<String> variation_tags = code_font_custom_variations.split(","); + for (int i = 0; i < variation_tags.size(); i++) { + Vector<String> subtag_a = variation_tags[i].split("="); + if (subtag_a.size() == 2) { + variations_mono[TS->name_to_tag(subtag_a[0])] = subtag_a[1].to_float(); + } else if (subtag_a.size() == 1) { + variations_mono[TS->name_to_tag(subtag_a[0])] = 1; + } + } + mono_fc->set_variation_opentype(variations_mono); + } + mono_fc->set_spacing(TextServer::SPACING_TOP, -EDSCALE); + mono_fc->set_spacing(TextServer::SPACING_BOTTOM, -EDSCALE); + + Ref<FontVariation> italic_fc = default_fc->duplicate(); + italic_fc->set_variation_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0)); + + // Setup theme. + + p_theme->set_default_font(default_fc); // Default theme font config. p_theme->set_default_font_size(default_font_size); - p_theme->set_font_size("main_size", "EditorFonts", default_font_size); - p_theme->set_font("main", "EditorFonts", df); + // Main font. - MAKE_DEFAULT_FONT_MSDF(df_msdf, String()); - p_theme->set_font("main_msdf", "EditorFonts", df_msdf); + p_theme->set_font("main", "EditorFonts", default_fc); + p_theme->set_font("main_msdf", "EditorFonts", default_fc_msdf); + p_theme->set_font_size("main_size", "EditorFonts", default_font_size); - // Bold font - MAKE_BOLD_FONT(df_bold, String()); - MAKE_SLANTED_FONT(df_italic, String()); + p_theme->set_font("bold", "EditorFonts", bold_fc); + p_theme->set_font("main_bold_msdf", "EditorFonts", bold_fc_msdf); p_theme->set_font_size("bold_size", "EditorFonts", default_font_size); - p_theme->set_font("bold", "EditorFonts", df_bold); - MAKE_BOLD_FONT_MSDF(df_bold_msdf, String()); - p_theme->set_font("main_bold_msdf", "EditorFonts", df_bold_msdf); + // Title font. - // Title font + p_theme->set_font("title", "EditorFonts", bold_fc); p_theme->set_font_size("title_size", "EditorFonts", default_font_size + 1 * EDSCALE); - p_theme->set_font("title", "EditorFonts", df_bold); + p_theme->set_font("main_button_font", "EditorFonts", bold_fc); p_theme->set_font_size("main_button_font_size", "EditorFonts", default_font_size + 1 * EDSCALE); - p_theme->set_font("main_button_font", "EditorFonts", df_bold); - p_theme->set_font("font", "Label", df); + p_theme->set_font("font", "Label", default_fc); p_theme->set_type_variation("HeaderSmall", "Label"); - p_theme->set_font("font", "HeaderSmall", df_bold); + p_theme->set_font("font", "HeaderSmall", bold_fc); p_theme->set_font_size("font_size", "HeaderSmall", default_font_size); p_theme->set_type_variation("HeaderMedium", "Label"); - p_theme->set_font("font", "HeaderMedium", df_bold); + p_theme->set_font("font", "HeaderMedium", bold_fc); p_theme->set_font_size("font_size", "HeaderMedium", default_font_size + 1 * EDSCALE); p_theme->set_type_variation("HeaderLarge", "Label"); - p_theme->set_font("font", "HeaderLarge", df_bold); + p_theme->set_font("font", "HeaderLarge", bold_fc); p_theme->set_font_size("font_size", "HeaderLarge", default_font_size + 3 * EDSCALE); // Documentation fonts - String code_font_custom_variations = EditorSettings::get_singleton()->get("interface/editor/code_font_custom_variations"); - MAKE_SOURCE_FONT(df_code, code_font_custom_variations); p_theme->set_font_size("doc_size", "EditorFonts", int(EDITOR_GET("text_editor/help/help_font_size")) * EDSCALE); - p_theme->set_font("doc", "EditorFonts", df); - p_theme->set_font("doc_bold", "EditorFonts", df_bold); - p_theme->set_font("doc_italic", "EditorFonts", df_italic); + p_theme->set_font("doc", "EditorFonts", default_fc); + p_theme->set_font("doc_bold", "EditorFonts", bold_fc); + p_theme->set_font("doc_italic", "EditorFonts", italic_fc); p_theme->set_font_size("doc_title_size", "EditorFonts", int(EDITOR_GET("text_editor/help/help_title_font_size")) * EDSCALE); - p_theme->set_font("doc_title", "EditorFonts", df_bold); + p_theme->set_font("doc_title", "EditorFonts", bold_fc); p_theme->set_font_size("doc_source_size", "EditorFonts", int(EDITOR_GET("text_editor/help/help_source_font_size")) * EDSCALE); - p_theme->set_font("doc_source", "EditorFonts", df_code); + p_theme->set_font("doc_source", "EditorFonts", mono_fc); p_theme->set_font_size("doc_keyboard_size", "EditorFonts", (int(EDITOR_GET("text_editor/help/help_source_font_size")) - 1) * EDSCALE); - p_theme->set_font("doc_keyboard", "EditorFonts", df_code); + p_theme->set_font("doc_keyboard", "EditorFonts", mono_fc); // Ruler font p_theme->set_font_size("rulers_size", "EditorFonts", 8 * EDSCALE); - p_theme->set_font("rulers", "EditorFonts", df); + p_theme->set_font("rulers", "EditorFonts", default_fc); // Rotation widget font p_theme->set_font_size("rotation_control_size", "EditorFonts", 14 * EDSCALE); - p_theme->set_font("rotation_control", "EditorFonts", df); + p_theme->set_font("rotation_control", "EditorFonts", default_fc); // Code font p_theme->set_font_size("source_size", "EditorFonts", int(EDITOR_GET("interface/editor/code_font_size")) * EDSCALE); - p_theme->set_font("source", "EditorFonts", df_code); + p_theme->set_font("source", "EditorFonts", mono_fc); p_theme->set_font_size("expression_size", "EditorFonts", (int(EDITOR_GET("interface/editor/code_font_size")) - 1) * EDSCALE); - p_theme->set_font("expression", "EditorFonts", df_code); + p_theme->set_font("expression", "EditorFonts", mono_fc); p_theme->set_font_size("output_source_size", "EditorFonts", int(EDITOR_GET("run/output/font_size")) * EDSCALE); - p_theme->set_font("output_source", "EditorFonts", df_code); + p_theme->set_font("output_source", "EditorFonts", mono_fc); p_theme->set_font_size("status_source_size", "EditorFonts", default_font_size); - p_theme->set_font("status_source", "EditorFonts", df_code); + p_theme->set_font("status_source", "EditorFonts", mono_fc); } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 48d4b96a67..a674451d1e 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -186,7 +186,7 @@ void EditorHelp::_class_desc_resized(bool p_force_update_theme) { // The margins increase as the width of the editor help container increases. Ref<Font> doc_code_font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts")); int font_size = get_theme_font_size(SNAME("doc_source_size"), SNAME("EditorFonts")); - real_t char_width = doc_code_font->get_char_size('x', 0, font_size).width; + real_t char_width = doc_code_font->get_char_size('x', font_size).width; const int new_display_margin = MAX(30 * EDSCALE, get_parent_anchorable_rect().size.width - char_width * 120 * EDSCALE) * 0.5; if (display_margin != new_display_margin || p_force_update_theme) { display_margin = new_display_margin; diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 2bf0cd2f20..dc47719f0a 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -322,7 +322,7 @@ void EditorProperty::_notification(int p_what) { Ref<Texture2D> pinned_icon = get_theme_icon(SNAME("Pin"), SNAME("EditorIcons")); int margin_w = get_theme_constant(SNAME("hseparator"), SNAME("Tree")) * 2; int total_icon_w = margin_w + pinned_icon->get_width(); - int text_w = font->get_string_size(label, font_size, rtl ? HORIZONTAL_ALIGNMENT_RIGHT : HORIZONTAL_ALIGNMENT_LEFT, text_limit - total_icon_w).x; + int text_w = font->get_string_size(label, rtl ? HORIZONTAL_ALIGNMENT_RIGHT : HORIZONTAL_ALIGNMENT_LEFT, text_limit - total_icon_w, font_size).x; int y = (size.height - pinned_icon->get_height()) / 2; if (rtl) { draw_texture(pinned_icon, Vector2(size.width - ofs - text_w - total_icon_w, y), color); @@ -1087,7 +1087,7 @@ void EditorInspectorCategory::_notification(int p_what) { int hs = get_theme_constant(SNAME("h_separation"), SNAME("Tree")); - int w = font->get_string_size(label, font_size).width; + int w = font->get_string_size(label, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width; if (icon.is_valid()) { w += hs + icon->get_width(); } @@ -3429,6 +3429,7 @@ void EditorInspector::_property_checked(const String &p_path, bool p_checked) { if (editor_property_map.has(p_path)) { for (EditorProperty *E : editor_property_map[p_path]) { + E->set_checked(p_checked); E->update_property(); E->update_revert_and_pin_status(); E->update_cache(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 7697bbfdf4..eafbf11df0 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -146,7 +146,7 @@ #include "editor/plugins/debugger_editor_plugin.h" #include "editor/plugins/editor_debugger_plugin.h" #include "editor/plugins/editor_preview_plugins.h" -#include "editor/plugins/font_editor_plugin.h" +#include "editor/plugins/font_config_plugin.h" #include "editor/plugins/gdextension_export_plugin.h" #include "editor/plugins/gpu_particles_2d_editor_plugin.h" #include "editor/plugins/gpu_particles_3d_editor_plugin.h" @@ -165,7 +165,6 @@ #include "editor/plugins/navigation_polygon_editor_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "editor/plugins/occluder_instance_3d_editor_plugin.h" -#include "editor/plugins/ot_features_plugin.h" #include "editor/plugins/packed_scene_translation_parser_plugin.h" #include "editor/plugins/path_2d_editor_plugin.h" #include "editor/plugins/path_3d_editor_plugin.h" @@ -187,7 +186,6 @@ #include "editor/plugins/sprite_frames_editor_plugin.h" #include "editor/plugins/style_box_editor_plugin.h" #include "editor/plugins/sub_viewport_preview_editor_plugin.h" -#include "editor/plugins/text_control_editor_plugin.h" #include "editor/plugins/text_editor.h" #include "editor/plugins/texture_3d_editor_plugin.h" #include "editor/plugins/texture_editor_plugin.h" @@ -7125,7 +7123,6 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(CollisionShape2DEditorPlugin)); add_editor_plugin(memnew(CurveEditorPlugin)); add_editor_plugin(memnew(FontEditorPlugin)); - add_editor_plugin(memnew(OpenTypeFeaturesEditorPlugin)); add_editor_plugin(memnew(TextureEditorPlugin)); add_editor_plugin(memnew(TextureLayeredEditorPlugin)); add_editor_plugin(memnew(Texture3DEditorPlugin)); @@ -7140,7 +7137,6 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(GPUParticlesCollisionSDF3DEditorPlugin)); add_editor_plugin(memnew(InputEventEditorPlugin)); add_editor_plugin(memnew(SubViewportPreviewEditorPlugin)); - add_editor_plugin(memnew(TextControlEditorPlugin)); add_editor_plugin(memnew(ControlEditorPlugin)); add_editor_plugin(memnew(GradientTexture2DEditorPlugin)); add_editor_plugin(memnew(BitMapEditorPlugin)); diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 4d53ddb344..77d627ab9c 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -534,8 +534,6 @@ void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<Strin p_vector->insert("Texture2D"); } else if (base == "ShaderMaterial") { p_vector->insert("Shader"); - } else if (base == "Font") { - p_vector->insert("FontData"); } else if (base == "Texture2D") { p_vector->insert("Image"); } @@ -675,16 +673,6 @@ void EditorResourcePicker::drop_data_fw(const Point2 &p_point, const Variant &p_ break; } - if (at == "Font" && Ref<FontData>(dropped_resource).is_valid()) { - Ref<Font> font = edited_resource; - if (!font.is_valid()) { - font.instantiate(); - } - font->add_data(dropped_resource); - dropped_resource = font; - break; - } - if (at == "Texture2D" && Ref<Image>(dropped_resource).is_valid()) { Ref<ImageTexture> texture = edited_resource; if (!texture.is_valid()) { diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index fbdc1c0a0c..fa8643af86 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -444,6 +444,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { // Inspector EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/inspector/max_array_dictionary_items_per_page", 20, "10,100,1") + EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/show_low_level_opentype_features", false, "") // Theme EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_ENUM, "interface/theme/preset", "Default", "Default,Breeze Dark,Godot 2,Gray,Light,Solarized (Dark),Solarized (Light),Custom") diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index f23f0cf758..c651d6bf6e 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -286,7 +286,7 @@ void EditorSpinSlider::_draw_spin_slider() { int sep_base = 4 * EDSCALE; int sep = sep_base + sb->get_offset().x; //make it have the same margin on both sides, looks better - int label_width = font->get_string_size(label, font_size).width; + int label_width = font->get_string_size(label, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width; int number_width = size.width - sb->get_minimum_size().width - label_width - sep; Ref<Texture2D> updown = get_theme_icon(is_read_only() ? SNAME("updown_disabled") : SNAME("updown"), SNAME("SpinBox")); @@ -324,7 +324,10 @@ void EditorSpinSlider::_draw_spin_slider() { int suffix_start = numstr.length(); RID num_rid = TS->create_shaped_text(); - TS->shaped_text_add_string(num_rid, numstr + U"\u2009" + suffix, font->get_rids(), font_size); + TS->shaped_text_add_string(num_rid, numstr + U"\u2009" + suffix, font->get_rids(), font_size, font->get_opentype_features()); + for (int i = 0; i < TextServer::SPACING_MAX; i++) { + TS->shaped_text_set_spacing(num_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i))); + } float text_start = rtl ? Math::round(sb->get_offset().x) : Math::round(sb->get_offset().x + label_width + sep); Vector2 text_ofs = rtl ? Vector2(text_start + (number_width - TS->shaped_text_get_width(num_rid)), vofs) : Vector2(text_start, vofs); diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index e1c9689f73..81b71b5609 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -764,8 +764,8 @@ void FindInFilesPanel::draw_result_text(Object *item_obj, Rect2 rect) { int font_size = _results_display->get_theme_font_size(SNAME("font_size")); Rect2 match_rect = rect; - match_rect.position.x += font->get_string_size(item_text.left(r.begin_trimmed), font_size).x; - match_rect.size.x = font->get_string_size(_search_text_label->get_text(), font_size).x; + match_rect.position.x += font->get_string_size(item_text.left(r.begin_trimmed), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x; + match_rect.size.x = font->get_string_size(_search_text_label->get_text(), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x; match_rect.position.y += 1 * EDSCALE; match_rect.size.y -= 2 * EDSCALE; diff --git a/editor/icons/Font.svg b/editor/icons/Font.svg index 2c8d7cb43e..dda1aa577e 100644 --- a/editor/icons/Font.svg +++ b/editor/icons/Font.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m1 1037.4h14v2h-14z"/><path d="m7 1037.4h2v14h-2z"/><path d="m5 1050.4h6v1h-6z"/><path d="m1037.4-2h4v1h-4z" transform="rotate(90)"/><path d="m1037.4-15h4v1h-4z" transform="rotate(90)"/><path d="m2 3v2a2 2 0 0 1 2-2z" transform="translate(0 1036.4)"/><path d="m12 3a2 2 0 0 1 2 2v-2z" transform="translate(0 1036.4)"/><path d="m5 1050.4a2 2 0 0 0 2-2v2z"/><path d="m11 1050.4a2 2 0 0 1 -2-2v2z"/></g></svg> +<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="M1 1h14v2H1z"/><path d="M7 1h2v14H7z"/><path d="M5 14h6v1H5zM2 1v4H1V1zm13 0v4h-1V1zM2 3v2a2 2 0 0 1 2-2zm10 0a2 2 0 0 1 2 2V3zM5 14a2 2 0 0 0 2-2v2zm6 0a2 2 0 0 1-2-2v2z"/></g></svg> diff --git a/editor/icons/FontData.svg b/editor/icons/FontData.svg deleted file mode 100644 index 4cb6412081..0000000000 --- a/editor/icons/FontData.svg +++ /dev/null @@ -1 +0,0 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2 1h1a1 1 0 0 1 1-1h2v6a1 1 0 0 1 -1 1v1h1 2 1v-1a1 1 0 0 1 -1-1v-6h2a1 1 0 0 1 1 1h1v-1-2h-4-2zm0 5v2h2v-2zm0 3v2h2v-2zm0 3v2h2v-2zm3 0v2h2v-2z" fill="#e0e0e0"/><path d="m4 5v2 1h1a1 1 0 0 1 1-1h2v6a1 1 0 0 1 -1 1v1h1 2 1v-1a1 1 0 0 1 -1-1v-6h2a1 1 0 0 1 1 1h1v-1-2h-4-2z" fill="#ff5f5f"/></svg> diff --git a/editor/icons/FontFile.svg b/editor/icons/FontFile.svg new file mode 100644 index 0000000000..4b94fd0d74 --- /dev/null +++ b/editor/icons/FontFile.svg @@ -0,0 +1 @@ +<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M1.5 1v3h1a1 1 0 0 1 1-1h2v6a1 1 0 0 1-1 1v1h4v-1a1 1 0 0 1-1-1V3h2a1 1 0 0 1 1 1h1V1h-6Z" fill="#e0e0e0"/><path d="M4.5 5v3h1a1 1 0 0 1 1-1h2v6a1 1 0 0 1-1 1v1h4v-1a1 1 0 0 1-1-1V7h2a1 1 0 0 1 1 1h1V5h-6Z" fill="#ff5f5f"/></svg> diff --git a/editor/icons/FontVariation.svg b/editor/icons/FontVariation.svg new file mode 100644 index 0000000000..eaad049fce --- /dev/null +++ b/editor/icons/FontVariation.svg @@ -0,0 +1 @@ +<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="M2.437 1 1.379 4h1A.84 1.192 50 0 1 3.73 3h2L3.615 9a.84 1.192 50 0 1-1.352 1l-.353 1h4l.353-1a.84 1.192 50 0 1-.648-1l2.116-6h2a.84 1.192 50 0 1 .648 1h1l1.058-3h-6Z" fill="#e0e0e0"/><path d="m4.621 5-.705 2-.353 1h1a.84 1.192 49.998 0 1 1.353-1h2L5.8 13a.84 1.192 49.998 0 1-1.353 1l-.353 1h4l.353-1a.84 1.192 49.998 0 1-.647-1l2.116-6h2a.84 1.192 49.998 0 1 .647 1h1l.353-1 .705-2h-6Z" fill="#ff5f5f"/></svg> diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp index f7fe334828..fa261496f0 100644 --- a/editor/import/dynamic_font_import_settings.cpp +++ b/editor/import/dynamic_font_import_settings.cpp @@ -41,50 +41,44 @@ /* Settings data */ /*************************************************************************/ -class DynamicFontImportSettingsData : public RefCounted { - GDCLASS(DynamicFontImportSettingsData, RefCounted) - friend class DynamicFontImportSettings; - - HashMap<StringName, Variant> settings; - HashMap<StringName, Variant> defaults; - List<ResourceImporter::ImportOption> options; - DynamicFontImportSettings *owner = nullptr; - - bool _set(const StringName &p_name, const Variant &p_value) { - if (defaults.has(p_name) && defaults[p_name] == p_value) { - settings.erase(p_name); - } else { - settings[p_name] = p_value; - } - return true; +bool DynamicFontImportSettingsData::_set(const StringName &p_name, const Variant &p_value) { + if (defaults.has(p_name) && defaults[p_name] == p_value) { + settings.erase(p_name); + } else { + settings[p_name] = p_value; } + return true; +} - bool _get(const StringName &p_name, Variant &r_ret) const { - if (settings.has(p_name)) { - r_ret = settings[p_name]; - return true; - } - if (defaults.has(p_name)) { - r_ret = defaults[p_name]; - return true; - } - return false; +bool DynamicFontImportSettingsData::_get(const StringName &p_name, Variant &r_ret) const { + if (settings.has(p_name)) { + r_ret = settings[p_name]; + return true; + } + if (defaults.has(p_name)) { + r_ret = defaults[p_name]; + return true; } + return false; +} - void _get_property_list(List<PropertyInfo> *p_list) const { - for (const List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) { - if (owner && owner->import_settings_data.is_valid()) { - if (owner->import_settings_data->get("multichannel_signed_distance_field") && (E->get().option.name == "size" || E->get().option.name == "outline_size" || E->get().option.name == "oversampling")) { - continue; - } - if (!owner->import_settings_data->get("multichannel_signed_distance_field") && (E->get().option.name == "msdf_pixel_range" || E->get().option.name == "msdf_size")) { - continue; - } +void DynamicFontImportSettingsData::_get_property_list(List<PropertyInfo> *p_list) const { + for (const List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) { + if (owner && owner->import_settings_data.is_valid()) { + if (owner->import_settings_data->get("multichannel_signed_distance_field") && (E->get().option.name == "size" || E->get().option.name == "outline_size" || E->get().option.name == "oversampling")) { + continue; + } + if (!owner->import_settings_data->get("multichannel_signed_distance_field") && (E->get().option.name == "msdf_pixel_range" || E->get().option.name == "msdf_size")) { + continue; } - p_list->push_back(E->get().option); } + p_list->push_back(E->get().option); } -}; +} + +Ref<FontFile> DynamicFontImportSettingsData::get_font() const { + return fd; +} /*************************************************************************/ /* Glyph ranges */ @@ -454,58 +448,32 @@ void DynamicFontImportSettings::_add_glyph_range_item(int32_t p_start, int32_t p void DynamicFontImportSettings::_main_prop_changed(const String &p_edited_property) { // Update font preview. - if (p_edited_property == "face_index") { - if (font_preview->get_data_count() > 0) { - font_preview->get_data(0)->set_face_index(import_settings_data->get("face_index")); - } - } else if (p_edited_property == "antialiased") { - if (font_preview->get_data_count() > 0) { - font_preview->get_data(0)->set_antialiased(import_settings_data->get("antialiased")); - } - } else if (p_edited_property == "generate_mipmaps") { - if (font_preview->get_data_count() > 0) { - font_preview->get_data(0)->set_generate_mipmaps(import_settings_data->get("generate_mipmaps")); - } - } else if (p_edited_property == "multichannel_signed_distance_field") { - if (font_preview->get_data_count() > 0) { - font_preview->get_data(0)->set_multichannel_signed_distance_field(import_settings_data->get("multichannel_signed_distance_field")); - } - _variation_selected(); - _variations_validate(); - } else if (p_edited_property == "msdf_pixel_range") { - if (font_preview->get_data_count() > 0) { - font_preview->get_data(0)->set_msdf_pixel_range(import_settings_data->get("msdf_pixel_range")); - } - } else if (p_edited_property == "msdf_size") { - if (font_preview->get_data_count() > 0) { - font_preview->get_data(0)->set_msdf_size(import_settings_data->get("msdf_size")); - } - } else if (p_edited_property == "force_autohinter") { - if (font_preview->get_data_count() > 0) { - font_preview->get_data(0)->set_force_autohinter(import_settings_data->get("force_autohinter")); - } - } else if (p_edited_property == "hinting") { - if (font_preview->get_data_count() > 0) { - font_preview->get_data(0)->set_hinting((TextServer::Hinting)import_settings_data->get("hinting").operator int()); - } - } else if (p_edited_property == "subpixel_positioning") { - if (font_preview->get_data_count() > 0) { - font_preview->get_data(0)->set_subpixel_positioning((TextServer::SubpixelPositioning)import_settings_data->get("subpixel_positioning").operator int()); - } - } else if (p_edited_property == "embolden") { - if (font_preview->get_data_count() > 0) { - font_preview->get_data(0)->set_embolden(import_settings_data->get("embolden")); - } - } else if (p_edited_property == "transform") { - if (font_preview->get_data_count() > 0) { - font_preview->get_data(0)->set_transform(import_settings_data->get("transform")); - } - } else if (p_edited_property == "oversampling") { - if (font_preview->get_data_count() > 0) { - font_preview->get_data(0)->set_oversampling(import_settings_data->get("oversampling")); + if (font_preview.is_valid()) { + if (p_edited_property == "antialiased") { + font_preview->set_antialiased(import_settings_data->get("antialiased")); + } else if (p_edited_property == "generate_mipmaps") { + font_preview->set_generate_mipmaps(import_settings_data->get("generate_mipmaps")); + } else if (p_edited_property == "multichannel_signed_distance_field") { + font_preview->set_multichannel_signed_distance_field(import_settings_data->get("multichannel_signed_distance_field")); + _variation_selected(); + _variations_validate(); + } else if (p_edited_property == "msdf_pixel_range") { + font_preview->set_msdf_pixel_range(import_settings_data->get("msdf_pixel_range")); + } else if (p_edited_property == "msdf_size") { + font_preview->set_msdf_size(import_settings_data->get("msdf_size")); + } else if (p_edited_property == "force_autohinter") { + font_preview->set_force_autohinter(import_settings_data->get("force_autohinter")); + } else if (p_edited_property == "hinting") { + font_preview->set_hinting((TextServer::Hinting)import_settings_data->get("hinting").operator int()); + } else if (p_edited_property == "subpixel_positioning") { + font_preview->set_subpixel_positioning((TextServer::SubpixelPositioning)import_settings_data->get("subpixel_positioning").operator int()); + } else if (p_edited_property == "oversampling") { + font_preview->set_oversampling(import_settings_data->get("oversampling")); } } + font_preview_label->add_theme_font_override("font", font_preview); + font_preview_label->add_theme_font_size_override("font_size", 200 * EDSCALE); font_preview_label->update(); } @@ -534,6 +502,7 @@ void DynamicFontImportSettings::_variation_add() { import_variation_data->options = options_variations; inspector_vars->edit(import_variation_data.ptr()); import_variation_data->notify_property_list_changed(); + import_variation_data->fd = font_main; vars_item->set_metadata(0, import_variation_data); @@ -548,6 +517,10 @@ void DynamicFontImportSettings::_variation_selected() { inspector_vars->edit(import_variation_data.ptr()); import_variation_data->notify_property_list_changed(); + + label_glyphs->set_text(TTR("Preloaded glyphs: ") + itos(import_variation_data->selected_glyphs.size())); + _range_selected(); + _change_text_opts(); } } @@ -611,63 +584,91 @@ void DynamicFontImportSettings::_variations_validate() { } /*************************************************************************/ -/* Page 3 callbacks: Text to select glyphs */ +/* Page 2.1 callbacks: Text to select glyphs */ /*************************************************************************/ void DynamicFontImportSettings::_change_text_opts() { - Vector<String> ftr = ftr_edit->get_text().split(","); - for (int i = 0; i < ftr.size(); i++) { - Vector<String> tokens = ftr[i].split("="); - if (tokens.size() == 2) { - text_edit->set_opentype_feature(tokens[0], tokens[1].to_int()); - } else if (tokens.size() == 1) { - text_edit->set_opentype_feature(tokens[0], 1); - } + Ref<DynamicFontImportSettingsData> import_variation_data; + + TreeItem *vars_item = vars_list->get_selected(); + if (vars_item) { + import_variation_data = vars_item->get_metadata(0); } - text_edit->set_language(lang_edit->get_text()); + if (import_variation_data.is_null()) { + return; + } + + Ref<FontVariation> font_main_text; + font_main_text.instantiate(); + font_main_text->set_base_font(font_main); + font_main_text->set_opentype_features(text_settings_data->get("opentype_features")); + font_main_text->set_variation_opentype(import_variation_data->get("variation_opentype")); + font_main_text->set_variation_embolden(import_variation_data->get("variation_embolden")); + font_main_text->set_variation_face_index(import_variation_data->get("variation_face_index")); + font_main_text->set_variation_transform(import_variation_data->get("variation_transform")); + + text_edit->add_theme_font_override("font", font_main_text); } void DynamicFontImportSettings::_glyph_clear() { - selected_glyphs.clear(); - label_glyphs->set_text(TTR("Preloaded glyphs:") + " " + itos(selected_glyphs.size())); + Ref<DynamicFontImportSettingsData> import_variation_data; + + TreeItem *vars_item = vars_list->get_selected(); + if (vars_item) { + import_variation_data = vars_item->get_metadata(0); + } + if (import_variation_data.is_null()) { + return; + } + + import_variation_data->selected_glyphs.clear(); + label_glyphs->set_text(TTR("Preloaded glyphs:") + " " + itos(import_variation_data->selected_glyphs.size())); _range_selected(); } void DynamicFontImportSettings::_glyph_text_selected() { - Dictionary ftrs; - Vector<String> ftr = ftr_edit->get_text().split(","); - for (int i = 0; i < ftr.size(); i++) { - Vector<String> tokens = ftr[i].split("="); - if (tokens.size() == 2) { - ftrs[tokens[0]] = tokens[1].to_int(); - } else if (tokens.size() == 1) { - ftrs[tokens[0]] = 1; - } - } + Ref<DynamicFontImportSettingsData> import_variation_data; + TreeItem *vars_item = vars_list->get_selected(); + if (vars_item) { + import_variation_data = vars_item->get_metadata(0); + } + if (import_variation_data.is_null()) { + return; + } RID text_rid = TS->create_shaped_text(); if (text_rid.is_valid()) { - TS->shaped_text_add_string(text_rid, text_edit->get_text(), font_main->get_rids(), 16, ftrs, text_edit->get_language()); + TS->shaped_text_add_string(text_rid, text_edit->get_text(), font_main->get_rids(), 16, text_settings_data->get("opentype_features"), text_settings_data->get("language")); TS->shaped_text_shape(text_rid); const Glyph *gl = TS->shaped_text_get_glyphs(text_rid); const int gl_size = TS->shaped_text_get_glyph_count(text_rid); for (int i = 0; i < gl_size; i++) { if (gl[i].font_rid.is_valid() && gl[i].index != 0) { - selected_glyphs.insert(gl[i].index); + import_variation_data->selected_glyphs.insert(gl[i].index); } } TS->free_rid(text_rid); - label_glyphs->set_text(TTR("Preloaded glyphs:") + " " + itos(selected_glyphs.size())); + label_glyphs->set_text(TTR("Preloaded glyphs:") + " " + itos(import_variation_data->selected_glyphs.size())); } _range_selected(); } /*************************************************************************/ -/* Page 4 callbacks: Character map */ +/* Page 2.2 callbacks: Character map */ /*************************************************************************/ void DynamicFontImportSettings::_glyph_selected() { + Ref<DynamicFontImportSettingsData> import_variation_data; + + TreeItem *vars_item = vars_list->get_selected(); + if (vars_item) { + import_variation_data = vars_item->get_metadata(0); + } + if (import_variation_data.is_null()) { + return; + } + TreeItem *item = glyph_table->get_selected(); ERR_FAIL_NULL(item); @@ -685,7 +686,7 @@ void DynamicFontImportSettings::_glyph_selected() { item->clear_custom_bg_color(glyph_table->get_selected_column()); } } - label_glyphs->set_text(TTR("Preloaded glyphs:") + " " + itos(selected_glyphs.size())); + label_glyphs->set_text(TTR("Preloaded glyphs:") + " " + itos(import_variation_data->selected_glyphs.size())); item = glyph_tree->get_selected(); ERR_FAIL_NULL(item); @@ -698,7 +699,7 @@ void DynamicFontImportSettings::_glyph_selected() { total_chars--; } - if (selected_chars.has(i)) { + if (import_variation_data->selected_chars.has(i)) { selected_count++; } } @@ -728,6 +729,16 @@ void DynamicFontImportSettings::_range_selected() { } void DynamicFontImportSettings::_edit_range(int32_t p_start, int32_t p_end) { + Ref<DynamicFontImportSettingsData> import_variation_data; + + TreeItem *vars_item = vars_list->get_selected(); + if (vars_item) { + import_variation_data = vars_item->get_metadata(0); + } + if (import_variation_data.is_null()) { + return; + } + glyph_table->clear(); TreeItem *root = glyph_table->create_item(); @@ -740,6 +751,8 @@ void DynamicFontImportSettings::_edit_range(int32_t p_start, int32_t p_end) { TreeItem *item = nullptr; int col = 0; + Ref<Font> font_main_big = font_main->duplicate(); + for (int32_t c = p_start; c <= p_end; c++) { if (col == 0) { item = glyph_table->create_item(root); @@ -752,7 +765,7 @@ void DynamicFontImportSettings::_edit_range(int32_t p_start, int32_t p_end) { if (font_main->has_char(c)) { item->set_text(col + 1, String::chr(c)); item->set_custom_color(col + 1, Color(1, 1, 1)); - if (selected_chars.has(c) || (font_main->get_data(0).is_valid() && selected_glyphs.has(font_main->get_data(0)->get_glyph_index(get_theme_font_size(SNAME("font_size")) * 2, c)))) { + if (import_variation_data->selected_chars.has(c) || import_variation_data->selected_glyphs.has(font_main->get_glyph_index(16, c))) { item->set_custom_color(col + 1, fcol); item->set_custom_bg_color(col + 1, scol); } else { @@ -765,7 +778,8 @@ void DynamicFontImportSettings::_edit_range(int32_t p_start, int32_t p_end) { item->set_metadata(col + 1, c); item->set_text_alignment(col + 1, HORIZONTAL_ALIGNMENT_CENTER); item->set_selectable(col + 1, true); - item->set_custom_font(col + 1, font_main); + + item->set_custom_font(col + 1, font_main_big); item->set_custom_font_size(col + 1, get_theme_font_size(SNAME("font_size")) * 2); col++; @@ -773,41 +787,61 @@ void DynamicFontImportSettings::_edit_range(int32_t p_start, int32_t p_end) { col = 0; } } - label_glyphs->set_text(TTR("Preloaded glyphs:") + " " + itos(selected_glyphs.size())); + label_glyphs->set_text(TTR("Preloaded glyphs:") + " " + itos(import_variation_data->selected_glyphs.size())); } bool DynamicFontImportSettings::_char_update(int32_t p_char) { - if (selected_chars.has(p_char)) { - selected_chars.erase(p_char); + Ref<DynamicFontImportSettingsData> import_variation_data; + + TreeItem *vars_item = vars_list->get_selected(); + if (vars_item) { + import_variation_data = vars_item->get_metadata(0); + } + if (import_variation_data.is_null()) { return false; - } else if (font_main->get_data(0).is_valid() && selected_glyphs.has(font_main->get_data(0)->get_glyph_index(get_theme_font_size(SNAME("font_size")) * 2, p_char))) { - selected_glyphs.erase(font_main->get_data(0)->get_glyph_index(get_theme_font_size(SNAME("font_size")) * 2, p_char)); + } + + if (import_variation_data->selected_chars.has(p_char)) { + import_variation_data->selected_chars.erase(p_char); + return false; + } else if (font_main.is_valid() && font_main.is_valid() && import_variation_data->selected_glyphs.has(font_main->get_glyph_index(16, p_char))) { + import_variation_data->selected_glyphs.erase(font_main->get_glyph_index(16, p_char)); return false; } else { - selected_chars.insert(p_char); + import_variation_data->selected_chars.insert(p_char); return true; } } void DynamicFontImportSettings::_range_update(int32_t p_start, int32_t p_end) { + Ref<DynamicFontImportSettingsData> import_variation_data; + + TreeItem *vars_item = vars_list->get_selected(); + if (vars_item) { + import_variation_data = vars_item->get_metadata(0); + } + if (import_variation_data.is_null()) { + return; + } + bool all_selected = true; for (int32_t i = p_start; i <= p_end; i++) { if (font_main->has_char(i)) { - if (font_main->get_data(0).is_valid()) { - all_selected = all_selected && (selected_chars.has(i) || (font_main->get_data(0).is_valid() && selected_glyphs.has(font_main->get_data(0)->get_glyph_index(get_theme_font_size(SNAME("font_size")) * 2, i)))); + if (font_main.is_valid()) { + all_selected = all_selected && (import_variation_data->selected_chars.has(i) || import_variation_data->selected_glyphs.has(font_main->get_glyph_index(16, i))); } else { - all_selected = all_selected && selected_chars.has(i); + all_selected = all_selected && import_variation_data->selected_chars.has(i); } } } for (int32_t i = p_start; i <= p_end; i++) { if (font_main->has_char(i)) { if (!all_selected) { - selected_chars.insert(i); + import_variation_data->selected_chars.insert(i); } else { - selected_chars.erase(i); - if (font_main->get_data(0).is_valid()) { - selected_glyphs.erase(font_main->get_data(0)->get_glyph_index(get_theme_font_size(SNAME("font_size")) * 2, i)); + import_variation_data->selected_chars.erase(i); + if (font_main.is_valid()) { + import_variation_data->selected_glyphs.erase(font_main->get_glyph_index(16, i)); } } } @@ -820,106 +854,6 @@ void DynamicFontImportSettings::_range_update(int32_t p_start, int32_t p_end) { } /*************************************************************************/ -/* Page 5 callbacks: CMetadata override */ -/*************************************************************************/ - -void DynamicFontImportSettings::_lang_add() { - locale_select->popup_locale_dialog(); -} - -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, p_locale); - lang_item->set_editable(1, true); - lang_item->add_button(2, lang_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove")); - lang_item->set_button_color(2, 0, Color(1, 1, 1, 0.75)); -} - -void DynamicFontImportSettings::_lang_remove(Object *p_item, int p_column, int p_id, MouseButton p_button) { - if (p_button != MouseButton::LEFT) { - return; - } - - TreeItem *lang_item = (TreeItem *)p_item; - ERR_FAIL_NULL(lang_item); - - lang_list_root->remove_child(lang_item); - memdelete(lang_item); -} - -void DynamicFontImportSettings::_ot_add() { - menu_ot->set_position(ot_list->get_screen_transform().xform(ot_list->get_local_mouse_position())); - menu_ot->set_size(Vector2(1, 1)); - menu_ot->popup(); -} - -void DynamicFontImportSettings::_ot_add_item(int p_option) { - String name = TS->tag_to_name(p_option); - for (TreeItem *ot_item = ot_list_root->get_first_child(); ot_item; ot_item = ot_item->get_next()) { - if (ot_item->get_text(0) == name) { - return; - } - } - TreeItem *ot_item = ot_list->create_item(ot_list_root); - ERR_FAIL_NULL(ot_item); - - ot_item->set_text(0, name); - ot_item->set_editable(0, false); - ot_item->set_text(1, "1"); - ot_item->set_editable(1, true); - ot_item->add_button(2, ot_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove")); - ot_item->set_button_color(2, 0, Color(1, 1, 1, 0.75)); -} - -void DynamicFontImportSettings::_ot_remove(Object *p_item, int p_column, int p_id, MouseButton p_button) { - if (p_button != MouseButton::LEFT) { - return; - } - - TreeItem *ot_item = (TreeItem *)p_item; - ERR_FAIL_NULL(ot_item); - - ot_list_root->remove_child(ot_item); - memdelete(ot_item); -} - -void DynamicFontImportSettings::_script_add() { - menu_scripts->set_position(script_list->get_screen_position() + script_list->get_local_mouse_position()); - menu_scripts->reset_size(); - menu_scripts->popup(); -} - -void DynamicFontImportSettings::_script_add_item(int p_option) { - TreeItem *script_item = script_list->create_item(script_list_root); - ERR_FAIL_NULL(script_item); - - 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, script_codes[p_option]); - script_item->set_editable(1, true); - script_item->add_button(2, lang_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove")); - script_item->set_button_color(2, 0, Color(1, 1, 1, 0.75)); -} - -void DynamicFontImportSettings::_script_remove(Object *p_item, int p_column, int p_id, MouseButton p_button) { - if (p_button != MouseButton::LEFT) { - return; - } - - TreeItem *script_item = (TreeItem *)p_item; - ERR_FAIL_NULL(script_item); - - script_list_root->remove_child(script_item); - memdelete(script_item); -} - -/*************************************************************************/ /* Common */ /*************************************************************************/ @@ -938,10 +872,7 @@ void DynamicFontImportSettings::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - add_lang->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); - add_script->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); add_var->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); - add_ot->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); } break; } } @@ -958,90 +889,40 @@ void DynamicFontImportSettings::_re_import() { main_settings["force_autohinter"] = import_settings_data->get("force_autohinter"); main_settings["hinting"] = import_settings_data->get("hinting"); main_settings["subpixel_positioning"] = import_settings_data->get("subpixel_positioning"); - main_settings["embolden"] = import_settings_data->get("embolden"); - main_settings["transform"] = import_settings_data->get("transform"); main_settings["oversampling"] = import_settings_data->get("oversampling"); + main_settings["fallbacks"] = import_settings_data->get("fallbacks"); main_settings["compress"] = import_settings_data->get("compress"); - Vector<String> variations; + Array configurations; for (TreeItem *vars_item = vars_list_root->get_first_child(); vars_item; vars_item = vars_item->get_next()) { - String variation; Ref<DynamicFontImportSettingsData> import_variation_data = vars_item->get_metadata(0); ERR_FAIL_NULL(import_variation_data); - String name = vars_item->get_text(0); - variation += ("name=" + name); + Dictionary preload_config; + preload_config["name"] = vars_item->get_text(0); + for (const KeyValue<StringName, Variant> &E : import_variation_data->settings) { - if (!variation.is_empty()) { - variation += ","; - } - variation += (String(E.key) + "=" + String(E.value)); - } - variations.push_back(variation); - } - main_settings["preload/configurations"] = variations; - - Vector<String> langs_enabled; - Vector<String> langs_disabled; - for (TreeItem *lang_item = lang_list_root->get_first_child(); lang_item; lang_item = lang_item->get_next()) { - bool selected = lang_item->is_checked(0); - String name = lang_item->get_text(1); - if (selected) { - langs_enabled.push_back(name); - } else { - langs_disabled.push_back(name); + preload_config[E.key] = E.value; } - } - main_settings["support_overrides/language_enabled"] = langs_enabled; - main_settings["support_overrides/language_disabled"] = langs_disabled; - - Vector<String> scripts_enabled; - Vector<String> scripts_disabled; - for (TreeItem *script_item = script_list_root->get_first_child(); script_item; script_item = script_item->get_next()) { - bool selected = script_item->is_checked(0); - String name = script_item->get_text(1); - if (selected) { - scripts_enabled.push_back(name); - } else { - scripts_disabled.push_back(name); - } - } - main_settings["support_overrides/script_enabled"] = scripts_enabled; - main_settings["support_overrides/script_disabled"] = scripts_disabled; - - if (!selected_chars.is_empty()) { - Vector<String> ranges; - char32_t start = selected_chars.front()->get(); - for (RBSet<char32_t>::Element *E = selected_chars.front()->next(); E; E = E->next()) { - if (E->prev() && ((E->prev()->get() + 1) != E->get())) { - ranges.push_back(String("0x") + String::num_int64(start, 16) + String("-0x") + String::num_int64(E->prev()->get(), 16)); - start = E->get(); - } + + Array chars; + for (const char32_t &E : import_variation_data->selected_chars) { + chars.push_back(E); } - ranges.push_back(String("0x") + String::num_int64(start, 16) + String("-0x") + String::num_int64(selected_chars.back()->get(), 16)); - main_settings["preload/char_ranges"] = ranges; - } + preload_config["chars"] = chars; - if (!selected_glyphs.is_empty()) { - Vector<String> ranges; - int32_t start = selected_glyphs.front()->get(); - for (RBSet<int32_t>::Element *E = selected_glyphs.front()->next(); E; E = E->next()) { - if (E->prev() && ((E->prev()->get() + 1) != E->get())) { - ranges.push_back(String("0x") + String::num_int64(start, 16) + String("-0x") + String::num_int64(E->prev()->get(), 16)); - start = E->get(); - } + Array glyphs; + for (const int32_t &E : import_variation_data->selected_glyphs) { + glyphs.push_back(E); } - ranges.push_back(String("0x") + String::num_int64(start, 16) + String("-0x") + String::num_int64(selected_glyphs.back()->get(), 16)); - main_settings["preload/glyph_ranges"] = ranges; - } + preload_config["glyphs"] = glyphs; - Dictionary ot_ov; - for (TreeItem *ot_item = ot_list_root->get_first_child(); ot_item; ot_item = ot_item->get_next()) { - String tag = ot_item->get_text(0); - int32_t value = ot_item->get_text(1).to_int(); - ot_ov[tag] = value; + configurations.push_back(preload_config); } - main_settings["opentype_feature_overrides"] = ot_ov; + main_settings["preload"] = configurations; + main_settings["language_support"] = import_settings_data->get("language_support"); + main_settings["script_support"] = import_settings_data->get("script_support"); + main_settings["opentype_features"] = import_settings_data->get("opentype_features"); if (OS::get_singleton()->is_stdout_verbose()) { print_line("Import settings:"); @@ -1058,33 +939,33 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { Vector<uint8_t> data = FileAccess::get_file_as_array(p_path); // Load font for preview. - Ref<FontData> dfont_prev; - dfont_prev.instantiate(); - dfont_prev->set_data(data); - font_preview.instantiate(); - font_preview->add_data(dfont_prev); + font_preview->set_data(data); + String font_name = vformat("%s (%s)", font_preview->get_font_name(), font_preview->get_font_style_name()); String sample; static const String sample_base = U"12漢字ԱբΑαАбΑαאבابܐܒހށआআਆઆଆஆఆಆആආกิກິༀကႠა한글ሀᎣᐁᚁᚠᜀᜠᝀᝠកᠠᤁᥐAb😀"; for (int i = 0; i < sample_base.length(); i++) { - if (dfont_prev->has_char(sample_base[i])) { + if (font_preview->has_char(sample_base[i])) { sample += sample_base[i]; } } if (sample.is_empty()) { - sample = dfont_prev->get_supported_chars().substr(0, 6); + sample = font_preview->get_supported_chars().substr(0, 6); } font_preview_label->set_text(sample); - // Load second copy of font with MSDF disabled for the glyph table and metadata extraction. - Ref<FontData> dfont_main; - dfont_main.instantiate(); - dfont_main->set_data(data); - dfont_main->set_multichannel_signed_distance_field(false); + Ref<Font> bold_font = get_theme_font(SNAME("bold"), SNAME("EditorFonts")); + if (bold_font.is_valid() && bold_font.is_valid()) { + font_name_label->add_theme_font_override("bold_font", bold_font); + } + font_name_label->set_text(font_name); + // Load second copy of font with MSDF disabled for the glyph table and metadata extraction. font_main.instantiate(); - font_main->add_data(dfont_main); + font_main->set_data(data); + font_main->set_multichannel_signed_distance_field(false); + text_edit->add_theme_font_override("font", font_main); base_path = p_path; @@ -1092,35 +973,27 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { inspector_vars->edit(nullptr); inspector_general->edit(nullptr); - int gww = get_theme_font(SNAME("font"))->get_string_size("00000", get_theme_font_size(SNAME("font_size"))).x + 50; + text_settings_data.instantiate(); + ERR_FAIL_NULL(text_settings_data); + + text_settings_data->owner = this; + + for (List<ResourceImporter::ImportOption>::Element *F = options_text.front(); F; F = F->next()) { + text_settings_data->defaults[F->get().option.name] = F->get().default_value; + } + + text_settings_data->fd = font_main; + text_settings_data->options = options_text; + + inspector_text->edit(text_settings_data.ptr()); + + int gww = get_theme_font(SNAME("font"))->get_string_size("00000").x + 50; glyph_table->set_column_custom_minimum_width(0, gww); glyph_table->clear(); vars_list->clear(); - lang_list->clear(); - script_list->clear(); - ot_list->clear(); - - selected_chars.clear(); - selected_glyphs.clear(); - text_edit->set_text(String()); vars_list_root = vars_list->create_item(); - lang_list_root = lang_list->create_item(); - script_list_root = script_list->create_item(); - ot_list_root = ot_list->create_item(); - - options_variations.clear(); - Dictionary var_list = dfont_main->get_supported_variation_list(); - for (int i = 0; i < var_list.size(); i++) { - int32_t tag = var_list.get_key_at_index(i); - Vector3i value = var_list.get_value_at_index(i); - options_variations.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, TS->tag_to_name(tag), PROPERTY_HINT_RANGE, itos(value.x) + "," + itos(value.y) + ",1"), value.z)); - } - options_variations.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "size", PROPERTY_HINT_RANGE, "0,127,1"), 16)); - options_variations.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "outline_size", PROPERTY_HINT_RANGE, "0,127,1"), 0)); - options_variations.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "extra_spacing_glyph"), 0)); - options_variations.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "extra_spacing_space"), 0)); import_settings_data->defaults.clear(); for (List<ResourceImporter::ImportOption>::Element *E = options_general.front(); E; E = E->next()) { @@ -1139,157 +1012,58 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { for (List<String>::Element *E = keys.front(); E; E = E->next()) { String key = E->get(); print_verbose(String(" ") + key + " == " + String(config->get_value("params", key))); - if (key == "preload/char_ranges") { - Vector<String> ranges = config->get_value("params", key); - for (int i = 0; i < ranges.size(); i++) { - int32_t start, end; - Vector<String> tokens = ranges[i].split("-"); - if (tokens.size() == 2) { - if (!ResourceImporterDynamicFont::_decode_range(tokens[0], start) || !ResourceImporterDynamicFont::_decode_range(tokens[1], end)) { - WARN_PRINT("Invalid range: \"" + ranges[i] + "\""); - continue; - } - } else if (tokens.size() == 1) { - if (!ResourceImporterDynamicFont::_decode_range(tokens[0], start)) { - WARN_PRINT("Invalid range: \"" + ranges[i] + "\""); - continue; - } - end = start; - } else { - WARN_PRINT("Invalid range: \"" + ranges[i] + "\""); - continue; - } - for (int32_t j = start; j <= end; j++) { - selected_chars.insert(j); - } - } - } else if (key == "preload/glyph_ranges") { - Vector<String> ranges = config->get_value("params", key); - for (int i = 0; i < ranges.size(); i++) { - int32_t start, end; - Vector<String> tokens = ranges[i].split("-"); - if (tokens.size() == 2) { - if (!ResourceImporterDynamicFont::_decode_range(tokens[0], start) || !ResourceImporterDynamicFont::_decode_range(tokens[1], end)) { - WARN_PRINT("Invalid range: \"" + ranges[i] + "\""); - continue; - } - } else if (tokens.size() == 1) { - if (!ResourceImporterDynamicFont::_decode_range(tokens[0], start)) { - WARN_PRINT("Invalid range: \"" + ranges[i] + "\""); - continue; - } - end = start; - } else { - WARN_PRINT("Invalid range: \"" + ranges[i] + "\""); - continue; - } - for (int32_t j = start; j <= end; j++) { - selected_glyphs.insert(j); - } - } - } else if (key == "preload/configurations") { - Vector<String> variations = config->get_value("params", key); - for (int i = 0; i < variations.size(); i++) { + if (key == "preload") { + Array preload_configurations = config->get_value("params", key); + for (int i = 0; i < preload_configurations.size(); i++) { + Dictionary preload_config = preload_configurations[i]; + + Dictionary variation = preload_config.has("variation_opentype") ? preload_config["variation_opentype"].operator Dictionary() : Dictionary(); + double embolden = preload_config.has("variation_embolden") ? preload_config["variation_embolden"].operator double() : 0; + int face_index = preload_config.has("variation_face_index") ? preload_config["variation_face_index"].operator int() : 0; + Transform2D transform = preload_config.has("variation_transform") ? preload_config["variation_transform"].operator Transform2D() : Transform2D(); + Vector2i size = preload_config.has("size") ? preload_config["size"].operator Vector2i() : Vector2i(16, 0); + String cfg_name = preload_config.has("name") ? preload_config["name"].operator String() : vformat("Configuration %d", i); + TreeItem *vars_item = vars_list->create_item(vars_list_root); ERR_FAIL_NULL(vars_item); - vars_item->set_text(0, TTR("Configuration") + " " + itos(i)); + vars_item->set_text(0, cfg_name); vars_item->set_editable(0, true); vars_item->add_button(1, vars_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove Variation")); vars_item->set_button_color(1, 0, Color(1, 1, 1, 0.75)); Ref<DynamicFontImportSettingsData> import_variation_data_custom; import_variation_data_custom.instantiate(); - import_variation_data_custom->owner = this; ERR_FAIL_NULL(import_variation_data_custom); + import_variation_data_custom->owner = this; for (List<ResourceImporter::ImportOption>::Element *F = options_variations.front(); F; F = F->next()) { import_variation_data_custom->defaults[F->get().option.name] = F->get().default_value; } - import_variation_data_custom->options = options_variations; + import_variation_data_custom->fd = font_main; + import_variation_data_custom->options = options_variations; vars_item->set_metadata(0, import_variation_data_custom); - Vector<String> variation_tags = variations[i].split(","); - for (int j = 0; j < variation_tags.size(); j++) { - Vector<String> tokens = variation_tags[j].split("="); - if (tokens[0] == "name") { - vars_item->set_text(0, tokens[1]); - } else if (tokens[0] == "size" || tokens[0] == "outline_size" || tokens[0] == "extra_spacing_space" || tokens[0] == "extra_spacing_glyph") { - import_variation_data_custom->set(tokens[0], tokens[1].to_int()); - } else { - import_variation_data_custom->set(tokens[0], tokens[1].to_float()); - } + + import_variation_data_custom->set("size", size.x); + import_variation_data_custom->set("outline_size", size.y); + import_variation_data_custom->set("variation_opentype", variation); + import_variation_data_custom->set("variation_embolden", embolden); + import_variation_data_custom->set("variation_face_index", face_index); + import_variation_data_custom->set("variation_transform", transform); + + Array chars = preload_config["chars"]; + for (int j = 0; j < chars.size(); j++) { + char32_t c = chars[j].operator int(); + import_variation_data_custom->selected_chars.insert(c); } - } - } else if (key == "support_overrides/language_enabled") { - PackedStringArray _langs = config->get_value("params", key); - for (int i = 0; i < _langs.size(); i++) { - 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, true); - lang_item->set_text(1, _langs[i]); - lang_item->set_editable(1, true); - lang_item->add_button(2, lang_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove")); - } - } else if (key == "support_overrides/language_disabled") { - PackedStringArray _langs = config->get_value("params", key); - for (int i = 0; i < _langs.size(); i++) { - 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[i]); - lang_item->set_editable(1, true); - lang_item->add_button(2, lang_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove")); - } - } else if (key == "support_overrides/script_enabled") { - PackedStringArray _scripts = config->get_value("params", key); - for (int i = 0; i < _scripts.size(); i++) { - TreeItem *script_item = script_list->create_item(script_list_root); - ERR_FAIL_NULL(script_item); - - script_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); - script_item->set_editable(0, true); - script_item->set_checked(0, true); - script_item->set_text(1, _scripts[i]); - script_item->set_editable(1, true); - script_item->add_button(2, lang_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove")); - } - } else if (key == "support_overrides/script_disabled") { - PackedStringArray _scripts = config->get_value("params", key); - for (int i = 0; i < _scripts.size(); i++) { - TreeItem *script_item = script_list->create_item(script_list_root); - ERR_FAIL_NULL(script_item); - - 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[i]); - script_item->set_editable(1, true); - script_item->add_button(2, lang_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove")); - } - } else if (key == "opentype_feature_overrides") { - Dictionary features = config->get_value("params", key); - for (const Variant *ftr = features.next(nullptr); ftr != nullptr; ftr = features.next(ftr)) { - TreeItem *ot_item = ot_list->create_item(ot_list_root); - ERR_FAIL_NULL(ot_item); - int32_t value = features[*ftr]; - if (ftr->get_type() == Variant::STRING) { - ot_item->set_text(0, *ftr); - } else { - ot_item->set_text(0, TS->tag_to_name(*ftr)); + + Array glyphs = preload_config["glyphs"]; + for (int j = 0; j < glyphs.size(); j++) { + int32_t c = glyphs[j]; + import_variation_data_custom->selected_glyphs.insert(c); } - ot_item->set_editable(0, false); - ot_item->set_text(1, itos(value)); - ot_item->set_editable(1, true); - ot_item->add_button(2, ot_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove")); - ot_item->set_button_color(2, 0, Color(1, 1, 1, 0.75)); } } else { Variant value = config->get_value("params", key); @@ -1297,61 +1071,26 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { } } } - label_glyphs->set_text(TTR("Preloaded glyphs:") + " " + itos(selected_glyphs.size())); + import_settings_data->fd = font_main; import_settings_data->options = options_general; inspector_general->edit(import_settings_data.ptr()); import_settings_data->notify_property_list_changed(); - if (font_preview->get_data_count() > 0) { - font_preview->get_data(0)->set_face_index(import_settings_data->get("face_index")); - font_preview->get_data(0)->set_antialiased(import_settings_data->get("antialiased")); - font_preview->get_data(0)->set_multichannel_signed_distance_field(import_settings_data->get("multichannel_signed_distance_field")); - font_preview->get_data(0)->set_msdf_pixel_range(import_settings_data->get("msdf_pixel_range")); - font_preview->get_data(0)->set_msdf_size(import_settings_data->get("msdf_size")); - font_preview->get_data(0)->set_force_autohinter(import_settings_data->get("force_autohinter")); - font_preview->get_data(0)->set_hinting((TextServer::Hinting)import_settings_data->get("hinting").operator int()); - font_preview->get_data(0)->set_subpixel_positioning((TextServer::SubpixelPositioning)import_settings_data->get("subpixel_positioning").operator int()); - font_preview->get_data(0)->set_embolden(import_settings_data->get("embolden")); - font_preview->get_data(0)->set_transform(import_settings_data->get("transform")); - font_preview->get_data(0)->set_oversampling(import_settings_data->get("oversampling")); + if (font_preview.is_valid()) { + font_preview->set_antialiased(import_settings_data->get("antialiased")); + font_preview->set_multichannel_signed_distance_field(import_settings_data->get("multichannel_signed_distance_field")); + font_preview->set_msdf_pixel_range(import_settings_data->get("msdf_pixel_range")); + font_preview->set_msdf_size(import_settings_data->get("msdf_size")); + font_preview->set_force_autohinter(import_settings_data->get("force_autohinter")); + font_preview->set_hinting((TextServer::Hinting)import_settings_data->get("hinting").operator int()); + font_preview->set_subpixel_positioning((TextServer::SubpixelPositioning)import_settings_data->get("subpixel_positioning").operator int()); + font_preview->set_oversampling(import_settings_data->get("oversampling")); } font_preview_label->add_theme_font_override("font", font_preview); + font_preview_label->add_theme_font_size_override("font_size", 200 * EDSCALE); font_preview_label->update(); - menu_ot->clear(); - menu_ot_ss->clear(); - menu_ot_cv->clear(); - menu_ot_cu->clear(); - bool have_ss = false; - bool have_cv = false; - bool have_cu = false; - Dictionary features = font_preview->get_feature_list(); - for (const Variant *ftr = features.next(nullptr); ftr != nullptr; ftr = features.next(ftr)) { - String ftr_name = TS->tag_to_name(*ftr); - if (ftr_name.begins_with("stylistic_set_")) { - menu_ot_ss->add_item(ftr_name.capitalize(), (int32_t)*ftr); - have_ss = true; - } else if (ftr_name.begins_with("character_variant_")) { - menu_ot_cv->add_item(ftr_name.capitalize(), (int32_t)*ftr); - have_cv = true; - } else if (ftr_name.begins_with("custom_")) { - menu_ot_cu->add_item(ftr_name.replace("custom_", ""), (int32_t)*ftr); - have_cu = true; - } else { - menu_ot->add_item(ftr_name.capitalize(), (int32_t)*ftr); - } - } - if (have_ss) { - menu_ot->add_submenu_item(RTR("Stylistic Sets"), "SSMenu"); - } - if (have_cv) { - menu_ot->add_submenu_item(RTR("Character Variants"), "CVMenu"); - } - if (have_cu) { - menu_ot->add_submenu_item(RTR("Custom"), "CUMenu"); - } - _variations_validate(); popup_centered_ratio(); @@ -1366,7 +1105,8 @@ DynamicFontImportSettings *DynamicFontImportSettings::get_singleton() { DynamicFontImportSettings::DynamicFontImportSettings() { singleton = this; - options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "face_index"), 0)); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::NIL, "Rendering", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant())); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "antialiased"), true)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "generate_mipmaps"), false)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true)); @@ -1375,44 +1115,29 @@ DynamicFontImportSettings::DynamicFontImportSettings() { options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "force_autohinter"), false)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), 1)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel"), 1)); - options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "embolden", PROPERTY_HINT_RANGE, "-2,2,0.01"), 0.f)); - options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::TRANSFORM2D, "transform"), Transform2D())); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_RANGE, "0,10,0.1"), 0.0)); - options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "compress", PROPERTY_HINT_NONE, ""), false)); - - // Popup menus - - 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"); - 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)); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::NIL, "Metadata Overrides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant())); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::DICTIONARY, "language_support"), Dictionary())); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::DICTIONARY, "script_support"), Dictionary())); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::DICTIONARY, "opentype_features"), Dictionary())); - menu_ot = memnew(PopupMenu); - add_child(menu_ot); - menu_ot->connect("id_pressed", callable_mp(this, &DynamicFontImportSettings::_ot_add_item)); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::NIL, "Fallbacks", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant())); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font")), Array())); - menu_ot_cv = memnew(PopupMenu); - menu_ot_cv->set_name("CVMenu"); - menu_ot->add_child(menu_ot_cv); - menu_ot_cv->connect("id_pressed", callable_mp(this, &DynamicFontImportSettings::_ot_add_item)); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::NIL, "Compress", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant())); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "compress", PROPERTY_HINT_NONE, ""), false)); - menu_ot_ss = memnew(PopupMenu); - menu_ot_ss->set_name("SSMenu"); - menu_ot->add_child(menu_ot_ss); - menu_ot_ss->connect("id_pressed", callable_mp(this, &DynamicFontImportSettings::_ot_add_item)); + options_text.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::DICTIONARY, "opentype_features"), Dictionary())); + options_text.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "")); - menu_ot_cu = memnew(PopupMenu); - menu_ot_cu->set_name("CUMenu"); - menu_ot->add_child(menu_ot_cu); - menu_ot_cu->connect("id_pressed", callable_mp(this, &DynamicFontImportSettings::_ot_add_item)); + options_variations.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "size", PROPERTY_HINT_RANGE, "0,127,1"), 16)); + options_variations.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "outline_size", PROPERTY_HINT_RANGE, "0,127,1"), 0)); + options_variations.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::NIL, "Variation", PROPERTY_HINT_NONE, "variation", PROPERTY_USAGE_GROUP), Variant())); + options_variations.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::DICTIONARY, "variation_opentype"), Dictionary())); + options_variations.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "variation_embolden", PROPERTY_HINT_RANGE, "-2,2,0.01"), 0)); + options_variations.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "variation_face_index"), 0)); + options_variations.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::TRANSFORM2D, "variation_transform"), Transform2D())); Color warn_color = (EditorNode::get_singleton()) ? EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor")) : Color(1, 1, 0); @@ -1442,7 +1167,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { main_pages->add_child(page1_vb); page1_description = memnew(Label); - page1_description->set_text(TTR("Select font rendering options:")); + page1_description->set_text(TTR("Select font rendering options, fallback font, and metadata override:")); page1_description->set_h_size_flags(Control::SIZE_EXPAND_FILL); page1_vb->add_child(page1_description); @@ -1451,15 +1176,25 @@ DynamicFontImportSettings::DynamicFontImportSettings() { page1_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); page1_vb->add_child(page1_hb); + VBoxContainer *page1_lbl_vb = memnew(VBoxContainer); + page1_lbl_vb->set_v_size_flags(Control::SIZE_EXPAND_FILL); + page1_lbl_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + page1_hb->add_child(page1_lbl_vb); + + font_name_label = memnew(Label); + font_name_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); + font_name_label->set_clip_text(true); + font_name_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + page1_lbl_vb->add_child(font_name_label); + font_preview_label = memnew(Label); - font_preview_label->add_theme_font_size_override("font_size", 200 * EDSCALE); font_preview_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); font_preview_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); font_preview_label->set_autowrap_mode(TextServer::AUTOWRAP_ARBITRARY); font_preview_label->set_clip_text(true); font_preview_label->set_v_size_flags(Control::SIZE_EXPAND_FILL); font_preview_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); - page1_hb->add_child(font_preview_label); + page1_lbl_vb->add_child(font_preview_label); inspector_general = memnew(EditorInspector); inspector_general->set_v_size_flags(Control::SIZE_EXPAND_FILL); @@ -1469,11 +1204,11 @@ DynamicFontImportSettings::DynamicFontImportSettings() { // Page 2 layout: Configurations VBoxContainer *page2_vb = memnew(VBoxContainer); - page2_vb->set_name(TTR("Sizes and Variations")); + page2_vb->set_name(TTR("Pre-render configurations")); main_pages->add_child(page2_vb); page2_description = memnew(Label); - page2_description->set_text(TTR("Add font size, variation coordinates, and extra spacing combinations to pre-render:")); + page2_description->set_text(TTR("Add font size, and variation coordinates, and select glyphs to pre-render:")); page2_description->set_h_size_flags(Control::SIZE_EXPAND_FILL); page2_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); page2_vb->add_child(page2_description); @@ -1517,48 +1252,44 @@ DynamicFontImportSettings::DynamicFontImportSettings() { inspector_vars = memnew(EditorInspector); inspector_vars->set_v_size_flags(Control::SIZE_EXPAND_FILL); inspector_vars->connect("property_edited", callable_mp(this, &DynamicFontImportSettings::_variation_changed)); - page2_hb->add_child(inspector_vars); - - // Page 3 layout: Text to select glyphs - VBoxContainer *page3_vb = memnew(VBoxContainer); - page3_vb->set_name(TTR("Glyphs from the Text")); - main_pages->add_child(page3_vb); + page2_side_vb->add_child(inspector_vars); - page3_description = memnew(Label); - page3_description->set_text(TTR("Enter a text to shape and add all required glyphs to pre-render list:")); - page3_description->set_h_size_flags(Control::SIZE_EXPAND_FILL); - page3_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); - page3_vb->add_child(page3_description); + preload_pages = memnew(TabContainer); + preload_pages->set_tab_alignment(TabBar::ALIGNMENT_CENTER); + preload_pages->set_v_size_flags(Control::SIZE_EXPAND_FILL); + preload_pages->set_h_size_flags(Control::SIZE_EXPAND_FILL); + page2_hb->add_child(preload_pages); - HBoxContainer *ot_hb = memnew(HBoxContainer); - page3_vb->add_child(ot_hb); - ot_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + // Page 2.1 layout: Text to select glyphs + VBoxContainer *page2_1_vb = memnew(VBoxContainer); + page2_1_vb->set_name(TTR("Glyphs from the Text")); + preload_pages->add_child(page2_1_vb); - Label *label_ed_ftr = memnew(Label); - ot_hb->add_child(label_ed_ftr); - label_ed_ftr->set_text(TTR("OpenType features:")); + page2_1_description = memnew(Label); + page2_1_description->set_text(TTR("Enter a text to shape and add all required glyphs to pre-render list:")); + page2_1_description->set_h_size_flags(Control::SIZE_EXPAND_FILL); + page2_1_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + page2_1_vb->add_child(page2_1_description); - ftr_edit = memnew(LineEdit); - ot_hb->add_child(ftr_edit); - ftr_edit->connect("text_changed", callable_mp(this, &DynamicFontImportSettings::_change_text_opts)); - ftr_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL); + HSplitContainer *page2_1_hb = memnew(HSplitContainer); + page2_1_vb->add_child(page2_1_hb); + page2_1_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + page2_1_hb->set_v_size_flags(Control::SIZE_EXPAND_FILL); - Label *label_ed_lang = memnew(Label); - ot_hb->add_child(label_ed_lang); - label_ed_lang->set_text(TTR("Text language:")); + inspector_text = memnew(EditorInspector); - lang_edit = memnew(LineEdit); - ot_hb->add_child(lang_edit); - lang_edit->connect("text_changed", callable_mp(this, &DynamicFontImportSettings::_change_text_opts)); - lang_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL); + inspector_text->set_v_size_flags(Control::SIZE_EXPAND_FILL); + inspector_text->set_custom_minimum_size(Size2(300 * EDSCALE, 250 * EDSCALE)); + inspector_text->connect("property_edited", callable_mp(this, &DynamicFontImportSettings::_change_text_opts)); + page2_1_hb->add_child(inspector_text); text_edit = memnew(TextEdit); - page3_vb->add_child(text_edit); + page2_1_hb->add_child(text_edit); text_edit->set_v_size_flags(Control::SIZE_EXPAND_FILL); text_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL); HBoxContainer *text_hb = memnew(HBoxContainer); - page3_vb->add_child(text_hb); + page2_1_vb->add_child(text_hb); text_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); label_glyphs = memnew(Label); @@ -1576,21 +1307,21 @@ DynamicFontImportSettings::DynamicFontImportSettings() { btn_clear->set_text(TTR("Clear glyph list")); btn_clear->connect("pressed", callable_mp(this, &DynamicFontImportSettings::_glyph_clear)); - // Page 4 layout: Character map - VBoxContainer *page4_vb = memnew(VBoxContainer); - page4_vb->set_name(TTR("Glyphs from the Character Map")); - main_pages->add_child(page4_vb); + // Page 2.2 layout: Character map + VBoxContainer *page2_2_vb = memnew(VBoxContainer); + page2_2_vb->set_name(TTR("Glyphs from the Character Map")); + preload_pages->add_child(page2_2_vb); - page4_description = memnew(Label); - page4_description->set_text(TTR("Add or remove additional glyphs from the character map to pre-render list:\nNote: Some stylistic alternatives and glyph variants do not have one-to-one correspondence to character, and not shown in this map, use \"Glyphs from the text\" to add these.")); - page4_description->set_h_size_flags(Control::SIZE_EXPAND_FILL); - page4_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); - page4_vb->add_child(page4_description); + page2_2_description = memnew(Label); + page2_2_description->set_text(TTR("Add or remove glyphs from the character map to pre-render list:\nNote: Some stylistic alternatives and glyph variants do not have one-to-one correspondence to character, and not shown in this map, use \"Glyphs from the text\" tab to add these.")); + page2_2_description->set_h_size_flags(Control::SIZE_EXPAND_FILL); + page2_2_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + page2_2_vb->add_child(page2_2_description); HSplitContainer *glyphs_split = memnew(HSplitContainer); glyphs_split->set_v_size_flags(Control::SIZE_EXPAND_FILL); glyphs_split->set_h_size_flags(Control::SIZE_EXPAND_FILL); - page4_vb->add_child(glyphs_split); + page2_2_vb->add_child(glyphs_split); glyph_table = memnew(Tree); glyphs_split->add_child(glyph_table); @@ -1627,101 +1358,6 @@ DynamicFontImportSettings::DynamicFontImportSettings() { _add_glyph_range_item(unicode_ranges[i].start, unicode_ranges[i].end, unicode_ranges[i].name); } - // Page 4 layout: Metadata override - VBoxContainer *page5_vb = memnew(VBoxContainer); - page5_vb->set_name(TTR("Metadata Override")); - main_pages->add_child(page5_vb); - - page5_description = memnew(Label); - page5_description->set_text(TTR("Add or remove language and script support overrides, to control fallback font selection order:")); - page5_description->set_h_size_flags(Control::SIZE_EXPAND_FILL); - page5_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); - page5_vb->add_child(page5_description); - - HBoxContainer *hb_lang = memnew(HBoxContainer); - page5_vb->add_child(hb_lang); - - label_langs = memnew(Label); - label_langs->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); - label_langs->set_h_size_flags(Control::SIZE_EXPAND_FILL); - label_langs->set_text(TTR("Language support overrides")); - hb_lang->add_child(label_langs); - - add_lang = memnew(Button); - hb_lang->add_child(add_lang); - add_lang->set_tooltip(TTR("Add language override")); - add_lang->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); - add_lang->connect("pressed", callable_mp(this, &DynamicFontImportSettings::_lang_add)); - - lang_list = memnew(Tree); - page5_vb->add_child(lang_list); - lang_list->set_hide_root(true); - lang_list->set_columns(3); - lang_list->set_column_expand(0, false); // Check - lang_list->set_column_custom_minimum_width(0, 50 * EDSCALE); - lang_list->set_column_expand(1, true); - lang_list->set_column_custom_minimum_width(1, 80 * EDSCALE); - lang_list->set_column_expand(2, false); - lang_list->set_column_custom_minimum_width(2, 50 * EDSCALE); - lang_list->connect("button_clicked", callable_mp(this, &DynamicFontImportSettings::_lang_remove)); - lang_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); - - HBoxContainer *hb_script = memnew(HBoxContainer); - page5_vb->add_child(hb_script); - - label_script = memnew(Label); - label_script->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); - label_script->set_h_size_flags(Control::SIZE_EXPAND_FILL); - label_script->set_text(TTR("Script support overrides")); - hb_script->add_child(label_script); - - add_script = memnew(Button); - hb_script->add_child(add_script); - add_script->set_tooltip(TTR("Add script override")); - add_script->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); - add_script->connect("pressed", callable_mp(this, &DynamicFontImportSettings::_script_add)); - - script_list = memnew(Tree); - page5_vb->add_child(script_list); - script_list->set_hide_root(true); - script_list->set_columns(3); - script_list->set_column_expand(0, false); - script_list->set_column_custom_minimum_width(0, 50 * EDSCALE); - script_list->set_column_expand(1, true); - script_list->set_column_custom_minimum_width(1, 80 * EDSCALE); - script_list->set_column_expand(2, false); - script_list->set_column_custom_minimum_width(2, 50 * EDSCALE); - script_list->connect("button_clicked", callable_mp(this, &DynamicFontImportSettings::_script_remove)); - script_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); - - HBoxContainer *hb_ot = memnew(HBoxContainer); - page5_vb->add_child(hb_ot); - - label_ot = memnew(Label); - label_ot->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); - label_ot->set_h_size_flags(Control::SIZE_EXPAND_FILL); - label_ot->set_text(TTR("OpenType feature overrides")); - hb_ot->add_child(label_ot); - - add_ot = memnew(Button); - hb_ot->add_child(add_ot); - add_ot->set_tooltip(TTR("Add feature override")); - add_ot->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); - add_ot->connect("pressed", callable_mp(this, &DynamicFontImportSettings::_ot_add)); - - ot_list = memnew(Tree); - page5_vb->add_child(ot_list); - ot_list->set_hide_root(true); - ot_list->set_columns(3); - ot_list->set_column_expand(0, true); - ot_list->set_column_custom_minimum_width(0, 80 * EDSCALE); - ot_list->set_column_expand(1, true); - ot_list->set_column_custom_minimum_width(1, 80 * EDSCALE); - ot_list->set_column_expand(2, false); - ot_list->set_column_custom_minimum_width(2, 50 * EDSCALE); - ot_list->connect("button_clicked", callable_mp(this, &DynamicFontImportSettings::_ot_remove)); - ot_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); - // Common import_settings_data.instantiate(); diff --git a/editor/import/dynamic_font_import_settings.h b/editor/import/dynamic_font_import_settings.h index ba75c98057..a1f763b445 100644 --- a/editor/import/dynamic_font_import_settings.h +++ b/editor/import/dynamic_font_import_settings.h @@ -45,7 +45,30 @@ #include "scene/resources/font.h" #include "servers/text_server.h" -class DynamicFontImportSettingsData; +class DynamicFontImportSettings; + +class DynamicFontImportSettingsData : public RefCounted { + GDCLASS(DynamicFontImportSettingsData, RefCounted) + friend class DynamicFontImportSettings; + + HashMap<StringName, Variant> settings; + HashMap<StringName, Variant> defaults; + List<ResourceImporter::ImportOption> options; + DynamicFontImportSettings *owner = nullptr; + + HashSet<char32_t> selected_chars; + HashSet<int32_t> selected_glyphs; + + Ref<FontFile> fd; + +public: + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + + Ref<FontFile> get_font() const; +}; + class EditorFileDialog; class EditorInspector; class EditorLocaleDialog; @@ -67,21 +90,19 @@ class DynamicFontImportSettings : public ConfirmationDialog { List<ResourceImporter::ImportOption> options_variations; List<ResourceImporter::ImportOption> options_general; - EditorLocaleDialog *locale_select = nullptr; - Vector<String> script_codes; - // Root layout Label *label_warn = nullptr; TabContainer *main_pages = nullptr; // Page 1 layout: Rendering Options Label *page1_description = nullptr; + Label *font_name_label = nullptr; Label *font_preview_label = nullptr; EditorInspector *inspector_general = nullptr; void _main_prop_changed(const String &p_edited_property); - // Page 2 layout: Configurations + // Page 2 layout: Preload Configurations Label *page2_description = nullptr; Label *label_vars = nullptr; Button *add_var = nullptr; @@ -95,19 +116,23 @@ class DynamicFontImportSettings : public ConfirmationDialog { void _variation_changed(const String &p_edited_property); void _variations_validate(); - // Page 3 layout: Text to select glyphs - Label *page3_description = nullptr; + TabContainer *preload_pages = nullptr; + + // Page 2.1 layout: Text to select glyphs + Label *page2_1_description = nullptr; Label *label_glyphs = nullptr; TextEdit *text_edit = nullptr; - LineEdit *ftr_edit = nullptr; - LineEdit *lang_edit = nullptr; + EditorInspector *inspector_text = nullptr; + + List<ResourceImporter::ImportOption> options_text; + Ref<DynamicFontImportSettingsData> text_settings_data; void _change_text_opts(); void _glyph_text_selected(); void _glyph_clear(); - // Page 4 layout: Character map - Label *page4_description = nullptr; + // Page 2.2 layout: Character map + Label *page2_2_description = nullptr; Tree *glyph_table = nullptr; Tree *glyph_tree = nullptr; TreeItem *glyph_root = nullptr; @@ -119,51 +144,12 @@ class DynamicFontImportSettings : public ConfirmationDialog { bool _char_update(int32_t p_char); void _range_update(int32_t p_start, int32_t p_end); - // Page 5 layout: Metadata override - Label *page5_description = nullptr; - Button *add_lang = nullptr; - Button *add_script = nullptr; - Button *add_ot = nullptr; - - PopupMenu *menu_scripts = nullptr; - PopupMenu *menu_ot = nullptr; - PopupMenu *menu_ot_ss = nullptr; - PopupMenu *menu_ot_cv = nullptr; - PopupMenu *menu_ot_cu = nullptr; - - Tree *lang_list = nullptr; - TreeItem *lang_list_root = nullptr; - Label *label_langs = nullptr; - - Tree *script_list = nullptr; - TreeItem *script_list_root = nullptr; - Label *label_script = nullptr; - - Tree *ot_list = nullptr; - TreeItem *ot_list_root = nullptr; - Label *label_ot = nullptr; - - void _lang_add(); - void _lang_add_item(const String &p_locale); - void _lang_remove(Object *p_item, int p_column, int p_id, MouseButton p_button); - - void _script_add(); - void _script_add_item(int p_option); - void _script_remove(Object *p_item, int p_column, int p_id, MouseButton p_button); - - void _ot_add(); - void _ot_add_item(int p_option); - void _ot_remove(Object *p_item, int p_column, int p_id, MouseButton p_button); - // Common void _add_glyph_range_item(int32_t p_start, int32_t p_end, const String &p_name); - Ref<Font> font_preview; - Ref<Font> font_main; - - RBSet<char32_t> selected_chars; - RBSet<int32_t> selected_glyphs; + Ref<FontFile> font_preview; + Ref<FontFile> font_main; void _re_import(); diff --git a/editor/import/resource_importer_bmfont.cpp b/editor/import/resource_importer_bmfont.cpp index 8a40b113b9..987ca4b911 100644 --- a/editor/import/resource_importer_bmfont.cpp +++ b/editor/import/resource_importer_bmfont.cpp @@ -52,7 +52,7 @@ String ResourceImporterBMFont::get_save_extension() const { } String ResourceImporterBMFont::get_resource_type() const { - return "FontData"; + return "FontFile"; } bool ResourceImporterBMFont::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const { @@ -60,19 +60,25 @@ bool ResourceImporterBMFont::get_option_visibility(const String &p_path, const S } void ResourceImporterBMFont::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const { + r_options->push_back(ImportOption(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font")), Array())); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress"), true)); } Error ResourceImporterBMFont::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { print_verbose("Importing BMFont font from: " + p_source_file); - Ref<FontData> font; + Array fallbacks = p_options["fallbacks"]; + + Ref<FontFile> font; font.instantiate(); Error err = font->load_bitmap_font(p_source_file); ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot load font to file \"" + p_source_file + "\"."); - int flg = ResourceSaver::SaverFlags::FLAG_BUNDLE_RESOURCES | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS; + font->set_fallbacks(fallbacks); + + int flg = 0; if ((bool)p_options["compress"]) { flg |= ResourceSaver::SaverFlags::FLAG_COMPRESS; } diff --git a/editor/import/resource_importer_dynamic_font.cpp b/editor/import/resource_importer_dynamic_font.cpp index a92b0fe280..f1a70ff30a 100644 --- a/editor/import/resource_importer_dynamic_font.cpp +++ b/editor/import/resource_importer_dynamic_font.cpp @@ -66,7 +66,7 @@ String ResourceImporterDynamicFont::get_save_extension() const { } String ResourceImporterDynamicFont::get_resource_type() const { - return "FontData"; + return "FontFile"; } bool ResourceImporterDynamicFont::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const { @@ -103,7 +103,7 @@ String ResourceImporterDynamicFont::get_preset_name(int p_idx) const { void ResourceImporterDynamicFont::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const { bool msdf = p_preset == PRESET_MSDF; - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "face_index"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::NIL, "Rendering", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant())); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "antialiased"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_mipmaps"), false)); @@ -114,63 +114,19 @@ void ResourceImporterDynamicFont::get_import_options(const String &p_path, List< r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force_autohinter"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), 1)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel"), 1)); - r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "embolden", PROPERTY_HINT_RANGE, "-2,2,0.01"), 0.f)); - r_options->push_back(ImportOption(PropertyInfo(Variant::TRANSFORM2D, "transform"), Transform2D())); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_RANGE, "0,10,0.1"), 0.0)); - r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress"), true)); - r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "opentype_feature_overrides"), Dictionary())); - - r_options->push_back(ImportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "preload/char_ranges"), Vector<String>())); - r_options->push_back(ImportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "preload/glyph_ranges"), Vector<String>())); - r_options->push_back(ImportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "preload/configurations"), Vector<String>())); - - r_options->push_back(ImportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "support_overrides/language_enabled"), Vector<String>())); - r_options->push_back(ImportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "support_overrides/language_disabled"), Vector<String>())); + r_options->push_back(ImportOption(PropertyInfo(Variant::NIL, "Fallbacks", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant())); + r_options->push_back(ImportOption(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font")), Array())); - r_options->push_back(ImportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "support_overrides/script_enabled"), Vector<String>())); - r_options->push_back(ImportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "support_overrides/script_disabled"), Vector<String>())); -} + r_options->push_back(ImportOption(PropertyInfo(Variant::NIL, "Compress", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant())); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress"), true)); -bool ResourceImporterDynamicFont::_decode_variation(const String &p_token, Dictionary &r_variations, Vector2i &r_size, String &r_name, Vector2i &r_spacing) { - Vector<String> tokens = p_token.split("="); - if (tokens.size() == 2) { - if (tokens[0] == "name") { - r_name = tokens[1]; - } else if (tokens[0] == "size") { - r_size.x = tokens[1].to_int(); - } else if (tokens[0] == "outline_size") { - r_size.y = tokens[1].to_int(); - } else if (tokens[0] == "spacing_space") { - r_spacing.x = tokens[1].to_int(); - } else if (tokens[0] == "spacing_glyph") { - r_spacing.y = tokens[1].to_int(); - } else { - r_variations[tokens[0]] = tokens[1].to_float(); - } - return true; - } else { - WARN_PRINT("Invalid variation: '" + p_token + "'."); - return false; - } -} - -bool ResourceImporterDynamicFont::_decode_range(const String &p_token, int32_t &r_pos) { - if (p_token.begins_with("U+") || p_token.begins_with("u+") || p_token.begins_with("0x")) { - // Unicode character hex index. - r_pos = p_token.substr(2).hex_to_int(); - return true; - } else if (p_token.length() == 3 && p_token[0] == '\'' && p_token[2] == '\'') { - // Unicode character. - r_pos = p_token.unicode_at(1); - return true; - } else if (p_token.is_numeric()) { - // Unicode character decimal index. - r_pos = p_token.to_int(); - return true; - } else { - return false; - } + // Hide from the main UI, only for advanced import dialog. + r_options->push_back(ImportOption(PropertyInfo(Variant::ARRAY, "preload", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), Array())); + r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "language_support", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), Dictionary())); + r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "script_support", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), Dictionary())); + r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "opentype_features", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), Dictionary())); } bool ResourceImporterDynamicFont::has_advanced_options() const { @@ -183,30 +139,26 @@ void ResourceImporterDynamicFont::show_advanced_options(const String &p_path) { Error ResourceImporterDynamicFont::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { print_verbose("Importing dynamic font from: " + p_source_file); - int face_index = p_options["face_index"]; - bool antialiased = p_options["antialiased"]; bool generate_mipmaps = p_options["generate_mipmaps"]; bool msdf = p_options["multichannel_signed_distance_field"]; int px_range = p_options["msdf_pixel_range"]; int px_size = p_options["msdf_size"]; - Dictionary ot_ov = p_options["opentype_feature_overrides"]; + Dictionary ot_ov = p_options["opentype_features"]; bool autohinter = p_options["force_autohinter"]; int hinting = p_options["hinting"]; int subpixel_positioning = p_options["subpixel_positioning"]; real_t oversampling = p_options["oversampling"]; - real_t embolden = p_options["embolden"]; - Transform2D transform = p_options["transform"]; + Array fallbacks = p_options["fallbacks"]; // Load base font data. Vector<uint8_t> data = FileAccess::get_file_as_array(p_source_file); // Create font. - Ref<FontData> font; + Ref<FontFile> font; font.instantiate(); font->set_data(data); - font->set_face_index(face_index); font->set_antialiased(antialiased); font->set_generate_mipmaps(generate_mipmaps); font->set_multichannel_signed_distance_field(msdf); @@ -216,105 +168,52 @@ Error ResourceImporterDynamicFont::import(const String &p_source_file, const Str font->set_fixed_size(0); font->set_force_autohinter(autohinter); font->set_subpixel_positioning((TextServer::SubpixelPositioning)subpixel_positioning); - font->set_embolden(embolden); - font->set_transform(transform); font->set_hinting((TextServer::Hinting)hinting); font->set_oversampling(oversampling); + font->set_fallbacks(fallbacks); - Vector<String> lang_en = p_options["support_overrides/language_enabled"]; - for (int i = 0; i < lang_en.size(); i++) { - font->set_language_support_override(lang_en[i], true); + Dictionary langs = p_options["language_support"]; + for (int i = 0; i < langs.size(); i++) { + String key = langs.get_key_at_index(i); + bool enabled = langs.get_value_at_index(i); + font->set_language_support_override(key, enabled); } - Vector<String> lang_dis = p_options["support_overrides/language_disabled"]; - for (int i = 0; i < lang_dis.size(); i++) { - font->set_language_support_override(lang_dis[i], false); + Dictionary scripts = p_options["script_support"]; + for (int i = 0; i < scripts.size(); i++) { + String key = scripts.get_key_at_index(i); + bool enabled = scripts.get_value_at_index(i); + font->set_script_support_override(key, enabled); } - Vector<String> scr_en = p_options["support_overrides/script_enabled"]; - for (int i = 0; i < scr_en.size(); i++) { - font->set_script_support_override(scr_en[i], true); - } + Array preload_configurations = p_options["preload"]; - Vector<String> scr_dis = p_options["support_overrides/script_disabled"]; - for (int i = 0; i < scr_dis.size(); i++) { - font->set_script_support_override(scr_dis[i], false); - } + for (int i = 0; i < preload_configurations.size(); i++) { + Dictionary preload_config = preload_configurations[i]; - Vector<String> variations = p_options["preload/configurations"]; - Vector<String> char_ranges = p_options["preload/char_ranges"]; - Vector<String> gl_ranges = p_options["preload/glyph_ranges"]; - - for (int i = 0; i < variations.size(); i++) { - String name; - Dictionary var; - Vector2i size = Vector2(16, 0); - Vector2i spacing; - - Vector<String> variation_tags = variations[i].split(","); - for (int j = 0; j < variation_tags.size(); j++) { - if (!_decode_variation(variation_tags[j], var, size, name, spacing)) { - WARN_PRINT(vformat(TTR("Invalid variation: \"%s\""), variations[i])); - continue; - } - } - RID conf = font->find_cache(var); - - for (int j = 0; j < char_ranges.size(); j++) { - int32_t start, end; - Vector<String> tokens = char_ranges[j].split("-"); - if (tokens.size() == 2) { - if (!_decode_range(tokens[0], start) || !_decode_range(tokens[1], end)) { - WARN_PRINT(vformat(TTR("Invalid range: \"%s\""), char_ranges[j])); - continue; - } - } else if (tokens.size() == 1) { - if (!_decode_range(tokens[0], start)) { - WARN_PRINT(vformat(TTR("Invalid range: \"%s\""), char_ranges[j])); - continue; - } - end = start; - } else { - WARN_PRINT(vformat(TTR("Invalid range: \"%s\""), char_ranges[j])); - continue; - } - - // Preload character ranges for each variations / sizes. - print_verbose(vformat(TTR("Pre-rendering range U+%s...%s from configuration \"%s\" (%d / %d)..."), String::num_int64(start, 16), String::num_int64(end, 16), name, i + 1, variations.size())); - TS->font_render_range(conf, size, start, end); - } + Dictionary variation = preload_config.has("variation_opentype") ? preload_config["variation_opentype"].operator Dictionary() : Dictionary(); + double embolden = preload_config.has("variation_embolden") ? preload_config["variation_embolden"].operator double() : 0; + int face_index = preload_config.has("variation_face_index") ? preload_config["variation_face_index"].operator int() : 0; + Transform2D transform = preload_config.has("variation_transform") ? preload_config["variation_transform"].operator Transform2D() : Transform2D(); + Vector2i size = preload_config.has("size") ? preload_config["size"].operator Vector2i() : Vector2i(16, 0); + String name = preload_config.has("name") ? preload_config["name"].operator String() : vformat("Configuration %d", i); - for (int j = 0; j < gl_ranges.size(); j++) { - int32_t start, end; - Vector<String> tokens = gl_ranges[j].split("-"); - if (tokens.size() == 2) { - if (!_decode_range(tokens[0], start) || !_decode_range(tokens[1], end)) { - WARN_PRINT(vformat(TTR("Invalid range: \"%s\""), gl_ranges[j])); - continue; - } - } else if (tokens.size() == 1) { - if (!_decode_range(tokens[0], start)) { - WARN_PRINT(vformat(TTR("Invalid range: \"%s\""), gl_ranges[j])); - continue; - } - end = start; - } else { - WARN_PRINT(vformat(TTR("Invalid range: \"%s\""), gl_ranges[j])); - continue; - } - - // Preload glyph range for each variations / sizes. - print_verbose(vformat(TTR("Pre-rendering glyph range 0x%s...%s from configuration \"%s\" (%d / %d)..."), String::num_int64(start, 16), String::num_int64(end, 16), name, i + 1, variations.size())); - for (int32_t k = start; k <= end; k++) { - TS->font_render_glyph(conf, size, k); - } + RID conf_rid = font->find_variation(variation, face_index, embolden, transform); + + Array chars = preload_config["chars"]; + for (int j = 0; j < chars.size(); j++) { + char32_t c = chars[j].operator int(); + TS->font_render_range(conf_rid, size, c, c); } - TS->font_set_spacing(conf, size.x, TextServer::SPACING_SPACE, spacing.x); - TS->font_set_spacing(conf, size.x, TextServer::SPACING_GLYPH, spacing.y); + Array glyphs = preload_config["glyphs"]; + for (int j = 0; j < glyphs.size(); j++) { + int32_t c = glyphs[j]; + TS->font_render_glyph(conf_rid, size, c); + } } - int flg = ResourceSaver::SaverFlags::FLAG_BUNDLE_RESOURCES | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS; + int flg = 0; if ((bool)p_options["compress"]) { flg |= ResourceSaver::SaverFlags::FLAG_COMPRESS; } diff --git a/editor/import/resource_importer_dynamic_font.h b/editor/import/resource_importer_dynamic_font.h index c0b6c094b0..a05c8bab05 100644 --- a/editor/import/resource_importer_dynamic_font.h +++ b/editor/import/resource_importer_dynamic_font.h @@ -43,9 +43,6 @@ class ResourceImporterDynamicFont : public ResourceImporter { }; public: - static bool _decode_range(const String &p_token, int32_t &r_pos); - static bool _decode_variation(const String &p_token, Dictionary &r_variations, Vector2i &r_size, String &r_name, Vector2i &r_spacing); - virtual String get_importer_name() const override; virtual String get_visible_name() const override; virtual void get_recognized_extensions(List<String> *p_extensions) const override; diff --git a/editor/import/resource_importer_imagefont.cpp b/editor/import/resource_importer_imagefont.cpp index 30c349d0f2..ea84d4c883 100644 --- a/editor/import/resource_importer_imagefont.cpp +++ b/editor/import/resource_importer_imagefont.cpp @@ -52,7 +52,7 @@ String ResourceImporterImageFont::get_save_extension() const { } String ResourceImporterImageFont::get_resource_type() const { - return "FontData"; + return "FontFile"; } bool ResourceImporterImageFont::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const { @@ -64,6 +64,9 @@ void ResourceImporterImageFont::get_import_options(const String &p_path, List<Im r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "columns"), 1)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "rows"), 1)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "font_size"), 14)); + + r_options->push_back(ImportOption(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font")), Array())); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress"), true)); } @@ -92,8 +95,9 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin int rows = p_options["rows"]; int base_size = p_options["font_size"]; Vector<String> ranges = p_options["character_ranges"]; + Array fallbacks = p_options["fallbacks"]; - Ref<FontData> font; + Ref<FontFile> font; font.instantiate(); font->set_antialiased(false); font->set_generate_mipmaps(false); @@ -103,6 +107,7 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin font->set_force_autohinter(false); font->set_hinting(TextServer::HINTING_NONE); font->set_oversampling(1.0f); + font->set_fallbacks(fallbacks); Ref<Image> img; img.instantiate(); @@ -145,10 +150,10 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin ERR_FAIL_COND_V_MSG(pos >= count, ERR_CANT_CREATE, "Too many characters in range."); } } - font->set_ascent(0, base_size, 0.5 * chr_height); - font->set_descent(0, base_size, 0.5 * chr_height); + font->set_cache_ascent(0, base_size, 0.5 * chr_height); + font->set_cache_descent(0, base_size, 0.5 * chr_height); - int flg = ResourceSaver::SaverFlags::FLAG_BUNDLE_RESOURCES | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS; + int flg = 0; if ((bool)p_options["compress"]) { flg |= ResourceSaver::SaverFlags::FLAG_COMPRESS; } diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index ad6d8e6379..affe46aaae 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -565,7 +565,7 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label")); int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label")); String num = String::num(vertex.vertex); - Size2 num_size = font->get_string_size(num, font_size); + Size2 num_size = font->get_string_size(num, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size); p_overlay->draw_string(font, point - num_size * 0.5, num, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(1.0, 1.0, 1.0, 0.5)); } } diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index 00cc5a6ca0..05d7a5f973 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -1224,7 +1224,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { Ref<StyleBox> sb = selected_nodes.has(E) ? style_selected : style; Size2 s = sb->get_minimum_size(); - int strsize = font->get_string_size(name, font_size).width; + int strsize = font->get_string_size(name, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width; s.width += strsize; s.height += MAX(font->get_height(font_size), play->get_height()); s.width += sep + play->get_width(); @@ -1379,7 +1379,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { Ref<AnimationNode> anode = state_machine->get_node(name); bool needs_editor = AnimationTreeEditor::get_singleton()->can_edit(anode); Ref<StyleBox> sb = selected_nodes.has(name) ? style_selected : style; - int strsize = font->get_string_size(name, font_size).width; + int strsize = font->get_string_size(name, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width; NodeRect &nr = node_rects.write[i]; Vector2 offset = nr.node.position; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 22788913d4..9ff32203f7 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -2677,7 +2677,7 @@ void CanvasItemEditor::_draw_text_at_position(Point2 p_position, String p_string color.a = 0.8; Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label")); int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label")); - Size2 text_size = font->get_string_size(p_string, font_size); + Size2 text_size = font->get_string_size(p_string, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size); switch (p_side) { case SIDE_LEFT: p_position += Vector2(-text_size.x - 5, text_size.y / 2); @@ -2749,16 +2749,18 @@ void CanvasItemEditor::_draw_guides() { String str = TS->format_number(vformat("%d px", Math::round(xform.affine_inverse().xform(dragged_guide_pos).x))); Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts")); int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")); - Size2 text_size = font->get_string_size(str, font_size); - viewport->draw_string(font, Point2(dragged_guide_pos.x + 10, RULER_WIDTH + text_size.y / 2 + 10), str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color, outline_size, outline_color); + Size2 text_size = font->get_string_size(str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size); + viewport->draw_string_outline(font, Point2(dragged_guide_pos.x + 10, RULER_WIDTH + text_size.y / 2 + 10), str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color); + viewport->draw_string(font, Point2(dragged_guide_pos.x + 10, RULER_WIDTH + text_size.y / 2 + 10), str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color); viewport->draw_line(Point2(dragged_guide_pos.x, 0), Point2(dragged_guide_pos.x, viewport->get_size().y), guide_color, Math::round(EDSCALE)); } if (drag_type == DRAG_DOUBLE_GUIDE || drag_type == DRAG_H_GUIDE) { String str = TS->format_number(vformat("%d px", Math::round(xform.affine_inverse().xform(dragged_guide_pos).y))); Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts")); int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")); - Size2 text_size = font->get_string_size(str, font_size); - viewport->draw_string(font, Point2(RULER_WIDTH + 10, dragged_guide_pos.y + text_size.y / 2 + 10), str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color, outline_size, outline_color); + Size2 text_size = font->get_string_size(str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size); + viewport->draw_string_outline(font, Point2(RULER_WIDTH + 10, dragged_guide_pos.y + text_size.y / 2 + 10), str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color); + viewport->draw_string(font, Point2(RULER_WIDTH + 10, dragged_guide_pos.y + text_size.y / 2 + 10), str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color); viewport->draw_line(Point2(0, dragged_guide_pos.y), Point2(viewport->get_size().x, dragged_guide_pos.y), guide_color, Math::round(EDSCALE)); } } @@ -2970,13 +2972,15 @@ void CanvasItemEditor::_draw_ruler_tool() { text_pos.y = CLAMP(text_pos.y, text_height * 1.5, viewport->get_rect().size.y - text_height * 1.5); if (begin.is_equal_approx(end)) { - viewport->draw_string(font, text_pos, (String)ruler_tool_origin, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color, outline_size, outline_color); + viewport->draw_string_outline(font, text_pos, (String)ruler_tool_origin, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color); + viewport->draw_string(font, text_pos, (String)ruler_tool_origin, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color); Ref<Texture2D> position_icon = get_theme_icon(SNAME("EditorPosition"), SNAME("EditorIcons")); viewport->draw_texture(get_theme_icon(SNAME("EditorPosition"), SNAME("EditorIcons")), (ruler_tool_origin - view_offset) * zoom - position_icon->get_size() / 2); return; } - viewport->draw_string(font, text_pos, TS->format_number(vformat("%.1f px", length_vector.length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color, outline_size, outline_color); + viewport->draw_string_outline(font, text_pos, TS->format_number(vformat("%.1f px", length_vector.length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color); + viewport->draw_string(font, text_pos, TS->format_number(vformat("%.1f px", length_vector.length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color); bool draw_secondary_lines = !(Math::is_equal_approx(begin.y, corner.y) || Math::is_equal_approx(end.x, corner.x)); @@ -2994,16 +2998,19 @@ void CanvasItemEditor::_draw_ruler_tool() { Point2 text_pos2 = text_pos; text_pos2.x = begin.x < text_pos.x ? MIN(text_pos.x - text_width, begin.x - text_width / 2) : MAX(text_pos.x + text_width, begin.x - text_width / 2); - viewport->draw_string(font, text_pos2, TS->format_number(vformat("%.1f px", length_vector.y)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color); + viewport->draw_string_outline(font, text_pos2, TS->format_number(vformat("%.1f px", length_vector.y)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color); + viewport->draw_string(font, text_pos2, TS->format_number(vformat("%.1f px", length_vector.y)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color); Point2 v_angle_text_pos = Point2(); v_angle_text_pos.x = CLAMP(begin.x - angle_text_width / 2, angle_text_width / 2, viewport->get_rect().size.x - angle_text_width); v_angle_text_pos.y = begin.y < end.y ? MIN(text_pos2.y - 2 * text_height, begin.y - text_height * 0.5) : MAX(text_pos2.y + text_height * 3, begin.y + text_height * 1.5); - viewport->draw_string(font, v_angle_text_pos, TS->format_number(vformat(String::utf8("%d°"), vertical_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color); + viewport->draw_string_outline(font, v_angle_text_pos, TS->format_number(vformat(String::utf8("%d°"), vertical_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color); + viewport->draw_string(font, v_angle_text_pos, TS->format_number(vformat(String::utf8("%d°"), vertical_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color); text_pos2 = text_pos; text_pos2.y = end.y < text_pos.y ? MIN(text_pos.y - text_height * 2, end.y - text_height / 2) : MAX(text_pos.y + text_height * 2, end.y - text_height / 2); - viewport->draw_string(font, text_pos2, TS->format_number(vformat("%.1f px", length_vector.x)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color); + viewport->draw_string_outline(font, text_pos2, TS->format_number(vformat("%.1f px", length_vector.x)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color); + viewport->draw_string(font, text_pos2, TS->format_number(vformat("%.1f px", length_vector.x)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color); Point2 h_angle_text_pos = Point2(); h_angle_text_pos.x = CLAMP(end.x - angle_text_width / 2, angle_text_width / 2, viewport->get_rect().size.x - angle_text_width); @@ -3020,7 +3027,8 @@ void CanvasItemEditor::_draw_ruler_tool() { h_angle_text_pos.y = MIN(text_pos.y - height_multiplier * text_height, MIN(end.y - text_height * 0.5, text_pos2.y - height_multiplier * text_height)); } } - viewport->draw_string(font, h_angle_text_pos, TS->format_number(vformat(String::utf8("%d°"), horizontal_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color); + viewport->draw_string_outline(font, h_angle_text_pos, TS->format_number(vformat(String::utf8("%d°"), horizontal_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color); + viewport->draw_string(font, h_angle_text_pos, TS->format_number(vformat(String::utf8("%d°"), horizontal_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color); // Angle arcs int arc_point_count = 8; @@ -3055,17 +3063,21 @@ void CanvasItemEditor::_draw_ruler_tool() { text_pos.y = CLAMP(text_pos.y, text_height * 2.5, viewport->get_rect().size.y - text_height / 2); if (draw_secondary_lines) { - viewport->draw_string(font, text_pos, TS->format_number(vformat("%.2f " + TTR("units"), (length_vector / grid_step).length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color, outline_size, outline_color); + viewport->draw_string_outline(font, text_pos, TS->format_number(vformat("%.2f " + TTR("units"), (length_vector / grid_step).length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color); + viewport->draw_string(font, text_pos, TS->format_number(vformat("%.2f " + TTR("units"), (length_vector / grid_step).length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color); Point2 text_pos2 = text_pos; text_pos2.x = begin.x < text_pos.x ? MIN(text_pos.x - text_width, begin.x - text_width / 2) : MAX(text_pos.x + text_width, begin.x - text_width / 2); - viewport->draw_string(font, text_pos2, TS->format_number(vformat("%d " + TTR("units"), roundf(length_vector.y / grid_step.y))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color); + viewport->draw_string_outline(font, text_pos2, TS->format_number(vformat("%d " + TTR("units"), roundf(length_vector.y / grid_step.y))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color); + viewport->draw_string(font, text_pos2, TS->format_number(vformat("%d " + TTR("units"), roundf(length_vector.y / grid_step.y))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color); text_pos2 = text_pos; text_pos2.y = end.y < text_pos.y ? MIN(text_pos.y - text_height * 2, end.y + text_height / 2) : MAX(text_pos.y + text_height * 2, end.y + text_height / 2); - viewport->draw_string(font, text_pos2, TS->format_number(vformat("%d " + TTR("units"), roundf(length_vector.x / grid_step.x))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color); + viewport->draw_string_outline(font, text_pos2, TS->format_number(vformat("%d " + TTR("units"), roundf(length_vector.x / grid_step.x))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color); + viewport->draw_string(font, text_pos2, TS->format_number(vformat("%d " + TTR("units"), roundf(length_vector.x / grid_step.x))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color); } else { - viewport->draw_string(font, text_pos, TS->format_number(vformat("%d " + TTR("units"), roundf((length_vector / grid_step).length()))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color, outline_size, outline_color); + viewport->draw_string_outline(font, text_pos, TS->format_number(vformat("%d " + TTR("units"), roundf((length_vector / grid_step).length()))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color); + viewport->draw_string(font, text_pos, TS->format_number(vformat("%d " + TTR("units"), roundf((length_vector / grid_step).length()))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color); } } } else { @@ -3611,7 +3623,7 @@ void CanvasItemEditor::_draw_hover() { Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label")); int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label")); - Size2 node_name_size = font->get_string_size(node_name, font_size); + Size2 node_name_size = font->get_string_size(node_name, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size); Size2 item_size = Size2(node_icon->get_size().x + 4 + node_name_size.x, MAX(node_icon->get_size().y, node_name_size.y - 3)); Point2 pos = transform.xform(hovering_results[i].position) - Point2(0, item_size.y) + (Point2(node_icon->get_size().x, -node_icon->get_size().y) / 4); @@ -3685,7 +3697,7 @@ void CanvasItemEditor::_draw_transform_message() { return; } - Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label")); + Ref<FontFile> font = get_theme_font(SNAME("font"), SNAME("Label")); int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label")); Point2 msgpos = Point2(RULER_WIDTH + 5 * EDSCALE, viewport->get_size().y - 20 * EDSCALE); viewport->draw_string(font, msgpos + Point2(1, 1), transform_message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8)); diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index bb0cfcba25..a00ed1e49a 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -812,19 +812,12 @@ void EditorFontPreviewPlugin::_preview_done() { } bool EditorFontPreviewPlugin::handles(const String &p_type) const { - return ClassDB::is_parent_class(p_type, "FontData") || ClassDB::is_parent_class(p_type, "Font"); + return ClassDB::is_parent_class(p_type, "Font"); } Ref<Texture2D> EditorFontPreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const { - Ref<Resource> res = ResourceLoader::load(p_path); - ERR_FAIL_COND_V(res.is_null(), Ref<Texture2D>()); - Ref<Font> sampled_font; - if (res->is_class("Font")) { - sampled_font = res->duplicate(); - } else if (res->is_class("FontData")) { - sampled_font.instantiate(); - sampled_font->add_data(res->duplicate()); - } + Ref<Font> sampled_font = ResourceLoader::load(p_path); + ERR_FAIL_COND_V(sampled_font.is_null(), Ref<Texture2D>()); String sample; static const String sample_base = U"12漢字ԱբΑαАбΑαאבابܐܒހށआআਆઆଆஆఆಆആආกิກິༀကႠა한글ሀᎣᐁᚁᚠᜀᜠᝀᝠកᠠᤁᥐAb😀"; @@ -836,18 +829,16 @@ Ref<Texture2D> EditorFontPreviewPlugin::generate_from_path(const String &p_path, if (sample.is_empty()) { sample = sampled_font->get_supported_chars().substr(0, 6); } - Vector2 size = sampled_font->get_string_size(sample, 50); + Vector2 size = sampled_font->get_string_size(sample, HORIZONTAL_ALIGNMENT_LEFT, -1, 50); Vector2 pos; pos.x = 64 - size.x / 2; pos.y = 80; - Ref<Font> font = sampled_font; - const Color c = GLOBAL_GET("rendering/environment/defaults/default_clear_color"); const float fg = c.get_luminance() < 0.5 ? 1.0 : 0.0; - font->draw_string(canvas_item, pos, sample, HORIZONTAL_ALIGNMENT_LEFT, -1.f, 50, Color(fg, fg, fg)); + sampled_font->draw_string(canvas_item, pos, sample, HORIZONTAL_ALIGNMENT_LEFT, -1.f, 50, Color(fg, fg, fg)); RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorFontPreviewPlugin *>(this), &EditorFontPreviewPlugin::_generate_frame_started), Vector<Variant>(), Object::CONNECT_ONESHOT); diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp new file mode 100644 index 0000000000..848fb5887d --- /dev/null +++ b/editor/plugins/font_config_plugin.cpp @@ -0,0 +1,979 @@ +/*************************************************************************/ +/* font_config_plugin.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 "font_config_plugin.h" + +#include "editor/editor_scale.h" +#include "editor/import/dynamic_font_import_settings.h" + +/*************************************************************************/ +/* EditorPropertyFontMetaObject */ +/*************************************************************************/ + +bool EditorPropertyFontMetaObject::_set(const StringName &p_name, const Variant &p_value) { + String name = p_name; + + if (name.begins_with("keys")) { + String key = name.get_slicec('/', 1); + dict[key] = p_value; + return true; + } + + return false; +} + +bool EditorPropertyFontMetaObject::_get(const StringName &p_name, Variant &r_ret) const { + String name = p_name; + + if (name.begins_with("keys")) { + String key = name.get_slicec('/', 1); + r_ret = dict[key]; + return true; + } + + return false; +} + +void EditorPropertyFontMetaObject::_bind_methods() { +} + +void EditorPropertyFontMetaObject::set_dict(const Dictionary &p_dict) { + dict = p_dict; +} + +Dictionary EditorPropertyFontMetaObject::get_dict() { + return dict; +} + +/*************************************************************************/ +/* EditorPropertyFontOTObject */ +/*************************************************************************/ + +bool EditorPropertyFontOTObject::_set(const StringName &p_name, const Variant &p_value) { + String name = p_name; + + if (name.begins_with("keys")) { + int key = name.get_slicec('/', 1).to_int(); + dict[key] = p_value; + return true; + } + + return false; +} + +bool EditorPropertyFontOTObject::_get(const StringName &p_name, Variant &r_ret) const { + String name = p_name; + + if (name.begins_with("keys")) { + int key = name.get_slicec('/', 1).to_int(); + r_ret = dict[key]; + return true; + } + + return false; +} + +void EditorPropertyFontOTObject::_bind_methods() { + ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &EditorPropertyFontOTObject::property_can_revert); + ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &EditorPropertyFontOTObject::property_get_revert); +} + +void EditorPropertyFontOTObject::set_dict(const Dictionary &p_dict) { + dict = p_dict; +} + +Dictionary EditorPropertyFontOTObject::get_dict() { + return dict; +} + +void EditorPropertyFontOTObject::set_defaults(const Dictionary &p_dict) { + defaults_dict = p_dict; +} + +Dictionary EditorPropertyFontOTObject::get_defaults() { + return defaults_dict; +} + +bool EditorPropertyFontOTObject::property_can_revert(const String &p_name) { + String name = p_name; + + if (name.begins_with("keys")) { + int key = name.get_slicec('/', 1).to_int(); + if (defaults_dict.has(key) && dict.has(key)) { + int value = dict[key]; + Vector3i range = defaults_dict[key]; + return range.z != value; + } + } + + return false; +} + +Variant EditorPropertyFontOTObject::property_get_revert(const String &p_name) { + String name = p_name; + + if (name.begins_with("keys")) { + int key = name.get_slicec('/', 1).to_int(); + if (defaults_dict.has(key)) { + Vector3i range = defaults_dict[key]; + return range.z; + } + } + + return Variant(); +} + +/*************************************************************************/ +/* EditorPropertyFontMetaOverride */ +/*************************************************************************/ + +void EditorPropertyFontMetaOverride::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + if (Object::cast_to<Button>(button_add)) { + button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + } + } break; + } +} + +void EditorPropertyFontMetaOverride::_property_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { + if (p_property.begins_with("keys")) { + Dictionary dict = object->get_dict(); + String key = p_property.get_slice("/", 1); + dict[key] = (bool)p_value; + + emit_changed(get_edited_property(), dict, "", true); + + dict = dict.duplicate(); // Duplicate, so undo/redo works better. + object->set_dict(dict); + } +} + +void EditorPropertyFontMetaOverride::_remove(Object *p_button, const String &p_key) { + Dictionary dict = object->get_dict(); + + dict.erase(p_key); + + emit_changed(get_edited_property(), dict, "", false); + + dict = dict.duplicate(); // Duplicate, so undo/redo works better. + object->set_dict(dict); + update_property(); +} + +void EditorPropertyFontMetaOverride::_add_menu() { + if (script_editor) { + Size2 size = get_size(); + menu->set_position(get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y)); + menu->reset_size(); + menu->popup(); + } else { + locale_select->popup_locale_dialog(); + } +} + +void EditorPropertyFontMetaOverride::_add_script(int p_option) { + Dictionary dict = object->get_dict(); + + dict[script_codes[p_option]] = true; + + emit_changed(get_edited_property(), dict, "", false); + + dict = dict.duplicate(); // Duplicate, so undo/redo works better. + object->set_dict(dict); + update_property(); +} + +void EditorPropertyFontMetaOverride::_add_lang(const String &p_locale) { + Dictionary dict = object->get_dict(); + + dict[p_locale] = true; + + emit_changed(get_edited_property(), dict, "", false); + + dict = dict.duplicate(); // Duplicate, so undo/redo works better. + object->set_dict(dict); + update_property(); +} + +void EditorPropertyFontMetaOverride::_object_id_selected(const StringName &p_property, ObjectID p_id) { + emit_signal(SNAME("object_id_selected"), p_property, p_id); +} + +void EditorPropertyFontMetaOverride::update_property() { + Variant updated_val = get_edited_object()->get(get_edited_property()); + + Dictionary dict = updated_val; + + edit->set_text(vformat(TTR("Overrides (%d)"), dict.size())); + + bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property()); + if (edit->is_pressed() != unfolded) { + edit->set_pressed(unfolded); + } + + if (unfolded) { + updating = true; + + if (!container) { + container = memnew(MarginContainer); + container->set_theme_type_variation("MarginContainer4px"); + add_child(container); + set_bottom_editor(container); + + VBoxContainer *vbox = memnew(VBoxContainer); + vbox->set_v_size_flags(SIZE_EXPAND_FILL); + container->add_child(vbox); + + property_vbox = memnew(VBoxContainer); + property_vbox->set_h_size_flags(SIZE_EXPAND_FILL); + vbox->add_child(property_vbox); + + paginator = memnew(EditorPaginator); + paginator->connect("page_changed", callable_mp(this, &EditorPropertyFontMetaOverride::_page_changed)); + vbox->add_child(paginator); + } else { + // Queue children for deletion, deleting immediately might cause errors. + for (int i = property_vbox->get_child_count() - 1; i >= 0; i--) { + property_vbox->get_child(i)->queue_delete(); + } + button_add = nullptr; + } + + int size = dict.size(); + + int max_page = MAX(0, size - 1) / page_length; + page_index = MIN(page_index, max_page); + + paginator->update(page_index, max_page); + paginator->set_visible(max_page > 0); + + int offset = page_index * page_length; + + int amount = MIN(size - offset, page_length); + + dict = dict.duplicate(); + object->set_dict(dict); + + for (int i = 0; i < amount; i++) { + String name = dict.get_key_at_index(i); + EditorProperty *prop = memnew(EditorPropertyCheck); + prop->set_object_and_property(object.ptr(), "keys/" + name); + + if (script_editor) { + prop->set_label(TranslationServer::get_singleton()->get_script_name(name)); + } else { + prop->set_label(TranslationServer::get_singleton()->get_locale_name(name)); + } + prop->set_tooltip(name); + prop->set_selectable(false); + + prop->connect("property_changed", callable_mp(this, &EditorPropertyFontMetaOverride::_property_changed)); + prop->connect("object_id_selected", callable_mp(this, &EditorPropertyFontMetaOverride::_object_id_selected)); + + HBoxContainer *hbox = memnew(HBoxContainer); + property_vbox->add_child(hbox); + hbox->add_child(prop); + prop->set_h_size_flags(SIZE_EXPAND_FILL); + Button *remove = memnew(Button); + remove->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); + hbox->add_child(remove); + remove->connect("pressed", callable_mp(this, &EditorPropertyFontMetaOverride::_remove), varray(remove, name)); + + prop->update_property(); + } + + if (script_editor) { + button_add = EditorInspector::create_inspector_action_button(TTR("Add Script")); + } else { + button_add = EditorInspector::create_inspector_action_button(TTR("Add Locale")); + } + button_add->connect("pressed", callable_mp(this, &EditorPropertyFontMetaOverride::_add_menu)); + property_vbox->add_child(button_add); + + updating = false; + } else { + if (container) { + set_bottom_editor(nullptr); + memdelete(container); + button_add = nullptr; + container = nullptr; + } + } +} + +void EditorPropertyFontMetaOverride::_edit_pressed() { + Variant prop_val = get_edited_object()->get(get_edited_property()); + if (prop_val.get_type() == Variant::NIL) { + Callable::CallError ce; + Variant::construct(Variant::DICTIONARY, prop_val, nullptr, 0, ce); + get_edited_object()->set(get_edited_property(), prop_val); + } + + get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed()); + update_property(); +} + +void EditorPropertyFontMetaOverride::_page_changed(int p_page) { + if (updating) { + return; + } + page_index = p_page; + update_property(); +} + +EditorPropertyFontMetaOverride::EditorPropertyFontMetaOverride(bool p_script) { + script_editor = p_script; + + object.instantiate(); + page_length = int(EDITOR_GET("interface/inspector/max_array_dictionary_items_per_page")); + + edit = memnew(Button); + edit->set_h_size_flags(SIZE_EXPAND_FILL); + edit->set_clip_text(true); + edit->connect("pressed", callable_mp(this, &EditorPropertyFontMetaOverride::_edit_pressed)); + edit->set_toggle_mode(true); + add_child(edit); + add_focusable(edit); + + menu = memnew(PopupMenu); + if (script_editor) { + script_codes = TranslationServer::get_singleton()->get_all_scripts(); + for (int i = 0; i < script_codes.size(); i++) { + menu->add_item(TranslationServer::get_singleton()->get_script_name(script_codes[i]) + " (" + script_codes[i] + ")", i); + } + } + add_child(menu); + menu->connect("id_pressed", callable_mp(this, &EditorPropertyFontMetaOverride::_add_script)); + + locale_select = memnew(EditorLocaleDialog); + locale_select->connect("locale_selected", callable_mp(this, &EditorPropertyFontMetaOverride::_add_lang)); + add_child(locale_select); +} + +/*************************************************************************/ +/* EditorPropertyOTVariation */ +/*************************************************************************/ + +void EditorPropertyOTVariation::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + } break; + } +} + +void EditorPropertyOTVariation::_property_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { + if (p_property.begins_with("keys")) { + Dictionary dict = object->get_dict(); + Dictionary defaults_dict = object->get_defaults(); + int key = p_property.get_slice("/", 1).to_int(); + dict[key] = (int)p_value; + if (defaults_dict.has(key)) { + Vector3i range = defaults_dict[key]; + if (range.z == (int)p_value) { + dict.erase(key); + } + } + + emit_changed(get_edited_property(), dict, "", true); + + dict = dict.duplicate(); // Duplicate, so undo/redo works better. + object->set_dict(dict); + } +} + +void EditorPropertyOTVariation::_object_id_selected(const StringName &p_property, ObjectID p_id) { + emit_signal(SNAME("object_id_selected"), p_property, p_id); +} + +void EditorPropertyOTVariation::update_property() { + Variant updated_val = get_edited_object()->get(get_edited_property()); + + Dictionary dict = updated_val; + + Ref<Font> fd; + if (Object::cast_to<Font>(get_edited_object()) != nullptr) { + fd = get_edited_object(); + } else if (Object::cast_to<DynamicFontImportSettingsData>(get_edited_object()) != nullptr) { + Ref<DynamicFontImportSettingsData> imp = Object::cast_to<DynamicFontImportSettingsData>(get_edited_object()); + fd = imp->get_font(); + } + + Dictionary supported = (fd.is_valid()) ? fd->get_supported_variation_list() : Dictionary(); + + edit->set_text(vformat(TTR("Variation Coordinates (%d)"), supported.size())); + + bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property()); + if (edit->is_pressed() != unfolded) { + edit->set_pressed(unfolded); + } + + if (unfolded) { + updating = true; + + if (!container) { + container = memnew(MarginContainer); + container->set_theme_type_variation("MarginContainer4px"); + add_child(container); + set_bottom_editor(container); + + VBoxContainer *vbox = memnew(VBoxContainer); + vbox->set_v_size_flags(SIZE_EXPAND_FILL); + container->add_child(vbox); + + property_vbox = memnew(VBoxContainer); + property_vbox->set_h_size_flags(SIZE_EXPAND_FILL); + vbox->add_child(property_vbox); + + paginator = memnew(EditorPaginator); + paginator->connect("page_changed", callable_mp(this, &EditorPropertyOTVariation::_page_changed)); + vbox->add_child(paginator); + } else { + // Queue children for deletion, deleting immediately might cause errors. + for (int i = property_vbox->get_child_count() - 1; i >= 0; i--) { + property_vbox->get_child(i)->queue_delete(); + } + } + + int size = supported.size(); + + int max_page = MAX(0, size - 1) / page_length; + page_index = MIN(page_index, max_page); + + paginator->update(page_index, max_page); + paginator->set_visible(max_page > 0); + + int offset = page_index * page_length; + + int amount = MIN(size - offset, page_length); + + dict = dict.duplicate(); + object->set_dict(dict); + object->set_defaults(supported); + + for (int i = 0; i < amount; i++) { + int name_tag = supported.get_key_at_index(i); + Vector3i range = supported.get_value_at_index(i); + + EditorPropertyInteger *prop = memnew(EditorPropertyInteger); + prop->setup(range.x, range.y, 1, false, false); + prop->set_object_and_property(object.ptr(), "keys/" + itos(name_tag)); + + String name = TS->tag_to_name(name_tag); + prop->set_label(name.capitalize()); + prop->set_tooltip(name); + prop->set_selectable(false); + + prop->connect("property_changed", callable_mp(this, &EditorPropertyOTVariation::_property_changed)); + prop->connect("object_id_selected", callable_mp(this, &EditorPropertyOTVariation::_object_id_selected)); + + property_vbox->add_child(prop); + + prop->update_property(); + } + + updating = false; + } else { + if (container) { + set_bottom_editor(nullptr); + memdelete(container); + container = nullptr; + } + } +} + +void EditorPropertyOTVariation::_edit_pressed() { + Variant prop_val = get_edited_object()->get(get_edited_property()); + if (prop_val.get_type() == Variant::NIL) { + Callable::CallError ce; + Variant::construct(Variant::DICTIONARY, prop_val, nullptr, 0, ce); + get_edited_object()->set(get_edited_property(), prop_val); + } + + get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed()); + update_property(); +} + +void EditorPropertyOTVariation::_page_changed(int p_page) { + if (updating) { + return; + } + page_index = p_page; + update_property(); +} + +EditorPropertyOTVariation::EditorPropertyOTVariation() { + object.instantiate(); + page_length = int(EDITOR_GET("interface/inspector/max_array_dictionary_items_per_page")); + + edit = memnew(Button); + edit->set_h_size_flags(SIZE_EXPAND_FILL); + edit->set_clip_text(true); + edit->connect("pressed", callable_mp(this, &EditorPropertyOTVariation::_edit_pressed)); + edit->set_toggle_mode(true); + add_child(edit); + add_focusable(edit); +} + +/*************************************************************************/ +/* EditorPropertyOTFeatures */ +/*************************************************************************/ + +void EditorPropertyOTFeatures::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + if (Object::cast_to<Button>(button_add)) { + button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + } + } break; + } +} + +void EditorPropertyOTFeatures::_property_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { + if (p_property.begins_with("keys")) { + Dictionary dict = object->get_dict(); + int key = p_property.get_slice("/", 1).to_int(); + dict[key] = (int)p_value; + + emit_changed(get_edited_property(), dict, "", true); + + dict = dict.duplicate(); // Duplicate, so undo/redo works better. + object->set_dict(dict); + } +} + +void EditorPropertyOTFeatures::_remove(Object *p_button, int p_key) { + Dictionary dict = object->get_dict(); + + dict.erase(p_key); + + emit_changed(get_edited_property(), dict, "", false); + + dict = dict.duplicate(); // Duplicate, so undo/redo works better. + object->set_dict(dict); + update_property(); +} + +void EditorPropertyOTFeatures::_add_menu() { + Size2 size = get_size(); + menu->set_position(get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y)); + menu->reset_size(); + menu->popup(); +} + +void EditorPropertyOTFeatures::_add_feature(int p_option) { + Dictionary dict = object->get_dict(); + + dict[p_option] = 1; + + emit_changed(get_edited_property(), dict, "", false); + + dict = dict.duplicate(); // Duplicate, so undo/redo works better. + object->set_dict(dict); + update_property(); +} + +void EditorPropertyOTFeatures::_object_id_selected(const StringName &p_property, ObjectID p_id) { + emit_signal(SNAME("object_id_selected"), p_property, p_id); +} + +void EditorPropertyOTFeatures::update_property() { + Variant updated_val = get_edited_object()->get(get_edited_property()); + + Dictionary dict = updated_val; + + Ref<Font> fd; + if (Object::cast_to<FontVariation>(get_edited_object()) != nullptr) { + fd = get_edited_object(); + } else if (Object::cast_to<DynamicFontImportSettingsData>(get_edited_object()) != nullptr) { + Ref<DynamicFontImportSettingsData> imp = Object::cast_to<DynamicFontImportSettingsData>(get_edited_object()); + fd = imp->get_font(); + } + + Dictionary supported; + if (fd.is_valid()) { + supported = fd->get_supported_feature_list(); + } + + edit->set_text(vformat(TTR("Features (%d of %d set)"), dict.size(), supported.size())); + + bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property()); + if (edit->is_pressed() != unfolded) { + edit->set_pressed(unfolded); + } + + if (unfolded) { + updating = true; + + if (!container) { + container = memnew(MarginContainer); + container->set_theme_type_variation("MarginContainer4px"); + add_child(container); + set_bottom_editor(container); + + VBoxContainer *vbox = memnew(VBoxContainer); + vbox->set_v_size_flags(SIZE_EXPAND_FILL); + container->add_child(vbox); + + property_vbox = memnew(VBoxContainer); + property_vbox->set_h_size_flags(SIZE_EXPAND_FILL); + vbox->add_child(property_vbox); + + paginator = memnew(EditorPaginator); + paginator->connect("page_changed", callable_mp(this, &EditorPropertyOTFeatures::_page_changed)); + vbox->add_child(paginator); + } else { + // Queue children for deletion, deleting immediately might cause errors. + for (int i = property_vbox->get_child_count() - 1; i >= 0; i--) { + property_vbox->get_child(i)->queue_delete(); + } + button_add = nullptr; + } + + // Update add menu items. + menu->clear(); + bool have_sub[FGRP_MAX]; + for (int i = 0; i < FGRP_MAX; i++) { + menu_sub[i]->clear(); + have_sub[i] = false; + } + + bool show_hidden = EDITOR_GET("interface/inspector/show_low_level_opentype_features"); + + for (int i = 0; i < supported.size(); i++) { + int name_tag = supported.get_key_at_index(i); + Dictionary info = supported.get_value_at_index(i); + bool hidden = info["hidden"].operator bool(); + String name = TS->tag_to_name(name_tag); + FeatureGroups grp = FGRP_MAX; + + if (hidden && !show_hidden) { + continue; + } + + if (name.begins_with("stylistic_set_")) { + grp = FGRP_STYLISTIC_SET; + } else if (name.begins_with("character_variant_")) { + grp = FGRP_CHARACTER_VARIANT; + } else if (name.ends_with("_capitals")) { + grp = FGRP_CAPITLS; + } else if (name.ends_with("_ligatures")) { + grp = FGRP_LIGATURES; + } else if (name.ends_with("_alternates")) { + grp = FGRP_ALTERNATES; + } else if (name.ends_with("_kanji_forms") || name.begins_with("jis") || name == "simplified_forms" || name == "traditional_name_forms" || name == "traditional_forms") { + grp = FGRP_EAL; + } else if (name.ends_with("_widths")) { + grp = FGRP_EAW; + } else if (name == "tabular_figures" || name == "proportional_figures") { + grp = FGRP_NUMAL; + } else if (name.begins_with("custom_")) { + grp = FGRP_CUSTOM; + } + String disp_name = name.capitalize(); + if (info.has("label")) { + disp_name = vformat("%s (%s)", disp_name, info["label"].operator String()); + } + + if (grp == FGRP_MAX) { + menu->add_item(disp_name, name_tag); + } else { + menu_sub[grp]->add_item(disp_name, name_tag); + have_sub[grp] = true; + } + } + for (int i = 0; i < FGRP_MAX; i++) { + if (have_sub[i]) { + menu->add_submenu_item(RTR(group_names[i]), "FTRMenu_" + itos(i)); + } + } + + int size = dict.size(); + + int max_page = MAX(0, size - 1) / page_length; + page_index = MIN(page_index, max_page); + + paginator->update(page_index, max_page); + paginator->set_visible(max_page > 0); + + int offset = page_index * page_length; + + int amount = MIN(size - offset, page_length); + + dict = dict.duplicate(); + object->set_dict(dict); + + for (int i = 0; i < amount; i++) { + int name_tag = dict.get_key_at_index(i); + + if (supported.has(name_tag)) { + Dictionary info = supported[name_tag]; + Variant::Type vtype = Variant::Type(info["type"].operator int()); + bool hidden = info["hidden"].operator bool(); + if (hidden && !show_hidden) { + continue; + } + + EditorProperty *prop = nullptr; + switch (vtype) { + case Variant::NIL: { + prop = memnew(EditorPropertyNil); + } break; + case Variant::BOOL: { + prop = memnew(EditorPropertyCheck); + } break; + case Variant::INT: { + EditorPropertyInteger *editor = memnew(EditorPropertyInteger); + editor->setup(0, 255, 1, false, false); + prop = editor; + } break; + default: { + ERR_CONTINUE_MSG(true, vformat("Unsupported OT feature data type %s", Variant::get_type_name(vtype))); + } + } + prop->set_object_and_property(object.ptr(), "keys/" + itos(name_tag)); + + String name = TS->tag_to_name(name_tag); + String disp_name = name.capitalize(); + if (info.has("label")) { + disp_name = vformat("%s (%s)", disp_name, info["label"].operator String()); + } + prop->set_label(disp_name); + prop->set_tooltip(name); + prop->set_selectable(false); + + prop->connect("property_changed", callable_mp(this, &EditorPropertyOTFeatures::_property_changed)); + prop->connect("object_id_selected", callable_mp(this, &EditorPropertyOTFeatures::_object_id_selected)); + + HBoxContainer *hbox = memnew(HBoxContainer); + property_vbox->add_child(hbox); + hbox->add_child(prop); + prop->set_h_size_flags(SIZE_EXPAND_FILL); + Button *remove = memnew(Button); + remove->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); + hbox->add_child(remove); + remove->connect("pressed", callable_mp(this, &EditorPropertyOTFeatures::_remove), varray(remove, name_tag)); + + prop->update_property(); + } + } + + button_add = EditorInspector::create_inspector_action_button(TTR("Add Feature")); + button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + button_add->connect("pressed", callable_mp(this, &EditorPropertyOTFeatures::_add_menu)); + property_vbox->add_child(button_add); + + updating = false; + } else { + if (container) { + set_bottom_editor(nullptr); + memdelete(container); + button_add = nullptr; + container = nullptr; + } + } +} + +void EditorPropertyOTFeatures::_edit_pressed() { + Variant prop_val = get_edited_object()->get(get_edited_property()); + if (prop_val.get_type() == Variant::NIL) { + Callable::CallError ce; + Variant::construct(Variant::DICTIONARY, prop_val, nullptr, 0, ce); + get_edited_object()->set(get_edited_property(), prop_val); + } + + get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed()); + update_property(); +} + +void EditorPropertyOTFeatures::_page_changed(int p_page) { + if (updating) { + return; + } + page_index = p_page; + update_property(); +} + +EditorPropertyOTFeatures::EditorPropertyOTFeatures() { + object.instantiate(); + page_length = int(EDITOR_GET("interface/inspector/max_array_dictionary_items_per_page")); + + edit = memnew(Button); + edit->set_h_size_flags(SIZE_EXPAND_FILL); + edit->set_clip_text(true); + edit->connect("pressed", callable_mp(this, &EditorPropertyOTFeatures::_edit_pressed)); + edit->set_toggle_mode(true); + add_child(edit); + add_focusable(edit); + + menu = memnew(PopupMenu); + add_child(menu); + menu->connect("id_pressed", callable_mp(this, &EditorPropertyOTFeatures::_add_feature)); + + for (int i = 0; i < FGRP_MAX; i++) { + menu_sub[i] = memnew(PopupMenu); + menu_sub[i]->set_name("FTRMenu_" + itos(i)); + menu->add_child(menu_sub[i]); + menu_sub[i]->connect("id_pressed", callable_mp(this, &EditorPropertyOTFeatures::_add_feature)); + } + + group_names[FGRP_STYLISTIC_SET] = "Stylistic Sets"; + group_names[FGRP_CHARACTER_VARIANT] = "Character Variants"; + group_names[FGRP_CAPITLS] = "Capitals"; + group_names[FGRP_LIGATURES] = "Ligatures"; + group_names[FGRP_ALTERNATES] = "Alternates"; + group_names[FGRP_EAL] = "East Asian Language"; + group_names[FGRP_EAW] = "East Asian Widths"; + group_names[FGRP_NUMAL] = "Numeral Alignment"; + group_names[FGRP_CUSTOM] = "Custom"; +} + +/*************************************************************************/ +/* EditorInspectorPluginFontVariation */ +/*************************************************************************/ + +bool EditorInspectorPluginFontVariation::can_handle(Object *p_object) { + return (Object::cast_to<FontVariation>(p_object) != nullptr) || (Object::cast_to<DynamicFontImportSettingsData>(p_object) != nullptr); +} + +bool EditorInspectorPluginFontVariation::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) { + if (p_path == "variation_opentype") { + add_property_editor(p_path, memnew(EditorPropertyOTVariation)); + return true; + } else if (p_path == "opentype_features") { + add_property_editor(p_path, memnew(EditorPropertyOTFeatures)); + return true; + } else if (p_path == "language_support") { + add_property_editor(p_path, memnew(EditorPropertyFontMetaOverride(false))); + return true; + } else if (p_path == "script_support") { + add_property_editor(p_path, memnew(EditorPropertyFontMetaOverride(true))); + return true; + } + return false; +} + +/*************************************************************************/ +/* FontPreview */ +/*************************************************************************/ + +void FontPreview::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_DRAW: { + // Draw font name (style). + Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label")); + int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label")); + Color text_color = get_theme_color(SNAME("font_color"), SNAME("Label")); + font->draw_string(get_canvas_item(), Point2(0, font->get_height(font_size) + 2 * EDSCALE), name, HORIZONTAL_ALIGNMENT_CENTER, get_size().x, font_size, text_color); + + // Draw font preview. + Vector2 pos = Vector2(0, font->get_height(font_size)) + (get_size() - Vector2(0, font->get_height(font_size)) - line->get_size()) / 2; + line->draw(get_canvas_item(), pos, text_color); + + // Draw font baseline. + Color line_color = text_color; + line_color.a *= 0.6; + draw_line(Vector2(0, pos.y + line->get_line_ascent()), Vector2(pos.x - 5, pos.y + line->get_line_ascent()), line_color); + draw_line(Vector2(pos.x + line->get_size().x + 5, pos.y + line->get_line_ascent()), Vector2(get_size().x, pos.y + line->get_line_ascent()), line_color); + } break; + } +} + +void FontPreview::_bind_methods() {} + +Size2 FontPreview::get_minimum_size() const { + return Vector2(64, 64) * EDSCALE; +} + +void FontPreview::set_data(const Ref<Font> &p_f) { + line->clear(); + if (p_f.is_valid()) { + name = vformat("%s (%s)", p_f->get_font_name(), p_f->get_font_style_name()); + if (p_f->is_class("FontVariation")) { + name += " " + TTR(" - Variation"); + } + String sample; + static const String sample_base = U"12漢字ԱբΑαАбΑαאבابܐܒހށआআਆઆଆஆఆಆആආกิກິༀကႠა한글ሀᎣᐁᚁᚠᜀᜠᝀᝠកᠠᤁᥐAb😀"; + for (int i = 0; i < sample_base.length(); i++) { + if (p_f->has_char(sample_base[i])) { + sample += sample_base[i]; + } + } + if (sample.is_empty()) { + sample = p_f->get_supported_chars().substr(0, 6); + } + line->add_string(sample, p_f, 50); + } + + update(); +} + +FontPreview::FontPreview() { + line.instantiate(); +} + +/*************************************************************************/ +/* EditorInspectorPluginFontPreview */ +/*************************************************************************/ + +bool EditorInspectorPluginFontPreview::can_handle(Object *p_object) { + return Object::cast_to<Font>(p_object) != nullptr; +} + +void EditorInspectorPluginFontPreview::parse_begin(Object *p_object) { + Font *fd = Object::cast_to<Font>(p_object); + ERR_FAIL_COND(!fd); + + FontPreview *editor = memnew(FontPreview); + editor->set_data(fd); + add_custom_control(editor); +} + +bool EditorInspectorPluginFontPreview::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) { + return false; +} + +/*************************************************************************/ +/* FontEditorPlugin */ +/*************************************************************************/ + +FontEditorPlugin::FontEditorPlugin() { + Ref<EditorInspectorPluginFontVariation> fc_plugin; + fc_plugin.instantiate(); + EditorInspector::add_inspector_plugin(fc_plugin); + + Ref<EditorInspectorPluginFontPreview> fp_plugin; + fp_plugin.instantiate(); + EditorInspector::add_inspector_plugin(fp_plugin); +} diff --git a/editor/plugins/font_config_plugin.h b/editor/plugins/font_config_plugin.h new file mode 100644 index 0000000000..9b7ee55870 --- /dev/null +++ b/editor/plugins/font_config_plugin.h @@ -0,0 +1,261 @@ +/*************************************************************************/ +/* font_config_plugin.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 OT_FEATURES_PLUGIN_H +#define OT_FEATURES_PLUGIN_H + +#include "core/io/marshalls.h" +#include "editor/editor_plugin.h" +#include "editor/editor_properties.h" + +/*************************************************************************/ + +class EditorPropertyFontMetaObject : public RefCounted { + GDCLASS(EditorPropertyFontMetaObject, RefCounted); + + Dictionary dict; + +protected: + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + static void _bind_methods(); + +public: + void set_dict(const Dictionary &p_dict); + Dictionary get_dict(); + + EditorPropertyFontMetaObject(){}; +}; + +/*************************************************************************/ + +class EditorPropertyFontOTObject : public RefCounted { + GDCLASS(EditorPropertyFontOTObject, RefCounted); + + Dictionary dict; + Dictionary defaults_dict; + +protected: + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + static void _bind_methods(); + +public: + void set_dict(const Dictionary &p_dict); + Dictionary get_dict(); + + void set_defaults(const Dictionary &p_dict); + Dictionary get_defaults(); + + bool property_can_revert(const String &p_name); + Variant property_get_revert(const String &p_name); + + EditorPropertyFontOTObject(){}; +}; + +/*************************************************************************/ + +class EditorPropertyFontMetaOverride : public EditorProperty { + GDCLASS(EditorPropertyFontMetaOverride, EditorProperty); + + Ref<EditorPropertyFontMetaObject> object; + + MarginContainer *container = nullptr; + VBoxContainer *property_vbox = nullptr; + + Button *button_add = nullptr; + Button *edit = nullptr; + PopupMenu *menu = nullptr; + EditorLocaleDialog *locale_select = nullptr; + + Vector<String> script_codes; + + bool script_editor = false; + bool updating = false; + int page_length = 20; + int page_index = 0; + EditorPaginator *paginator = nullptr; + +protected: + void _notification(int p_what); + static void _bind_methods(){}; + + void _edit_pressed(); + void _page_changed(int p_page); + void _property_changed(const String &p_property, Variant p_value, const String &p_name = "", bool p_changing = false); + void _remove(Object *p_button, const String &p_key); + void _add_menu(); + void _add_script(int p_option); + void _add_lang(const String &p_locale); + void _object_id_selected(const StringName &p_property, ObjectID p_id); + +public: + virtual void update_property() override; + + EditorPropertyFontMetaOverride(bool p_script); +}; + +/*************************************************************************/ + +class EditorPropertyOTVariation : public EditorProperty { + GDCLASS(EditorPropertyOTVariation, EditorProperty); + + Ref<EditorPropertyFontOTObject> object; + + MarginContainer *container = nullptr; + VBoxContainer *property_vbox = nullptr; + + Button *edit = nullptr; + + bool updating = false; + int page_length = 20; + int page_index = 0; + EditorPaginator *paginator = nullptr; + +protected: + void _notification(int p_what); + static void _bind_methods(){}; + + void _edit_pressed(); + void _page_changed(int p_page); + void _property_changed(const String &p_property, Variant p_value, const String &p_name = "", bool p_changing = false); + void _object_id_selected(const StringName &p_property, ObjectID p_id); + +public: + virtual void update_property() override; + + EditorPropertyOTVariation(); +}; + +/*************************************************************************/ + +class EditorPropertyOTFeatures : public EditorProperty { + GDCLASS(EditorPropertyOTFeatures, EditorProperty); + + enum FeatureGroups { + FGRP_STYLISTIC_SET, + FGRP_CHARACTER_VARIANT, + FGRP_CAPITLS, + FGRP_LIGATURES, + FGRP_ALTERNATES, + FGRP_EAL, + FGRP_EAW, + FGRP_NUMAL, + FGRP_CUSTOM, + FGRP_MAX, + }; + + Ref<EditorPropertyFontOTObject> object; + + MarginContainer *container = nullptr; + VBoxContainer *property_vbox = nullptr; + + Button *button_add = nullptr; + Button *edit = nullptr; + PopupMenu *menu = nullptr; + PopupMenu *menu_sub[FGRP_MAX]; + String group_names[FGRP_MAX]; + + bool updating = false; + int page_length = 20; + int page_index = 0; + EditorPaginator *paginator = nullptr; + +protected: + void _notification(int p_what); + static void _bind_methods(){}; + + void _edit_pressed(); + void _page_changed(int p_page); + void _property_changed(const String &p_property, Variant p_value, const String &p_name = "", bool p_changing = false); + void _remove(Object *p_button, int p_key); + void _add_menu(); + void _add_feature(int p_option); + void _object_id_selected(const StringName &p_property, ObjectID p_id); + +public: + virtual void update_property() override; + + EditorPropertyOTFeatures(); +}; + +/*************************************************************************/ + +class EditorInspectorPluginFontVariation : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginFontVariation, EditorInspectorPlugin); + +public: + virtual bool can_handle(Object *p_object) override; + virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override; +}; + +/*************************************************************************/ + +class FontPreview : public Control { + GDCLASS(FontPreview, Control); + +protected: + void _notification(int p_what); + static void _bind_methods(); + + String name; + Ref<TextLine> line; + +public: + virtual Size2 get_minimum_size() const override; + + void set_data(const Ref<Font> &p_f); + + FontPreview(); +}; + +/*************************************************************************/ + +class EditorInspectorPluginFontPreview : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginFontPreview, EditorInspectorPlugin); + +public: + virtual bool can_handle(Object *p_object) override; + virtual void parse_begin(Object *p_object) override; + virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override; +}; + +/*************************************************************************/ + +class FontEditorPlugin : public EditorPlugin { + GDCLASS(FontEditorPlugin, EditorPlugin); + +public: + FontEditorPlugin(); + + virtual String get_name() const override { return "Font"; } +}; + +#endif // OT_FEATURES_PLUGIN_H diff --git a/editor/plugins/font_editor_plugin.cpp b/editor/plugins/font_editor_plugin.cpp deleted file mode 100644 index b9de621bcb..0000000000 --- a/editor/plugins/font_editor_plugin.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/*************************************************************************/ -/* font_editor_plugin.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 "font_editor_plugin.h" - -#include "editor/editor_scale.h" - -void FontDataPreview::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_DRAW: { - Color text_color = get_theme_color(SNAME("font_color"), SNAME("Label")); - Color line_color = text_color; - line_color.a *= 0.6; - Vector2 pos = (get_size() - line->get_size()) / 2; - line->draw(get_canvas_item(), pos, text_color); - draw_line(Vector2(0, pos.y + line->get_line_ascent()), Vector2(pos.x - 5, pos.y + line->get_line_ascent()), line_color); - draw_line(Vector2(pos.x + line->get_size().x + 5, pos.y + line->get_line_ascent()), Vector2(get_size().x, pos.y + line->get_line_ascent()), line_color); - } break; - } -} - -void FontDataPreview::_bind_methods() {} - -Size2 FontDataPreview::get_minimum_size() const { - return Vector2(64, 64) * EDSCALE; -} - -void FontDataPreview::set_data(const Ref<FontData> &p_data) { - Ref<Font> f = memnew(Font); - f->add_data(p_data); - - line->clear(); - if (p_data.is_valid()) { - String sample; - static const String sample_base = U"12漢字ԱբΑαАбΑαאבابܐܒހށआআਆઆଆஆఆಆആආกิກິༀကႠა한글ሀᎣᐁᚁᚠᜀᜠᝀᝠកᠠᤁᥐAb😀"; - for (int i = 0; i < sample_base.length(); i++) { - if (p_data->has_char(sample_base[i])) { - sample += sample_base[i]; - } - } - if (sample.is_empty()) { - sample = p_data->get_supported_chars().substr(0, 6); - } - line->add_string(sample, f, 72); - } - - update(); -} - -FontDataPreview::FontDataPreview() { - line.instantiate(); -} - -/*************************************************************************/ - -bool EditorInspectorPluginFont::can_handle(Object *p_object) { - return Object::cast_to<FontData>(p_object) != nullptr; -} - -void EditorInspectorPluginFont::parse_begin(Object *p_object) { - FontData *fd = Object::cast_to<FontData>(p_object); - ERR_FAIL_COND(!fd); - - FontDataPreview *editor = memnew(FontDataPreview); - editor->set_data(fd); - add_custom_control(editor); -} - -bool EditorInspectorPluginFont::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) { - return false; -} - -/*************************************************************************/ - -FontEditorPlugin::FontEditorPlugin() { - Ref<EditorInspectorPluginFont> fd_plugin; - fd_plugin.instantiate(); - EditorInspector::add_inspector_plugin(fd_plugin); -} diff --git a/editor/plugins/font_editor_plugin.h b/editor/plugins/font_editor_plugin.h deleted file mode 100644 index 3f0700d880..0000000000 --- a/editor/plugins/font_editor_plugin.h +++ /dev/null @@ -1,77 +0,0 @@ -/*************************************************************************/ -/* font_editor_plugin.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 FONT_EDITOR_PLUGIN_H -#define FONT_EDITOR_PLUGIN_H - -#include "editor/editor_plugin.h" -#include "scene/resources/font.h" -#include "scene/resources/text_line.h" - -class FontDataPreview : public Control { - GDCLASS(FontDataPreview, Control); - -protected: - void _notification(int p_what); - static void _bind_methods(); - - Ref<TextLine> line; - -public: - virtual Size2 get_minimum_size() const override; - - void set_data(const Ref<FontData> &p_data); - - FontDataPreview(); -}; - -/*************************************************************************/ - -class EditorInspectorPluginFont : public EditorInspectorPlugin { - GDCLASS(EditorInspectorPluginFont, EditorInspectorPlugin); - -public: - virtual bool can_handle(Object *p_object) override; - virtual void parse_begin(Object *p_object) override; - virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override; -}; - -/*************************************************************************/ - -class FontEditorPlugin : public EditorPlugin { - GDCLASS(FontEditorPlugin, EditorPlugin); - -public: - FontEditorPlugin(); - - virtual String get_name() const override { return "Font"; } -}; - -#endif // FONT_EDITOR_PLUGIN_H diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 7730f7f294..99c492379d 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -145,7 +145,7 @@ void ViewportRotationControl::_draw_axis(const Axis2D &p_axis) { // Draw the axis letter for the positive axes. const String axis_name = direction == 0 ? "X" : (direction == 1 ? "Y" : "Z"); - draw_char(get_theme_font(SNAME("rotation_control"), SNAME("EditorFonts")), p_axis.screen_point + Vector2i(Math::round(-4.0 * EDSCALE), Math::round(5.0 * EDSCALE)), axis_name, "", get_theme_font_size(SNAME("rotation_control_size"), SNAME("EditorFonts")), Color(0.0, 0.0, 0.0, alpha)); + draw_char(get_theme_font(SNAME("rotation_control"), SNAME("EditorFonts")), p_axis.screen_point + Vector2i(Math::round(-4.0 * EDSCALE), Math::round(5.0 * EDSCALE)), axis_name, get_theme_font_size(SNAME("rotation_control_size"), SNAME("EditorFonts")), Color(0.0, 0.0, 0.0, alpha)); } else { // Draw an outline around the negative axes. draw_circle(p_axis.screen_point, AXIS_CIRCLE_RADIUS, c); @@ -2725,7 +2725,8 @@ static void draw_indicator_bar(Control &p_surface, real_t p_fill, const Ref<Text p_surface.draw_texture(p_icon, icon_pos, p_color); // Draw text below the bar (for speed/zoom information). - p_surface.draw_string(p_font, Vector2(icon_pos.x, icon_pos.y + icon_size.y + 16 * EDSCALE), p_text, HORIZONTAL_ALIGNMENT_LEFT, -1.f, p_font_size, p_color, Math::round(2 * EDSCALE), Color(0, 0, 0)); + p_surface.draw_string_outline(p_font, Vector2(icon_pos.x, icon_pos.y + icon_size.y + 16 * EDSCALE), p_text, HORIZONTAL_ALIGNMENT_LEFT, -1.f, p_font_size, Math::round(2 * EDSCALE), Color(0, 0, 0)); + p_surface.draw_string(p_font, Vector2(icon_pos.x, icon_pos.y + icon_size.y + 16 * EDSCALE), p_text, HORIZONTAL_ALIGNMENT_LEFT, -1.f, p_font_size, p_color); } void Node3DEditorViewport::_draw() { diff --git a/editor/plugins/ot_features_plugin.cpp b/editor/plugins/ot_features_plugin.cpp deleted file mode 100644 index f8526fb715..0000000000 --- a/editor/plugins/ot_features_plugin.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/*************************************************************************/ -/* ot_features_plugin.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 "ot_features_plugin.h" - -#include "scene/3d/label_3d.h" -#include "scene/resources/primitive_meshes.h" - -void OpenTypeFeaturesEditor::_value_changed(double val) { - if (setting) { - return; - } - - emit_changed(get_edited_property(), spin->get_value()); -} - -void OpenTypeFeaturesEditor::update_property() { - double val = get_edited_object()->get(get_edited_property()); - setting = true; - spin->set_value(val); - setting = false; -} - -void OpenTypeFeaturesEditor::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: - case NOTIFICATION_THEME_CHANGED: { - Color base = get_theme_color(SNAME("accent_color"), SNAME("Editor")); - - button->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); - button->set_size(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))->get_size()); - spin->add_theme_color_override("label_color", base); - } break; - } -} - -void OpenTypeFeaturesEditor::_remove_feature() { - get_edited_object()->set(get_edited_property(), -1); -} - -void OpenTypeFeaturesEditor::_bind_methods() { -} - -OpenTypeFeaturesEditor::OpenTypeFeaturesEditor() { - HBoxContainer *bc = memnew(HBoxContainer); - add_child(bc); - - spin = memnew(EditorSpinSlider); - spin->set_flat(true); - bc->add_child(spin); - add_focusable(spin); - spin->connect("value_changed", callable_mp(this, &OpenTypeFeaturesEditor::_value_changed)); - spin->set_h_size_flags(SIZE_EXPAND_FILL); - - spin->set_min(0); - spin->set_max(65536); - spin->set_step(1); - spin->set_hide_slider(false); - spin->set_allow_greater(false); - spin->set_allow_lesser(false); - - button = memnew(Button); - button->set_tooltip(RTR("Remove feature")); - button->set_flat(true); - bc->add_child(button); - - button->connect("pressed", callable_mp(this, &OpenTypeFeaturesEditor::_remove_feature)); - - setting = false; -} - -/*************************************************************************/ - -void OpenTypeFeaturesAdd::_add_feature(int p_option) { - edited_object->set("opentype_features/" + TS->tag_to_name(p_option), 1); -} - -void OpenTypeFeaturesAdd::_features_menu() { - Size2 size = get_size(); - menu->set_position(get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y)); - menu->reset_size(); - menu->popup(); -} - -void OpenTypeFeaturesAdd::setup(Object *p_object) { - edited_object = p_object; - - menu->clear(); - menu_ss->clear(); - menu_cv->clear(); - menu_cu->clear(); - bool have_ss = false; - bool have_cv = false; - bool have_cu = false; - - Ref<Font> font; - - Control *ctrl = Object::cast_to<Control>(edited_object); - if (ctrl != nullptr) { - font = ctrl->get_theme_font(SNAME("font")); - } - Label3D *l3d = Object::cast_to<Label3D>(edited_object); - if (l3d != nullptr) { - font = l3d->_get_font_or_default(); - } - TextMesh *tm = Object::cast_to<TextMesh>(edited_object); - if (tm != nullptr) { - font = tm->_get_font_or_default(); - } - - if (font.is_null()) { - return; - } - - Dictionary features = font->get_feature_list(); - - for (const Variant *ftr = features.next(nullptr); ftr != nullptr; ftr = features.next(ftr)) { - String ftr_name = TS->tag_to_name(*ftr); - if (ftr_name.begins_with("stylistic_set_")) { - menu_ss->add_item(ftr_name.capitalize(), (int32_t)*ftr); - have_ss = true; - } else if (ftr_name.begins_with("character_variant_")) { - menu_cv->add_item(ftr_name.capitalize(), (int32_t)*ftr); - have_cv = true; - } else if (ftr_name.begins_with("custom_")) { - menu_cu->add_item(ftr_name.replace("custom_", ""), (int32_t)*ftr); - have_cu = true; - } else { - menu->add_item(ftr_name.capitalize(), (int32_t)*ftr); - } - } - if (have_ss) { - menu->add_submenu_item(RTR("Stylistic Sets"), "SSMenu"); - } - if (have_cv) { - menu->add_submenu_item(RTR("Character Variants"), "CVMenu"); - } - if (have_cu) { - menu->add_submenu_item(RTR("Custom"), "CUMenu"); - } -} - -void OpenTypeFeaturesAdd::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - connect("pressed", callable_mp(this, &OpenTypeFeaturesAdd::_features_menu)); - [[fallthrough]]; - } - case NOTIFICATION_THEME_CHANGED: { - set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); - } break; - } -} - -void OpenTypeFeaturesAdd::_bind_methods() { -} - -OpenTypeFeaturesAdd::OpenTypeFeaturesAdd() { - set_text(TTR("Add Feature...")); - - menu = memnew(PopupMenu); - add_child(menu); - - menu_cv = memnew(PopupMenu); - menu_cv->set_name("CVMenu"); - menu->add_child(menu_cv); - - menu_ss = memnew(PopupMenu); - menu_ss->set_name("SSMenu"); - menu->add_child(menu_ss); - - menu_cu = memnew(PopupMenu); - menu_cu->set_name("CUMenu"); - menu->add_child(menu_cu); - - menu->connect("id_pressed", callable_mp(this, &OpenTypeFeaturesAdd::_add_feature)); - menu_cv->connect("id_pressed", callable_mp(this, &OpenTypeFeaturesAdd::_add_feature)); - menu_ss->connect("id_pressed", callable_mp(this, &OpenTypeFeaturesAdd::_add_feature)); - menu_cu->connect("id_pressed", callable_mp(this, &OpenTypeFeaturesAdd::_add_feature)); -} - -/*************************************************************************/ - -bool EditorInspectorPluginOpenTypeFeatures::can_handle(Object *p_object) { - return (Object::cast_to<Control>(p_object) != nullptr) || (Object::cast_to<Label3D>(p_object) != nullptr) || (Object::cast_to<TextMesh>(p_object) != nullptr); -} - -bool EditorInspectorPluginOpenTypeFeatures::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) { - if (p_path == "opentype_features/_new") { - OpenTypeFeaturesAdd *editor = memnew(OpenTypeFeaturesAdd); - editor->setup(p_object); - add_custom_control(editor); - return true; - } else if (p_path.begins_with("opentype_features")) { - OpenTypeFeaturesEditor *editor = memnew(OpenTypeFeaturesEditor); - add_property_editor(p_path, editor); - return true; - } - return false; -} - -/*************************************************************************/ - -OpenTypeFeaturesEditorPlugin::OpenTypeFeaturesEditorPlugin() { - Ref<EditorInspectorPluginOpenTypeFeatures> ftr_plugin; - ftr_plugin.instantiate(); - EditorInspector::add_inspector_plugin(ftr_plugin); -} diff --git a/editor/plugins/ot_features_plugin.h b/editor/plugins/ot_features_plugin.h deleted file mode 100644 index 6639148080..0000000000 --- a/editor/plugins/ot_features_plugin.h +++ /dev/null @@ -1,102 +0,0 @@ -/*************************************************************************/ -/* ot_features_plugin.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 OT_FEATURES_PLUGIN_H -#define OT_FEATURES_PLUGIN_H - -#include "editor/editor_plugin.h" -#include "editor/editor_properties.h" - -/*************************************************************************/ - -class OpenTypeFeaturesEditor : public EditorProperty { - GDCLASS(OpenTypeFeaturesEditor, EditorProperty); - EditorSpinSlider *spin = nullptr; - bool setting = true; - void _value_changed(double p_val); - Button *button = nullptr; - - void _remove_feature(); - -protected: - void _notification(int p_what); - static void _bind_methods(); - -public: - virtual void update_property() override; - OpenTypeFeaturesEditor(); -}; - -/*************************************************************************/ - -class OpenTypeFeaturesAdd : public Button { - GDCLASS(OpenTypeFeaturesAdd, Button); - - Object *edited_object = nullptr; - PopupMenu *menu = nullptr; - PopupMenu *menu_ss = nullptr; - PopupMenu *menu_cv = nullptr; - PopupMenu *menu_cu = nullptr; - - void _add_feature(int p_option); - void _features_menu(); - -protected: - void _notification(int p_what); - static void _bind_methods(); - -public: - void setup(Object *p_object); - - OpenTypeFeaturesAdd(); -}; - -/*************************************************************************/ - -class EditorInspectorPluginOpenTypeFeatures : public EditorInspectorPlugin { - GDCLASS(EditorInspectorPluginOpenTypeFeatures, EditorInspectorPlugin); - -public: - virtual bool can_handle(Object *p_object) override; - virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override; -}; - -/*************************************************************************/ - -class OpenTypeFeaturesEditorPlugin : public EditorPlugin { - GDCLASS(OpenTypeFeaturesEditorPlugin, EditorPlugin); - -public: - OpenTypeFeaturesEditorPlugin(); - - virtual String get_name() const override { return "OpenTypeFeatures"; } -}; - -#endif // OT_FEATURES_PLUGIN_H diff --git a/editor/plugins/text_control_editor_plugin.cpp b/editor/plugins/text_control_editor_plugin.cpp deleted file mode 100644 index 2a5faba4a2..0000000000 --- a/editor/plugins/text_control_editor_plugin.cpp +++ /dev/null @@ -1,660 +0,0 @@ -/*************************************************************************/ -/* text_control_editor_plugin.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 "text_control_editor_plugin.h" - -#include "editor/editor_node.h" -#include "editor/editor_scale.h" -#include "editor/multi_node_edit.h" - -void TextControlEditor::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - if (!EditorFileSystem::get_singleton()->is_connected("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts))) { - EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts), make_binds("")); - } - [[fallthrough]]; - } - case NOTIFICATION_THEME_CHANGED: { - clear_formatting->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); - } break; - - case NOTIFICATION_EXIT_TREE: { - if (EditorFileSystem::get_singleton()->is_connected("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts))) { - EditorFileSystem::get_singleton()->disconnect("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts)); - } - } break; - } -} - -void TextControlEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_update_control"), &TextControlEditor::_update_control); -} - -void TextControlEditor::_find_resources(EditorFileSystemDirectory *p_dir) { - for (int i = 0; i < p_dir->get_subdir_count(); i++) { - _find_resources(p_dir->get_subdir(i)); - } - - for (int i = 0; i < p_dir->get_file_count(); i++) { - if (p_dir->get_file_type(i) == "FontData") { - Ref<FontData> fd = ResourceLoader::load(p_dir->get_file_path(i)); - if (fd.is_valid()) { - String name = fd->get_font_name(); - String sty = fd->get_font_style_name(); - if (sty.is_empty()) { - sty = "Default"; - } - fonts[name][sty] = p_dir->get_file_path(i); - } - } - } -} - -void TextControlEditor::_reload_fonts(const String &p_path) { - fonts.clear(); - _find_resources(EditorFileSystem::get_singleton()->get_filesystem()); - _update_control(); -} - -void TextControlEditor::_update_fonts_menu() { - font_list->clear(); - font_list->add_item(TTR("[Theme Default]"), FONT_INFO_THEME_DEFAULT); - if (custom_font.is_valid()) { - font_list->add_item(TTR("[Custom Font]"), FONT_INFO_USER_CUSTOM); - } - - int id = FONT_INFO_ID; - for (const KeyValue<String, HashMap<String, String>> &E : fonts) { - font_list->add_item(E.key, id++); - } - - if (font_list->get_item_count() > 1) { - font_list->show(); - } else { - font_list->hide(); - } -} - -void TextControlEditor::_update_styles_menu() { - font_style_list->clear(); - if ((font_list->get_selected_id() >= FONT_INFO_ID)) { - const String &name = font_list->get_item_text(font_list->get_selected()); - for (KeyValue<String, String> &E : fonts[name]) { - font_style_list->add_item(E.key); - } - } else if (font_list->get_selected() >= 0) { - font_style_list->add_item("Default"); - } - - if (font_style_list->get_item_count() > 1) { - font_style_list->show(); - } else { - font_style_list->hide(); - } -} - -void TextControlEditor::_update_control() { - if (!edited_controls.is_empty()) { - String font_selected; - bool same_font = true; - String style_selected; - bool same_style = true; - int font_size = 0; - bool same_font_size = true; - int outline_size = 0; - bool same_outline_size = true; - Color font_color = Color{ 1.0f, 1.0f, 1.0f }; - bool same_font_color = true; - Color outline_color = Color{ 1.0f, 1.0f, 1.0f }; - bool same_outline_color = true; - - int count = edited_controls.size(); - for (int i = 0; i < count; ++i) { - Control *edited_control = edited_controls[i]; - - StringName edited_color; - StringName edited_font; - StringName edited_font_size; - - // Get override names. - if (Object::cast_to<RichTextLabel>(edited_control)) { - edited_color = SNAME("default_color"); - edited_font = SNAME("normal_font"); - edited_font_size = SNAME("normal_font_size"); - } else { - edited_color = SNAME("font_color"); - edited_font = SNAME("font"); - edited_font_size = SNAME("font_size"); - } - - // Get font override. - Ref<Font> font; - if (edited_control->has_theme_font_override(edited_font)) { - font = edited_control->get_theme_font(edited_font); - } - - if (font.is_valid()) { - if (font->get_data_count() != 1) { - if (i > 0) { - same_font = same_font && (custom_font == font); - } - custom_font = font; - - font_selected = TTR("[Custom Font]"); - same_style = false; - } else { - String name = font->get_data(0)->get_font_name(); - String style = font->get_data(0)->get_font_style_name(); - if (fonts.has(name) && fonts[name].has(style)) { - if (i > 0) { - same_font = same_font && (name == font_selected); - same_style = same_style && (style == style_selected); - } - font_selected = name; - style_selected = style; - } else { - if (i > 0) { - same_font = same_font && (custom_font == font); - } - custom_font = font; - - font_selected = TTR("[Custom Font]"); - same_style = false; - } - } - } else { - if (i > 0) { - same_font = same_font && (font_selected == TTR("[Theme Default]")); - } - - font_selected = TTR("[Theme Default]"); - same_style = false; - } - - int current_font_size = edited_control->get_theme_font_size(edited_font_size); - int current_outline_size = edited_control->get_theme_constant(SNAME("outline_size")); - Color current_font_color = edited_control->get_theme_color(edited_color); - Color current_outline_color = edited_control->get_theme_color(SNAME("font_outline_color")); - if (i > 0) { - same_font_size = same_font_size && (font_size == current_font_size); - same_outline_size = same_outline_size && (outline_size == current_outline_size); - same_font_color = same_font_color && (font_color == current_font_color); - same_outline_color = same_outline_color && (outline_color == current_outline_color); - } - - font_size = current_font_size; - outline_size = current_outline_size; - font_color = current_font_color; - outline_color = current_outline_color; - } - _update_fonts_menu(); - if (same_font) { - for (int j = 0; j < font_list->get_item_count(); j++) { - if (font_list->get_item_text(j) == font_selected) { - font_list->select(j); - break; - } - } - } else { - custom_font = Ref<Font>(); - font_list->select(-1); - } - - _update_styles_menu(); - if (same_style) { - for (int j = 0; j < font_style_list->get_item_count(); j++) { - if (font_style_list->get_item_text(j) == style_selected) { - font_style_list->select(j); - break; - } - } - } else { - font_style_list->select(-1); - } - - // Get other theme overrides. - font_size_list->set_block_signals(true); - if (same_font_size) { - font_size_list->get_line_edit()->set_text(String::num_uint64(font_size)); - font_size_list->set_value(font_size); - } else { - font_size_list->get_line_edit()->set_text(""); - } - font_size_list->set_block_signals(false); - - outline_size_list->set_block_signals(true); - if (same_outline_size) { - outline_size_list->get_line_edit()->set_text(String::num_uint64(outline_size)); - outline_size_list->set_value(outline_size); - } else { - outline_size_list->get_line_edit()->set_text(""); - } - outline_size_list->set_block_signals(false); - - if (!same_font_color) { - font_color = Color{ 1.0f, 1.0f, 1.0f }; - } - font_color_picker->set_pick_color(font_color); - - if (!same_outline_color) { - outline_color = Color{ 1.0f, 1.0f, 1.0f }; - } - outline_color_picker->set_pick_color(outline_color); - } -} - -void TextControlEditor::_font_selected(int p_id) { - _update_styles_menu(); - _set_font(); -} - -void TextControlEditor::_font_style_selected(int p_id) { - _set_font(); -} - -void TextControlEditor::_set_font() { - if (edited_controls.is_empty()) { - return; - } - - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Set Font")); - - int count = edited_controls.size(); - for (int i = 0; i < count; ++i) { - Control *edited_control = edited_controls[i]; - - StringName edited_font; - if (Object::cast_to<RichTextLabel>(edited_control)) { - edited_font = SNAME("normal_font"); - } else { - edited_font = SNAME("font"); - } - - if (font_list->get_selected_id() == FONT_INFO_THEME_DEFAULT) { - // Remove font override. - ur->add_do_method(edited_control, "remove_theme_font_override", edited_font); - } else if (font_list->get_selected_id() == FONT_INFO_USER_CUSTOM) { - // Restore "custom_font". - ur->add_do_method(edited_control, "add_theme_font_override", edited_font, custom_font); - } else if (font_list->get_selected() >= 0) { - // Load new font resource using selected name and style. - String name = font_list->get_item_text(font_list->get_selected()); - String style = font_style_list->get_item_text(font_style_list->get_selected()); - if (style.is_empty()) { - style = "Default"; - } - if (fonts.has(name)) { - Ref<FontData> fd = ResourceLoader::load(fonts[name][style]); - if (fd.is_valid()) { - Ref<Font> font; - font.instantiate(); - font->add_data(fd); - ur->add_do_method(edited_control, "add_theme_font_override", edited_font, font); - } - } - } - - if (edited_control->has_theme_font_override(edited_font)) { - ur->add_undo_method(edited_control, "add_theme_font_override", edited_font, edited_control->get_theme_font(edited_font)); - } else { - ur->add_undo_method(edited_control, "remove_theme_font_override", edited_font); - } - } - - ur->add_do_method(this, "_update_control"); - ur->add_undo_method(this, "_update_control"); - - ur->commit_action(); -} - -void TextControlEditor::_font_size_selected(double p_size) { - if (edited_controls.is_empty()) { - return; - } - - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Set Font Size")); - - int count = edited_controls.size(); - for (int i = 0; i < count; ++i) { - Control *edited_control = edited_controls[i]; - - StringName edited_font_size; - if (Object::cast_to<RichTextLabel>(edited_control)) { - edited_font_size = SNAME("normal_font_size"); - } else { - edited_font_size = SNAME("font_size"); - } - - ur->add_do_method(edited_control, "add_theme_font_size_override", edited_font_size, p_size); - if (edited_control->has_theme_font_size_override(edited_font_size)) { - ur->add_undo_method(edited_control, "add_theme_font_size_override", edited_font_size, edited_control->get_theme_font_size(edited_font_size)); - } else { - ur->add_undo_method(edited_control, "remove_theme_font_size_override", edited_font_size); - } - } - - ur->add_do_method(this, "_update_control"); - ur->add_undo_method(this, "_update_control"); - - ur->commit_action(); -} - -void TextControlEditor::_outline_size_selected(double p_size) { - if (edited_controls.is_empty()) { - return; - } - - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Set Font Outline Size")); - - int count = edited_controls.size(); - for (int i = 0; i < count; ++i) { - Control *edited_control = edited_controls[i]; - - ur->add_do_method(edited_control, "add_theme_constant_override", "outline_size", p_size); - if (edited_control->has_theme_constant_override("outline_size")) { - ur->add_undo_method(edited_control, "add_theme_constant_override", "outline_size", edited_control->get_theme_constant(SNAME("outline_size"))); - } else { - ur->add_undo_method(edited_control, "remove_theme_constant_override", "outline_size"); - } - } - - ur->add_do_method(this, "_update_control"); - ur->add_undo_method(this, "_update_control"); - - ur->commit_action(); -} - -void TextControlEditor::_font_color_changed(const Color &p_color) { - if (edited_controls.is_empty()) { - return; - } - - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Set Font Color"), UndoRedo::MERGE_ENDS); - - int count = edited_controls.size(); - for (int i = 0; i < count; ++i) { - Control *edited_control = edited_controls[i]; - - StringName edited_color; - if (Object::cast_to<RichTextLabel>(edited_control)) { - edited_color = SNAME("default_color"); - } else { - edited_color = SNAME("font_color"); - } - - ur->add_do_method(edited_control, "add_theme_color_override", edited_color, p_color); - if (edited_control->has_theme_color_override(edited_color)) { - ur->add_undo_method(edited_control, "add_theme_color_override", edited_color, edited_control->get_theme_color(edited_color)); - } else { - ur->add_undo_method(edited_control, "remove_theme_color_override", edited_color); - } - } - - ur->add_do_method(this, "_update_control"); - ur->add_undo_method(this, "_update_control"); - - ur->commit_action(); -} - -void TextControlEditor::_outline_color_changed(const Color &p_color) { - if (edited_controls.is_empty()) { - return; - } - - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Set Font Outline Color"), UndoRedo::MERGE_ENDS); - - int count = edited_controls.size(); - for (int i = 0; i < count; ++i) { - Control *edited_control = edited_controls[i]; - - ur->add_do_method(edited_control, "add_theme_color_override", "font_outline_color", p_color); - if (edited_control->has_theme_color_override("font_outline_color")) { - ur->add_undo_method(edited_control, "add_theme_color_override", "font_outline_color", edited_control->get_theme_color(SNAME("font_outline_color"))); - } else { - ur->add_undo_method(edited_control, "remove_theme_color_override", "font_outline_color"); - } - } - - ur->add_do_method(this, "_update_control"); - ur->add_undo_method(this, "_update_control"); - - ur->commit_action(); -} - -void TextControlEditor::_clear_formatting() { - if (edited_controls.is_empty()) { - return; - } - - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Clear Control Formatting")); - - int count = edited_controls.size(); - for (int i = 0; i < count; ++i) { - Control *edited_control = edited_controls[i]; - - StringName edited_color; - StringName edited_font; - StringName edited_font_size; - - // Get override names. - if (Object::cast_to<RichTextLabel>(edited_control)) { - edited_color = SNAME("default_color"); - edited_font = SNAME("normal_font"); - edited_font_size = SNAME("normal_font_size"); - } else { - edited_color = SNAME("font_color"); - edited_font = SNAME("font"); - edited_font_size = SNAME("font_size"); - } - - ur->add_do_method(edited_control, "begin_bulk_theme_override"); - ur->add_undo_method(edited_control, "begin_bulk_theme_override"); - - ur->add_do_method(edited_control, "remove_theme_font_override", edited_font); - if (edited_control->has_theme_font_override(edited_font)) { - ur->add_undo_method(edited_control, "add_theme_font_override", edited_font, edited_control->get_theme_font(edited_font)); - } - - ur->add_do_method(edited_control, "remove_theme_font_size_override", edited_font_size); - if (edited_control->has_theme_font_size_override(edited_font_size)) { - ur->add_undo_method(edited_control, "add_theme_font_size_override", edited_font_size, edited_control->get_theme_font_size(edited_font_size)); - } - - ur->add_do_method(edited_control, "remove_theme_color_override", edited_color); - if (edited_control->has_theme_color_override(edited_color)) { - ur->add_undo_method(edited_control, "add_theme_color_override", edited_color, edited_control->get_theme_color(edited_color)); - } - - ur->add_do_method(edited_control, "remove_theme_color_override", "font_outline_color"); - if (edited_control->has_theme_color_override("font_outline_color")) { - ur->add_undo_method(edited_control, "add_theme_color_override", "font_outline_color", edited_control->get_theme_color(SNAME("font_outline_color"))); - } - - ur->add_do_method(edited_control, "remove_theme_constant_override", "outline_size"); - if (edited_control->has_theme_constant_override("outline_size")) { - ur->add_undo_method(edited_control, "add_theme_constant_override", "outline_size", edited_control->get_theme_constant(SNAME("outline_size"))); - } - - ur->add_do_method(edited_control, "end_bulk_theme_override"); - ur->add_undo_method(edited_control, "end_bulk_theme_override"); - } - - ur->add_do_method(this, "_update_control"); - ur->add_undo_method(this, "_update_control"); - - ur->commit_action(); -} - -void TextControlEditor::edit(Object *p_object) { - Control *ctrl = Object::cast_to<Control>(p_object); - MultiNodeEdit *multi_node = Object::cast_to<MultiNodeEdit>(p_object); - - edited_controls.clear(); - custom_font = Ref<Font>(); - if (ctrl) { - edited_controls.append(ctrl); - _update_control(); - } else if (multi_node && handles(multi_node)) { - int count = multi_node->get_node_count(); - Node *scene = EditorNode::get_singleton()->get_edited_scene(); - - for (int i = 0; i < count; ++i) { - Control *child = Object::cast_to<Control>(scene->get_node(multi_node->get_node(i))); - edited_controls.append(child); - } - _update_control(); - } -} - -bool TextControlEditor::handles(Object *p_object) const { - Control *ctrl = Object::cast_to<Control>(p_object); - MultiNodeEdit *multi_node = Object::cast_to<MultiNodeEdit>(p_object); - - if (!ctrl && !multi_node) { - return false; - } else if (ctrl) { - bool valid = false; - ctrl->get("text", &valid); - return valid; - } else { - bool valid = true; - int count = multi_node->get_node_count(); - Node *scene = EditorNode::get_singleton()->get_edited_scene(); - - for (int i = 0; i < count; ++i) { - bool temp_valid = false; - Control *child = Object::cast_to<Control>(scene->get_node(multi_node->get_node(i))); - if (child) { - child->get("text", &temp_valid); - } - valid = valid && temp_valid; - - if (!valid) { - break; - } - } - - return valid; - } -} - -TextControlEditor::TextControlEditor() { - add_child(memnew(VSeparator)); - - font_list = memnew(OptionButton); - font_list->set_flat(true); - font_list->set_tooltip(TTR("Font")); - add_child(font_list); - font_list->connect("item_selected", callable_mp(this, &TextControlEditor::_font_selected)); - - font_style_list = memnew(OptionButton); - font_style_list->set_flat(true); - font_style_list->set_tooltip(TTR("Font style")); - font_style_list->set_toggle_mode(true); - add_child(font_style_list); - font_style_list->connect("item_selected", callable_mp(this, &TextControlEditor::_font_style_selected)); - - font_size_list = memnew(SpinBox); - font_size_list->set_tooltip(TTR("Font Size")); - font_size_list->get_line_edit()->add_theme_constant_override("minimum_character_width", 2); - font_size_list->set_min(6); - font_size_list->set_step(1); - font_size_list->set_max(96); - font_size_list->get_line_edit()->set_flat(true); - add_child(font_size_list); - font_size_list->connect("value_changed", callable_mp(this, &TextControlEditor::_font_size_selected)); - - font_color_picker = memnew(ColorPickerButton); - font_color_picker->set_custom_minimum_size(Size2(20, 0) * EDSCALE); - font_color_picker->set_flat(true); - font_color_picker->set_tooltip(TTR("Text Color")); - add_child(font_color_picker); - font_color_picker->connect("color_changed", callable_mp(this, &TextControlEditor::_font_color_changed)); - - add_child(memnew(VSeparator)); - - outline_size_list = memnew(SpinBox); - outline_size_list->set_tooltip(TTR("Outline Size")); - outline_size_list->get_line_edit()->add_theme_constant_override("minimum_character_width", 2); - outline_size_list->set_min(0); - outline_size_list->set_step(1); - outline_size_list->set_max(96); - outline_size_list->get_line_edit()->set_flat(true); - add_child(outline_size_list); - outline_size_list->connect("value_changed", callable_mp(this, &TextControlEditor::_outline_size_selected)); - - outline_color_picker = memnew(ColorPickerButton); - outline_color_picker->set_custom_minimum_size(Size2(20, 0) * EDSCALE); - outline_color_picker->set_flat(true); - outline_color_picker->set_tooltip(TTR("Outline Color")); - add_child(outline_color_picker); - outline_color_picker->connect("color_changed", callable_mp(this, &TextControlEditor::_outline_color_changed)); - - add_child(memnew(VSeparator)); - - clear_formatting = memnew(Button); - clear_formatting->set_flat(true); - clear_formatting->set_tooltip(TTR("Clear Formatting")); - add_child(clear_formatting); - clear_formatting->connect("pressed", callable_mp(this, &TextControlEditor::_clear_formatting)); -} - -/*************************************************************************/ - -void TextControlEditorPlugin::edit(Object *p_object) { - text_ctl_editor->edit(p_object); -} - -bool TextControlEditorPlugin::handles(Object *p_object) const { - return text_ctl_editor->handles(p_object); -} - -void TextControlEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { - text_ctl_editor->show(); - } else { - text_ctl_editor->hide(); - text_ctl_editor->edit(nullptr); - } -} - -TextControlEditorPlugin::TextControlEditorPlugin() { - text_ctl_editor = memnew(TextControlEditor); - CanvasItemEditor::get_singleton()->add_control_to_menu_panel(text_ctl_editor); - - text_ctl_editor->hide(); -} diff --git a/editor/plugins/text_control_editor_plugin.h b/editor/plugins/text_control_editor_plugin.h deleted file mode 100644 index cf069338b6..0000000000 --- a/editor/plugins/text_control_editor_plugin.h +++ /dev/null @@ -1,115 +0,0 @@ -/*************************************************************************/ -/* text_control_editor_plugin.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 TEXT_CONTROL_EDITOR_PLUGIN_H -#define TEXT_CONTROL_EDITOR_PLUGIN_H - -#include "canvas_item_editor_plugin.h" -#include "editor/editor_file_system.h" -#include "editor/editor_inspector.h" -#include "editor/editor_plugin.h" -#include "scene/gui/color_picker.h" -#include "scene/gui/color_rect.h" -#include "scene/gui/menu_button.h" -#include "scene/gui/option_button.h" -#include "scene/gui/popup_menu.h" - -/*************************************************************************/ - -class TextControlEditor : public HBoxContainer { - GDCLASS(TextControlEditor, HBoxContainer); - - enum FontInfoID { - FONT_INFO_THEME_DEFAULT = 0, - FONT_INFO_USER_CUSTOM = 1, - FONT_INFO_ID = 100, - }; - - HashMap<String, HashMap<String, String>> fonts; - - OptionButton *font_list = nullptr; - SpinBox *font_size_list = nullptr; - OptionButton *font_style_list = nullptr; - ColorPickerButton *font_color_picker = nullptr; - SpinBox *outline_size_list = nullptr; - ColorPickerButton *outline_color_picker = nullptr; - Button *clear_formatting = nullptr; - - Vector<Control *> edited_controls; - Ref<Font> custom_font; - -protected: - void _notification(int p_what); - static void _bind_methods(); - - void _find_resources(EditorFileSystemDirectory *p_dir); - void _reload_fonts(const String &p_path); - - void _update_fonts_menu(); - void _update_styles_menu(); - void _update_control(); - - void _font_selected(int p_id); - void _font_style_selected(int p_id); - void _set_font(); - - void _font_size_selected(double p_size); - void _outline_size_selected(double p_size); - - void _font_color_changed(const Color &p_color); - void _outline_color_changed(const Color &p_color); - - void _clear_formatting(); - -public: - void edit(Object *p_object); - bool handles(Object *p_object) const; - - TextControlEditor(); -}; - -/*************************************************************************/ - -class TextControlEditorPlugin : public EditorPlugin { - GDCLASS(TextControlEditorPlugin, EditorPlugin); - - TextControlEditor *text_ctl_editor = nullptr; - -public: - virtual String get_name() const override { return "TextControlFontEditor"; } - bool has_main_screen() const override { return false; } - virtual void edit(Object *p_object) override; - virtual bool handles(Object *p_object) const override; - virtual void make_visible(bool p_visible) override; - - TextControlEditorPlugin(); -}; - -#endif // TEXT_CONTROL_EDITOR_PLUGIN_H diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index c7dc61b3a8..b01b90cd08 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -2931,10 +2931,6 @@ void ThemeTypeEditor::_item_remove_cbk(int p_data_type, String p_item_name) { ur->add_undo_method(*edited_theme, "set_font", p_item_name, edited_type, Ref<Font>()); } } break; - case Theme::DATA_TYPE_FONT_SIZE: { - ur->add_do_method(*edited_theme, "clear_font_size", p_item_name, edited_type); - ur->add_undo_method(*edited_theme, "set_font_size", p_item_name, edited_type, edited_theme->get_font_size(p_item_name, edited_type)); - } break; case Theme::DATA_TYPE_ICON: { ur->add_do_method(*edited_theme, "clear_icon", p_item_name, edited_type); if (edited_theme->has_icon(p_item_name, edited_type)) { @@ -3698,7 +3694,7 @@ bool ThemeEditorPlugin::handles(Object *p_node) const { // If we are editing a theme already and this particular resource happens to belong to it, // then we just keep editing it, despite not being able to directly handle it. - // This only goes one layer deep, but if required this can be extended to support, say, FontData inside of Font. + // This only goes one layer deep, but if required this can be extended to support, say, Font inside of Font. bool belongs_to_theme = false; if (Object::cast_to<Font>(p_node)) { diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp index a6e34cf5e0..826631d750 100644 --- a/editor/plugins/theme_editor_preview.cpp +++ b/editor/plugins/theme_editor_preview.cpp @@ -126,7 +126,7 @@ void ThemeEditorPreview::_draw_picker_overlay() { } Rect2 highlight_label_rect = highlight_rect; - highlight_label_rect.size = theme_cache.preview_picker_font->get_string_size(highlight_name, theme_cache.font_size); + highlight_label_rect.size = theme_cache.preview_picker_font->get_string_size(highlight_name, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size); int margin_top = theme_cache.preview_picker_label->get_margin(SIDE_TOP); int margin_left = theme_cache.preview_picker_label->get_margin(SIDE_LEFT); diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index 468681c967..1263ee5758 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -218,7 +218,7 @@ void GenericTilePolygonEditor::_base_control_draw() { Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label")); int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label")); String text = multiple_polygon_mode ? vformat("%d:%d", tinted_polygon_index, tinted_point_index) : vformat("%d", tinted_point_index); - Size2 text_size = font->get_string_size(text, font_size); + Size2 text_size = font->get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size); base_control->draw_string(font, xform.xform(polygons[tinted_polygon_index][tinted_point_index]) - text_size * 0.5, text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(1.0, 1.0, 1.0, 0.5)); } @@ -1116,8 +1116,9 @@ void TileDataDefaultEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2 } } - Vector2 string_size = font->get_string_size(text, font_size); - p_canvas_item->draw_string(font, p_transform.get_origin() + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color, 1, Color(0, 0, 0, 1)); + Vector2 string_size = font->get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size); + p_canvas_item->draw_string_outline(font, p_transform.get_origin() + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, 1, Color(0, 0, 0, 1)); + p_canvas_item->draw_string(font, p_transform.get_origin() + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color); } } @@ -1727,8 +1728,9 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas } else { text = "-"; } - Vector2 string_size = font->get_string_size(text, font_size); - p_canvas_item->draw_string(font, p_transform.xform(position) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color, 1, Color(0, 0, 0, 1)); + Vector2 string_size = font->get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size); + p_canvas_item->draw_string_outline(font, p_transform.xform(position) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, 1, Color(0, 0, 0, 1)); + p_canvas_item->draw_string(font, p_transform.xform(position) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color); } } } @@ -1918,8 +1920,9 @@ void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_til } else { text = "-"; } - Vector2 string_size = font->get_string_size(text, font_size); - p_canvas_item->draw_string(font, p_transform.xform(position) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color, 1, Color(0, 0, 0, 1)); + Vector2 string_size = font->get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size); + p_canvas_item->draw_string_outline(font, p_transform.xform(position) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, 1, Color(0, 0, 0, 1)); + p_canvas_item->draw_string(font, p_transform.xform(position) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color); } } } diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index 9ed3b72587..654ebf4573 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -1253,7 +1253,7 @@ static const char *class_renames[][2] = { { "AudioStreamRandomPitch", "AudioStreamRandomizer" }, { "BakedLightmap", "LightmapGI" }, { "BakedLightmapData", "LightmapGIData" }, - { "BitmapFont", "Font" }, + { "BitmapFont", "FontFile" }, { "BoneAttachment", "BoneAttachment3D" }, { "BoxShape", "BoxShape3D" }, { "CPUParticles", "CPUParticles3D" }, @@ -1279,8 +1279,8 @@ static const char *class_renames[][2] = { { "CubeMesh", "BoxMesh" }, { "CylinderShape", "CylinderShape3D" }, { "DirectionalLight", "DirectionalLight3D" }, - { "DynamicFont", "Font" }, - { "DynamicFontData", "FontData" }, + { "DynamicFont", "FontFile" }, + { "DynamicFontData", "FontFile" }, { "EditorNavigationMeshGenerator", "NavigationMeshGenerator" }, { "EditorSceneImporter", "EditorSceneFormatImporter" }, { "EditorSceneImporterFBX", "EditorSceneFormatImporterFBX" }, |