diff options
50 files changed, 643 insertions, 87 deletions
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index d189f3224b..df1aae5370 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -3359,36 +3359,36 @@ String String::repeat(int p_count) const { return new_string; } -String String::left(int p_pos) const { - if (p_pos < 0) { - p_pos = length() + p_pos; +String String::left(int p_len) const { + if (p_len < 0) { + p_len = length() + p_len; } - if (p_pos <= 0) { + if (p_len <= 0) { return ""; } - if (p_pos >= length()) { + if (p_len >= length()) { return *this; } - return substr(0, p_pos); + return substr(0, p_len); } -String String::right(int p_pos) const { - if (p_pos < 0) { - p_pos = length() + p_pos; +String String::right(int p_len) const { + if (p_len < 0) { + p_len = length() + p_len; } - if (p_pos <= 0) { + if (p_len <= 0) { return ""; } - if (p_pos >= length()) { + if (p_len >= length()) { return *this; } - return substr(length() - p_pos); + return substr(length() - p_len); } char32_t String::unicode_at(int p_idx) const { diff --git a/core/string/ustring.h b/core/string/ustring.h index e4f6c3327a..11d0974381 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -356,8 +356,8 @@ public: int count(const String &p_string, int p_from = 0, int p_to = 0) const; int countn(const String &p_string, int p_from = 0, int p_to = 0) const; - String left(int p_pos) const; - String right(int p_pos) const; + String left(int p_len) const; + String right(int p_len) const; String indent(const String &p_prefix) const; String dedent() const; String strip_edges(bool left = true, bool right = true) const; diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 741d3e5b8f..b335f2fcf4 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1402,8 +1402,8 @@ static void _register_variant_builtin_methods() { bind_method(String, to_upper, sarray(), varray()); bind_method(String, to_lower, sarray(), varray()); - bind_method(String, left, sarray("position"), varray()); - bind_method(String, right, sarray("position"), varray()); + bind_method(String, left, sarray("length"), varray()); + bind_method(String, right, sarray("length"), varray()); bind_method(String, strip_edges, sarray("left", "right"), varray(true, true)); bind_method(String, strip_escapes, sarray(), varray()); diff --git a/doc/classes/AnimationLibrary.xml b/doc/classes/AnimationLibrary.xml index 0a731edadd..d856c65dfc 100644 --- a/doc/classes/AnimationLibrary.xml +++ b/doc/classes/AnimationLibrary.xml @@ -51,18 +51,18 @@ </members> <signals> <signal name="animation_added"> - <argument index="0" name="name" type="Animation" /> + <argument index="0" name="name" type="StringName" /> <description> </description> </signal> <signal name="animation_removed"> - <argument index="0" name="name" type="Animation" /> + <argument index="0" name="name" type="StringName" /> <description> </description> </signal> <signal name="animation_renamed"> - <argument index="0" name="name" type="Animation" /> - <argument index="1" name="to_name" type="Animation" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="to_name" type="StringName" /> <description> </description> </signal> diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml index d85d02fbfb..4ece57fa81 100644 --- a/doc/classes/Button.xml +++ b/doc/classes/Button.xml @@ -92,6 +92,9 @@ <member name="text_direction" type="int" setter="set_text_direction" getter="get_text_direction" enum="Control.TextDirection" default="0"> Base text writing direction. </member> + <member name="text_overrun_behavior" type="int" setter="set_text_overrun_behavior" getter="get_text_overrun_behavior" enum="TextParagraph.OverrunBehavior" default="0"> + Sets the clipping behavior when the text exceeds the node's bounding rectangle. See [enum TextParagraph.OverrunBehavior] for a description of all modes. + </member> </members> <theme_items> <theme_item name="font_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 1)"> diff --git a/doc/classes/CurveTexture.xml b/doc/classes/CurveTexture.xml index 6aa39e453e..85473fc237 100644 --- a/doc/classes/CurveTexture.xml +++ b/doc/classes/CurveTexture.xml @@ -5,23 +5,27 @@ </brief_description> <description> Renders a given [Curve] provided to it. Simplifies the task of drawing curves and/or saving them as image files. + If you need to store up to 3 curves within a single texture, use [CurveXYZTexture] instead. See also [GradientTexture1D] and [GradientTexture2D]. </description> <tutorials> </tutorials> <members> <member name="curve" type="Curve" setter="set_curve" getter="get_curve"> - The [code]curve[/code] rendered onto the texture. + The [Curve] that is rendered onto the texture. </member> <member name="texture_mode" type="int" setter="set_texture_mode" getter="get_texture_mode" enum="CurveTexture.TextureMode" default="0"> + The format the texture should be generated with. When passing a CurveTexture as a input to a [Shader], this may need to be adjusted. </member> <member name="width" type="int" setter="set_width" getter="get_width" default="256"> - The width of the texture. + The width of the texture (in pixels). Higher values make it possible to represent high-frequency data better (such as sudden direction changes), at the cost of increased generation time and memory usage. </member> </members> <constants> <constant name="TEXTURE_MODE_RGB" value="0" enum="TextureMode"> + Store the curve equally across the red, green and blue channels. This uses more video memory, but is more compatible with shaders that only read the green and blue values. </constant> <constant name="TEXTURE_MODE_RED" value="1" enum="TextureMode"> + Store the curve only in the red channel. This saves video memory, but some custom shaders may not be able to work with this. </constant> </constants> </class> diff --git a/doc/classes/CurveXYZTexture.xml b/doc/classes/CurveXYZTexture.xml index d289e394aa..e3f2e8fc45 100644 --- a/doc/classes/CurveXYZTexture.xml +++ b/doc/classes/CurveXYZTexture.xml @@ -1,19 +1,26 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="CurveXYZTexture" inherits="Texture2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> + A texture that shows 3 different curves (stored on the red, green and blue color channels). </brief_description> <description> + Renders 3 given [Curve]s provided to it, on the red, green and blue channels respectively. Compared to using separate [CurveTexture]s, this further simplifies the task of drawing curves and/or saving them as image files. + If you only need to store one curve within a single texture, use [CurveTexture] instead. See also [GradientTexture1D] and [GradientTexture2D]. </description> <tutorials> </tutorials> <members> <member name="curve_x" type="Curve" setter="set_curve_x" getter="get_curve_x"> + The [Curve] that is rendered onto the texture's red channel. </member> <member name="curve_y" type="Curve" setter="set_curve_y" getter="get_curve_y"> + The [Curve] that is rendered onto the texture's green channel. </member> <member name="curve_z" type="Curve" setter="set_curve_z" getter="get_curve_z"> + The [Curve] that is rendered onto the texture's blue channel. </member> <member name="width" type="int" setter="set_width" getter="get_width" default="256"> + The width of the texture (in pixels). Higher values make it possible to represent high-frequency data better (such as sudden direction changes), at the cost of increased generation time and memory usage. </member> </members> </class> diff --git a/doc/classes/FontData.xml b/doc/classes/FontData.xml index a423d7a4e4..d32e7b3a94 100644 --- a/doc/classes/FontData.xml +++ b/doc/classes/FontData.xml @@ -3,7 +3,7 @@ <brief_description> Font source data and prerendered glyph cache, imported from dynamic or bitmap font. Supported font formats: - - Dynamic font importer: TrueType (.ttf), OpenType (.otf), WOFF (.woff), WOFF2 (.woff2), Type 1 (.pfb, .pfm). + - Dynamic font importer: TrueType (.ttf), TrueType collection (.ttc), OpenType (.otf), OpenType collection (.otc), WOFF (.woff), WOFF2 (.woff2), Type 1 (.pfb, .pfm). - Bitmap font importer: AngelCode BMFont (.fnt, .font), text and binary (version 3) format variants. - Monospace image font importer: All supported image formats. </brief_description> @@ -87,6 +87,12 @@ Returns font descent (number of pixels below the baseline). </description> </method> + <method name="get_face_count" qualifiers="const"> + <return type="int" /> + <description> + Returns number of faces in the TrueType / OpenType collection. + </description> + </method> <method name="get_glyph_advance" qualifiers="const"> <return type="Vector2" /> <argument index="0" name="cache_index" type="int" /> @@ -318,7 +324,8 @@ <return type="int" enum="Error" /> <argument index="0" name="path" type="String" /> <description> - Loads a TrueType (.ttf), OpenType (.otf), WOFF (.woff), WOFF2 (.woff2) or Type 1 (.pfb, .pfm) dynamic font from file [code]path[/code]. + Loads a TrueType (.ttf), TrueType collection (.ttc), OpenType (.otf), OpenType collection (.otc), WOFF (.woff), WOFF2 (.woff2) or Type 1 (.pfb, .pfm) dynamic font from file [code]path[/code]. + [b]Note:[/b] Use [member face_index] to select specific face from the collection file. [b]Warning:[/b] This method should only be used in the editor or in cases when you need to load external fonts at run-time, such as fonts located at the [code]user://[/code] directory. </description> </method> @@ -570,6 +577,9 @@ <member name="embolden" type="float" setter="set_embolden" getter="get_embolden" default="0.0"> If is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness. </member> + <member name="face_index" type="int" setter="set_face_index" getter="get_face_index" default="0"> + Active face index in the TrueType / OpenType collection file. + </member> <member name="fixed_size" type="int" setter="set_fixed_size" getter="get_fixed_size" default="0"> Font size, used only for the bitmap fonts. </member> diff --git a/doc/classes/GradientTexture1D.xml b/doc/classes/GradientTexture1D.xml index a124753a9f..3254754ac1 100644 --- a/doc/classes/GradientTexture1D.xml +++ b/doc/classes/GradientTexture1D.xml @@ -4,7 +4,7 @@ Gradient-filled texture. </brief_description> <description> - GradientTexture1D uses a [Gradient] to fill the texture data. The gradient will be filled from left to right using colors obtained from the gradient. This means the texture does not necessarily represent an exact copy of the gradient, but instead an interpolation of samples obtained from the gradient at fixed steps (see [member width]). + GradientTexture1D uses a [Gradient] to fill the texture data. The gradient will be filled from left to right using colors obtained from the gradient. This means the texture does not necessarily represent an exact copy of the gradient, but instead an interpolation of samples obtained from the gradient at fixed steps (see [member width]). See also [GradientTexture2D], [CurveTexture] and [CurveXYZTexture]. </description> <tutorials> </tutorials> diff --git a/doc/classes/GradientTexture2D.xml b/doc/classes/GradientTexture2D.xml index 4362578932..7561f1b947 100644 --- a/doc/classes/GradientTexture2D.xml +++ b/doc/classes/GradientTexture2D.xml @@ -4,7 +4,7 @@ Gradient-filled 2D texture. </brief_description> <description> - The texture uses a [Gradient] to fill the texture data in 2D space. The gradient is filled according to the specified [member fill] and [member repeat] types using colors obtained from the gradient. The texture does not necessarily represent an exact copy of the gradient, but instead an interpolation of samples obtained from the gradient at fixed steps (see [member width] and [member height]). + The texture uses a [Gradient] to fill the texture data in 2D space. The gradient is filled according to the specified [member fill] and [member repeat] types using colors obtained from the gradient. The texture does not necessarily represent an exact copy of the gradient, but instead an interpolation of samples obtained from the gradient at fixed steps (see [member width] and [member height]). See also [GradientTexture1D], [CurveTexture] and [CurveXYZTexture]. </description> <tutorials> </tutorials> diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 1f3d5596aa..f4d453700c 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -412,9 +412,9 @@ </method> <method name="left" qualifiers="const"> <return type="String" /> - <argument index="0" name="position" type="int" /> + <argument index="0" name="length" type="int" /> <description> - Returns a number of characters from the left of the string. If negative [code]position[/code] is used, the characters are counted downwards from [String]'s length. + Returns a number of characters from the left of the string. If negative [code]length[/code] is used, the characters are counted downwards from [String]'s length. Examples: [codeblock] print("sample text".left(3)) #prints "sam" @@ -599,9 +599,9 @@ </method> <method name="right" qualifiers="const"> <return type="String" /> - <argument index="0" name="position" type="int" /> + <argument index="0" name="length" type="int" /> <description> - Returns a number of characters from the right of the string. If negative [code]position[/code] is used, the characters are counted downwards from [String]'s length. + Returns a number of characters from the right of the string. If negative [code]length[/code] is used, the characters are counted downwards from [String]'s length. Examples: [codeblock] print("sample text".right(3)) #prints "ext" diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index 2f57b76374..19be38b323 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -121,6 +121,20 @@ Returns font embolden strength. </description> </method> + <method name="font_get_face_count" qualifiers="const"> + <return type="int" /> + <argument index="0" name="font_rid" type="RID" /> + <description> + Returns number of faces in the TrueType / OpenType collection. + </description> + </method> + <method name="font_get_face_index" qualifiers="const"> + <return type="int" /> + <argument index="0" name="font_rid" type="RID" /> + <description> + Recturns an active face index in the TrueType / OpenType collection. + </description> + </method> <method name="font_get_fixed_size" qualifiers="const"> <return type="int" /> <argument index="0" name="font_rid" type="RID" /> @@ -593,6 +607,14 @@ Sets font embolden strength. If [code]strength[/code] is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness. </description> </method> + <method name="font_set_face_index"> + <return type="void" /> + <argument index="0" name="font_rid" type="RID" /> + <argument index="1" name="face_index" type="int" /> + <description> + Sets an active face index in the TrueType / OpenType collection. + </description> + </method> <method name="font_set_fixed_size"> <return type="void" /> <argument index="0" name="font_rid" type="RID" /> diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml index 434d6f909c..b3be858ca1 100644 --- a/doc/classes/TextServerExtension.xml +++ b/doc/classes/TextServerExtension.xml @@ -114,6 +114,20 @@ Returns font embolden strength. </description> </method> + <method name="font_get_face_count" qualifiers="virtual const"> + <return type="int" /> + <argument index="0" name="font_rid" type="RID" /> + <description> + Returns number of faces in the TrueType / OpenType collection. + </description> + </method> + <method name="font_get_face_index" qualifiers="virtual const"> + <return type="int" /> + <argument index="0" name="font_rid" type="RID" /> + <description> + Returns an active face index in the TrueType / OpenType collection. + </description> + </method> <method name="font_get_fixed_size" qualifiers="virtual const"> <return type="int" /> <argument index="0" name="font_rid" type="RID" /> @@ -590,6 +604,14 @@ Sets font embolden strength. If [code]strength[/code] is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness. </description> </method> + <method name="font_set_face_index" qualifiers="virtual"> + <return type="void" /> + <argument index="0" name="font_rid" type="RID" /> + <argument index="1" name="face_index" type="int" /> + <description> + Sets an active face index in the TrueType / OpenType collection. + </description> + </method> <method name="font_set_fixed_size" qualifiers="virtual"> <return type="void" /> <argument index="0" name="font_rid" type="RID" /> diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp index bc28b11a71..e13af59d69 100644 --- a/editor/debugger/editor_debugger_node.cpp +++ b/editor/debugger/editor_debugger_node.cpp @@ -103,6 +103,7 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() { node->connect("remote_object_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_updated), varray(id)); node->connect("remote_object_property_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_property_updated), varray(id)); node->connect("remote_object_requested", callable_mp(this, &EditorDebuggerNode::_remote_object_requested), varray(id)); + node->connect("errors_cleared", callable_mp(this, &EditorDebuggerNode::_update_errors)); if (tabs->get_tab_count() > 0) { get_debugger(0)->clear_style(); @@ -267,40 +268,7 @@ void EditorDebuggerNode::_notification(int p_what) { } server->poll(); - // Errors and warnings - int error_count = 0; - int warning_count = 0; - _for_all(tabs, [&](ScriptEditorDebugger *dbg) { - error_count += dbg->get_error_count(); - warning_count += dbg->get_warning_count(); - }); - - if (error_count != last_error_count || warning_count != last_warning_count) { - _for_all(tabs, [&](ScriptEditorDebugger *dbg) { - dbg->update_tabs(); - }); - - if (error_count == 0 && warning_count == 0) { - debugger_button->set_text(TTR("Debugger")); - debugger_button->remove_theme_color_override("font_color"); - debugger_button->set_icon(Ref<Texture2D>()); - } else { - debugger_button->set_text(TTR("Debugger") + " (" + itos(error_count + warning_count) + ")"); - if (error_count >= 1 && warning_count >= 1) { - debugger_button->set_icon(get_theme_icon(SNAME("ErrorWarning"), SNAME("EditorIcons"))); - // Use error color to represent the highest level of severity reported. - debugger_button->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor"))); - } else if (error_count >= 1) { - debugger_button->set_icon(get_theme_icon(SNAME("Error"), SNAME("EditorIcons"))); - debugger_button->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor"))); - } else { - debugger_button->set_icon(get_theme_icon(SNAME("Warning"), SNAME("EditorIcons"))); - debugger_button->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor"))); - } - } - last_error_count = error_count; - last_warning_count = warning_count; - } + _update_errors(); // Remote scene tree update remote_scene_tree_timeout -= get_process_delta_time(); @@ -361,6 +329,42 @@ void EditorDebuggerNode::_notification(int p_what) { } } +void EditorDebuggerNode::_update_errors() { + int error_count = 0; + int warning_count = 0; + _for_all(tabs, [&](ScriptEditorDebugger *dbg) { + error_count += dbg->get_error_count(); + warning_count += dbg->get_warning_count(); + }); + + if (error_count != last_error_count || warning_count != last_warning_count) { + _for_all(tabs, [&](ScriptEditorDebugger *dbg) { + dbg->update_tabs(); + }); + + if (error_count == 0 && warning_count == 0) { + debugger_button->set_text(TTR("Debugger")); + debugger_button->remove_theme_color_override("font_color"); + debugger_button->set_icon(Ref<Texture2D>()); + } else { + debugger_button->set_text(TTR("Debugger") + " (" + itos(error_count + warning_count) + ")"); + if (error_count >= 1 && warning_count >= 1) { + debugger_button->set_icon(get_theme_icon(SNAME("ErrorWarning"), SNAME("EditorIcons"))); + // Use error color to represent the highest level of severity reported. + debugger_button->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor"))); + } else if (error_count >= 1) { + debugger_button->set_icon(get_theme_icon(SNAME("Error"), SNAME("EditorIcons"))); + debugger_button->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor"))); + } else { + debugger_button->set_icon(get_theme_icon(SNAME("Warning"), SNAME("EditorIcons"))); + debugger_button->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor"))); + } + } + last_error_count = error_count; + last_warning_count = warning_count; + } +} + void EditorDebuggerNode::_debugger_stopped(int p_id) { ScriptEditorDebugger *dbg = get_debugger(p_id); ERR_FAIL_COND(!dbg); diff --git a/editor/debugger/editor_debugger_node.h b/editor/debugger/editor_debugger_node.h index 87457fc09a..8dc53690eb 100644 --- a/editor/debugger/editor_debugger_node.h +++ b/editor/debugger/editor_debugger_node.h @@ -116,6 +116,7 @@ private: ScriptEditorDebugger *_add_debugger(); EditorDebuggerRemoteObject *get_inspected_remote_object(); + void _update_errors(); friend class DebuggerEditorPlugin; friend class DebugAdapterParser; diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index 9184846408..05409dbeeb 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -1465,6 +1465,7 @@ void ScriptEditorDebugger::_clear_errors_list() { error_tree->clear(); error_count = 0; warning_count = 0; + emit_signal(SNAME("errors_cleared")); update_tabs(); expand_all_button->set_disabled(true); @@ -1626,6 +1627,7 @@ void ScriptEditorDebugger::_bind_methods() { ADD_SIGNAL(MethodInfo("debug_data", PropertyInfo(Variant::STRING, "msg"), PropertyInfo(Variant::ARRAY, "data"))); ADD_SIGNAL(MethodInfo("set_breakpoint", PropertyInfo("script"), PropertyInfo(Variant::INT, "line"), PropertyInfo(Variant::BOOL, "enabled"))); ADD_SIGNAL(MethodInfo("clear_breakpoints")); + ADD_SIGNAL(MethodInfo("errors_cleared")); } void ScriptEditorDebugger::add_debugger_plugin(const Ref<Script> &p_script) { diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp index b361dcd036..5e203a3e39 100644 --- a/editor/import/dynamic_font_import_settings.cpp +++ b/editor/import/dynamic_font_import_settings.cpp @@ -454,7 +454,11 @@ 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 == "antialiased") { + 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")); } @@ -945,6 +949,7 @@ void DynamicFontImportSettings::_notification(int p_what) { void DynamicFontImportSettings::_re_import() { HashMap<StringName, Variant> main_settings; + main_settings["face_index"] = import_settings_data->get("face_index"); main_settings["antialiased"] = import_settings_data->get("antialiased"); main_settings["generate_mipmaps"] = import_settings_data->get("generate_mipmaps"); main_settings["multichannel_signed_distance_field"] = import_settings_data->get("multichannel_signed_distance_field"); @@ -1299,6 +1304,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { 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")); @@ -1360,6 +1366,7 @@ 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::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)); diff --git a/editor/import/resource_importer_dynamic_font.cpp b/editor/import/resource_importer_dynamic_font.cpp index 04f6a0b7af..a92b0fe280 100644 --- a/editor/import/resource_importer_dynamic_font.cpp +++ b/editor/import/resource_importer_dynamic_font.cpp @@ -50,7 +50,9 @@ void ResourceImporterDynamicFont::get_recognized_extensions(List<String> *p_exte if (p_extensions) { #ifdef MODULE_FREETYPE_ENABLED p_extensions->push_back("ttf"); + p_extensions->push_back("ttc"); p_extensions->push_back("otf"); + p_extensions->push_back("otc"); p_extensions->push_back("woff"); p_extensions->push_back("woff2"); p_extensions->push_back("pfb"); @@ -101,6 +103,8 @@ 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::BOOL, "antialiased"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_mipmaps"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), (msdf) ? true : false)); @@ -179,6 +183,8 @@ 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"]; @@ -200,6 +206,7 @@ Error ResourceImporterDynamicFont::import(const String &p_source_file, const Str Ref<FontData> 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); diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 80230bc316..f2975b1d7a 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -658,6 +658,44 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap<R } } } + } else if (_teststr(name, "vehicle")) { + if (isroot) { + return p_node; + } + + Node *owner = p_node->get_owner(); + Node3D *s = Object::cast_to<Node3D>(p_node); + VehicleBody3D *bv = memnew(VehicleBody3D); + String n = _fixstr(p_node->get_name(), "vehicle"); + bv->set_name(n); + p_node->replace_by(bv); + p_node->set_name(n); + bv->add_child(p_node); + bv->set_owner(owner); + p_node->set_owner(owner); + bv->set_transform(s->get_transform()); + s->set_transform(Transform3D()); + + p_node = bv; + } else if (_teststr(name, "wheel")) { + if (isroot) { + return p_node; + } + + Node *owner = p_node->get_owner(); + Node3D *s = Object::cast_to<Node3D>(p_node); + VehicleWheel3D *bv = memnew(VehicleWheel3D); + String n = _fixstr(p_node->get_name(), "wheel"); + bv->set_name(n); + p_node->replace_by(bv); + p_node->set_name(n); + bv->add_child(p_node); + bv->set_owner(owner); + p_node->set_owner(owner); + bv->set_transform(s->get_transform()); + s->set_transform(Transform3D()); + + p_node = bv; } else if (Object::cast_to<ImporterMeshInstance3D>(p_node)) { //last attempt, maybe collision inside the mesh data diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs index ef135da51a..2febf37f05 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs @@ -2,17 +2,27 @@ using System; namespace Godot { + /// <summary> + /// An attribute that determines if an assembly has scripts. If so, what types of scripts the assembly has. + /// </summary> [AttributeUsage(AttributeTargets.Assembly)] public class AssemblyHasScriptsAttribute : Attribute { private readonly bool requiresLookup; private readonly System.Type[] scriptTypes; + /// <summary> + /// Constructs a new AssemblyHasScriptsAttribute instance. + /// </summary> public AssemblyHasScriptsAttribute() { requiresLookup = true; } + /// <summary> + /// Constructs a new AssemblyHasScriptsAttribute instance. + /// </summary> + /// <param name="scriptTypes">The specified type(s) of scripts.</param> public AssemblyHasScriptsAttribute(System.Type[] scriptTypes) { requiresLookup = false; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs index e93bc89811..0b00878e8c 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs @@ -2,6 +2,9 @@ using System; namespace Godot { + /// <summary> + /// An attribute that disables Godot Generators. + /// </summary> [AttributeUsage(AttributeTargets.Class)] public class DisableGodotGeneratorsAttribute : Attribute { } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs index 6adf044886..46eb128d37 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs @@ -2,12 +2,20 @@ using System; namespace Godot { + /// <summary> + /// An attribute used to export objects. + /// </summary> [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] public class ExportAttribute : Attribute { private PropertyHint hint; private string hintString; + /// <summary> + /// Constructs a new ExportAttribute Instance. + /// </summary> + /// <param name="hint">A hint to the exported object.</param> + /// <param name="hintString">A string representing the exported object.</param> public ExportAttribute(PropertyHint hint = PropertyHint.None, string hintString = "") { this.hint = hint; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs index 55848769d5..8d4ff0fdb7 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs @@ -2,6 +2,9 @@ using System; namespace Godot { + /// <summary> + /// An attribute for a method. + /// </summary> [AttributeUsage(AttributeTargets.Method)] internal class GodotMethodAttribute : Attribute { @@ -9,6 +12,10 @@ namespace Godot public string MethodName { get { return methodName; } } + /// <summary> + /// Constructs a new GodotMethodAttribute instance. + /// </summary> + /// <param name="methodName">The name of the method.</param> public GodotMethodAttribute(string methodName) { this.methodName = methodName; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs index b8b9bc660c..f0d37c344d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs @@ -2,9 +2,15 @@ using System; namespace Godot { + /// <summary> + /// Constructs a new AnyPeerAttribute instance. Members with the AnyPeerAttribute are given authority over their own player. + /// </summary> [AttributeUsage(AttributeTargets.Method)] public class AnyPeerAttribute : Attribute { } + /// <summary> + /// Constructs a new AuthorityAttribute instance. Members with the AuthorityAttribute are given authority over the game. + /// </summary> [AttributeUsage(AttributeTargets.Method)] public class AuthorityAttribute : Attribute { } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs index 12eb1035c3..3ebb6612de 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs @@ -2,11 +2,18 @@ using System; namespace Godot { + /// <summary> + /// An attribute that contains the path to the object's script. + /// </summary> [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class ScriptPathAttribute : Attribute { private string path; + /// <summary> + /// Constructs a new ScriptPathAttribute instance. + /// </summary> + /// <param name="path">The file path to the script</param> public ScriptPathAttribute(string path) { this.path = path; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs index 072e0f20ff..6475237002 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs @@ -4,9 +4,16 @@ namespace Godot { public static class Dispatcher { + /// <summary> + /// Implements an external instance of GodotTaskScheduler. + /// </summary> + /// <returns>A GodotTaskScheduler instance.</returns> [MethodImpl(MethodImplOptions.InternalCall)] private static extern GodotTaskScheduler godot_icall_DefaultGodotTaskScheduler(); + /// <summary> + /// Initializes the synchronization context as the context of the GodotTaskScheduler. + /// </summary> public static GodotSynchronizationContext SynchronizationContext => godot_icall_DefaultGodotTaskScheduler().Context; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs index c01c926e82..1b599beab5 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs @@ -14,6 +14,9 @@ namespace Godot _queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state)); } + /// <summary> + /// Calls the Key method on each workItem object in the _queue to activate their callbacks. + /// </summary> public void ExecutePendingContinuations() { while (_queue.TryTake(out var workItem)) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs index 8eaeea50dc..408bed71b2 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs @@ -6,11 +6,25 @@ using System.Threading.Tasks; namespace Godot { + /// <summary> + /// GodotTaskScheduler contains a linked list of tasks to perform as a queue. Methods + /// within the class are used to control the queue and perform the contained tasks. + /// </summary> public class GodotTaskScheduler : TaskScheduler { + /// <summary> + /// The current synchronization context. + /// </summary> internal GodotSynchronizationContext Context { get; } + + /// <summary> + /// The queue of tasks for the task scheduler. + /// </summary> private readonly LinkedList<Task> _tasks = new LinkedList<Task>(); + /// <summary> + /// Constructs a new GodotTaskScheduler instance. + /// </summary> public GodotTaskScheduler() { Context = new GodotSynchronizationContext(); @@ -53,12 +67,19 @@ namespace Godot } } + /// <summary> + /// Executes all queued tasks and pending tasks from the current context. + /// </summary> public void Activate() { ExecuteQueuedTasks(); Context.ExecutePendingContinuations(); } + /// <summary> + /// Loops through and attempts to execute each task in _tasks. + /// </summary> + /// <exception cref="InvalidOperationException"></exception> private void ExecuteQueuedTasks() { while (true) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs index 0397957d00..e747e03c1e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs @@ -1,10 +1,17 @@ namespace Godot { + /// <summary> + /// An interface that requires a GetAwaiter() method to get a reference to the Awaiter. + /// </summary> public interface IAwaitable { IAwaiter GetAwaiter(); } + /// <summary> + /// A templated interface that requires a GetAwaiter() method to get a reference to the Awaiter. + /// </summary> + /// <typeparam name="TResult">A reference to the result to be passed out.</typeparam> public interface IAwaitable<out TResult> { IAwaiter<TResult> GetAwaiter(); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs index d3be9d781c..dec225eb29 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs @@ -2,6 +2,9 @@ using System.Runtime.CompilerServices; namespace Godot { + /// <summary> + /// An interface that requires a boolean for completion status and a method that gets the result of completion. + /// </summary> public interface IAwaiter : INotifyCompletion { bool IsCompleted { get; } @@ -9,6 +12,10 @@ namespace Godot void GetResult(); } + /// <summary> + /// A templated interface that requires a boolean for completion status and a method that gets the result of completion and returns it. + /// </summary> + /// <typeparam name="TResult">A reference to the result to be passed out.</typeparam> public interface IAwaiter<out TResult> : INotifyCompletion { bool IsCompleted { get; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs index c3fa2f3e82..90b4d1b8d3 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs @@ -1,5 +1,8 @@ namespace Godot { + /// <summary> + /// An interface that requires methods for before and after serialization. + /// </summary> public interface ISerializationListener { void OnBeforeSerialize(); diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index d18ed97def..f7d6ce87dc 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -1288,7 +1288,16 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced fargs.memory_size = p_font_data->data_size; fargs.flags = FT_OPEN_MEMORY; fargs.stream = &fd->stream; - error = FT_Open_Face(ft_library, &fargs, 0, &fd->face); + + int max_index = 0; + FT_Face tmp_face; + error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face); + if (error == 0) { + max_index = tmp_face->num_faces - 1; + } + FT_Done_Face(tmp_face); + + error = FT_Open_Face(ft_library, &fargs, CLAMP(p_font_data->face_index, 0, max_index), &fd->face); if (error) { FT_Done_Face(fd->face); fd->face = nullptr; @@ -1720,6 +1729,69 @@ void TextServerAdvanced::font_set_data_ptr(const RID &p_font_rid, const uint8_t fd->data_size = p_data_size; } +void TextServerAdvanced::font_set_face_index(const RID &p_font_rid, int64_t p_face_index) { + ERR_FAIL_COND(p_face_index < 0); + ERR_FAIL_COND(p_face_index >= 0x7FFF); + + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + if (fd->face_index != p_face_index) { + fd->face_index = p_face_index; + _font_clear_cache(fd); + } +} + +int64_t TextServerAdvanced::font_get_face_index(const RID &p_font_rid) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, 0); + + MutexLock lock(fd->mutex); + return fd->face_index; +} + +int64_t TextServerAdvanced::font_get_face_count(const RID &p_font_rid) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, 0); + + MutexLock lock(fd->mutex); + int face_count = 0; + + if (fd->data_ptr && (fd->data_size > 0)) { + // Init dynamic font. +#ifdef MODULE_FREETYPE_ENABLED + int error = 0; + if (!ft_library) { + error = FT_Init_FreeType(&ft_library); + ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'."); + } + + FT_StreamRec stream; + memset(&stream, 0, sizeof(FT_StreamRec)); + stream.base = (unsigned char *)fd->data_ptr; + stream.size = fd->data_size; + stream.pos = 0; + + FT_Open_Args fargs; + memset(&fargs, 0, sizeof(FT_Open_Args)); + fargs.memory_base = (unsigned char *)fd->data_ptr; + fargs.memory_size = fd->data_size; + fargs.flags = FT_OPEN_MEMORY; + fargs.stream = &stream; + + FT_Face tmp_face; + error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face); + if (error == 0) { + face_count = tmp_face->num_faces; + } + FT_Done_Face(tmp_face); +#endif + } + + return face_count; +} + void TextServerAdvanced::font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -4780,6 +4852,9 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star RID f = p_fonts[p_fb_index]; FontDataAdvanced *fd = font_owner.get_or_null(f); + ERR_FAIL_COND(!fd); + MutexLock lock(fd->mutex); + Vector2i fss = _get_size(fd, fs); hb_font_t *hb_font = _font_get_hb_handle(f, fs); double scale = font_get_scale(f, fs); diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 62f94472b5..c72454d0bb 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -247,6 +247,7 @@ class TextServerAdvanced : public TextServerExtension { PackedByteArray data; const uint8_t *data_ptr; size_t data_size; + int face_index = 0; mutable ThreadWorkPool work_pool; ~FontDataAdvanced() { @@ -473,6 +474,11 @@ public: virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) override; virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) override; + virtual void font_set_face_index(const RID &p_font_rid, int64_t p_index) override; + virtual int64_t font_get_face_index(const RID &p_font_rid) const override; + + virtual int64_t font_get_face_count(const RID &p_font_rid) const override; + virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) override; virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const override; diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 498b58175e..1863baf769 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -733,7 +733,16 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback fargs.memory_size = p_font_data->data_size; fargs.flags = FT_OPEN_MEMORY; fargs.stream = &fd->stream; - error = FT_Open_Face(ft_library, &fargs, 0, &fd->face); + + int max_index = 0; + FT_Face tmp_face; + error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face); + if (error == 0) { + max_index = tmp_face->num_faces - 1; + } + FT_Done_Face(tmp_face); + + error = FT_Open_Face(ft_library, &fargs, CLAMP(p_font_data->face_index, 0, max_index), &fd->face); if (error) { FT_Done_Face(fd->face); fd->face = nullptr; @@ -892,6 +901,69 @@ void TextServerFallback::font_set_style(const RID &p_font_rid, int64_t /*FontSty fd->style_flags = p_style; } +void TextServerFallback::font_set_face_index(const RID &p_font_rid, int64_t p_face_index) { + ERR_FAIL_COND(p_face_index < 0); + ERR_FAIL_COND(p_face_index >= 0x7FFF); + + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + if (fd->face_index != p_face_index) { + fd->face_index = p_face_index; + _font_clear_cache(fd); + } +} + +int64_t TextServerFallback::font_get_face_index(const RID &p_font_rid) const { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, 0); + + MutexLock lock(fd->mutex); + return fd->face_index; +} + +int64_t TextServerFallback::font_get_face_count(const RID &p_font_rid) const { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, 0); + + MutexLock lock(fd->mutex); + int face_count = 0; + + if (fd->data_ptr && (fd->data_size > 0)) { + // Init dynamic font. +#ifdef MODULE_FREETYPE_ENABLED + int error = 0; + if (!ft_library) { + error = FT_Init_FreeType(&ft_library); + ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'."); + } + + FT_StreamRec stream; + memset(&stream, 0, sizeof(FT_StreamRec)); + stream.base = (unsigned char *)fd->data_ptr; + stream.size = fd->data_size; + stream.pos = 0; + + FT_Open_Args fargs; + memset(&fargs, 0, sizeof(FT_Open_Args)); + fargs.memory_base = (unsigned char *)fd->data_ptr; + fargs.memory_size = fd->data_size; + fargs.flags = FT_OPEN_MEMORY; + fargs.stream = &stream; + + FT_Face tmp_face; + error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face); + if (error == 0) { + face_count = tmp_face->num_faces; + } + FT_Done_Face(tmp_face); +#endif + } + + return face_count; +} + int64_t /*FontStyle*/ TextServerFallback::font_get_style(const RID &p_font_rid) const { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index f3d516edea..c085b58898 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -209,6 +209,7 @@ class TextServerFallback : public TextServerExtension { PackedByteArray data; const uint8_t *data_ptr; size_t data_size; + int face_index = 0; mutable ThreadWorkPool work_pool; @@ -364,6 +365,11 @@ public: virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) override; virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) override; + virtual void font_set_face_index(const RID &p_font_rid, int64_t p_index) override; + virtual int64_t font_get_face_index(const RID &p_font_rid) const override; + + virtual int64_t font_get_face_count(const RID &p_font_rid) const override; + virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) override; virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const override; diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index c54897035a..0d21d82896 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -35,7 +35,7 @@ Size2 Button::get_minimum_size() const { Size2 minsize = text_buf->get_size(); - if (clip_text) { + if (clip_text || overrun_behavior != TextParagraph::OVERRUN_NO_TRIMMING) { minsize.width = 0; } @@ -292,9 +292,9 @@ void Button::_notification(int p_what) { icon_ofs.x = 0.0; } int text_clip = size.width - style->get_minimum_size().width - icon_ofs.width; - text_buf->set_width(clip_text ? text_clip : -1); + text_buf->set_width((clip_text || overrun_behavior != TextParagraph::OVERRUN_NO_TRIMMING) ? text_clip : -1); - int text_width = MAX(1, clip_text ? MIN(text_clip, text_buf->get_size().x) : text_buf->get_size().x); + int text_width = MAX(1, (clip_text || overrun_behavior != TextParagraph::OVERRUN_NO_TRIMMING) ? MIN(text_clip, text_buf->get_size().x) : text_buf->get_size().x); if (_internal_margin[SIDE_LEFT] > 0) { text_clip -= _internal_margin[SIDE_LEFT] + get_theme_constant(SNAME("h_separation")); @@ -364,6 +364,21 @@ void Button::_shape() { text_buf->set_direction((TextServer::Direction)text_direction); } text_buf->add_string(xl_text, font, font_size, opentype_features, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale()); + text_buf->set_text_overrun_behavior(overrun_behavior); +} + +void Button::set_text_overrun_behavior(TextParagraph::OverrunBehavior p_behavior) { + if (overrun_behavior != p_behavior) { + overrun_behavior = p_behavior; + _shape(); + + update(); + update_minimum_size(); + } +} + +TextParagraph::OverrunBehavior Button::get_text_overrun_behavior() const { + return overrun_behavior; } void Button::set_text(const String &p_text) { @@ -550,6 +565,8 @@ void Button::_get_property_list(List<PropertyInfo> *p_list) const { void Button::_bind_methods() { ClassDB::bind_method(D_METHOD("set_text", "text"), &Button::set_text); ClassDB::bind_method(D_METHOD("get_text"), &Button::get_text); + ClassDB::bind_method(D_METHOD("set_text_overrun_behavior", "overrun_behavior"), &Button::set_text_overrun_behavior); + ClassDB::bind_method(D_METHOD("get_text_overrun_behavior"), &Button::get_text_overrun_behavior); ClassDB::bind_method(D_METHOD("set_text_direction", "direction"), &Button::set_text_direction); ClassDB::bind_method(D_METHOD("get_text_direction"), &Button::get_text_direction); ClassDB::bind_method(D_METHOD("set_opentype_feature", "tag", "value"), &Button::set_opentype_feature); @@ -577,6 +594,7 @@ void Button::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "get_clip_text"); ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_text_alignment", "get_text_alignment"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior", PROPERTY_HINT_ENUM, "Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis"), "set_text_overrun_behavior", "get_text_overrun_behavior"); ADD_PROPERTY(PropertyInfo(Variant::INT, "icon_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_icon_alignment", "get_icon_alignment"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_icon"), "set_expand_icon", "is_expand_icon"); } diff --git a/scene/gui/button.h b/scene/gui/button.h index 1abf86c986..175785a35c 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -46,6 +46,7 @@ private: Dictionary opentype_features; String language; TextDirection text_direction = TEXT_DIRECTION_AUTO; + TextParagraph::OverrunBehavior overrun_behavior = TextParagraph::OVERRUN_NO_TRIMMING; Ref<Texture2D> icon; bool expand_icon = false; @@ -71,6 +72,9 @@ public: void set_text(const String &p_text); String get_text() const; + void set_text_overrun_behavior(TextParagraph::OverrunBehavior p_behavior); + TextParagraph::OverrunBehavior get_text_overrun_behavior() const; + void set_text_direction(TextDirection p_text_direction); TextDirection get_text_direction() const; diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index 6532fc5934..c4396f636a 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -108,9 +108,7 @@ void Popup::_close_pressed() { _deinitialize_visible_parents(); - // Hide after returning to process events, but only if we don't - // get popped up in the interim. - call_deferred(SNAME("_popup_conditional_hide")); + call_deferred(SNAME("hide")); } void Popup::_post_popup() { @@ -118,15 +116,8 @@ void Popup::_post_popup() { popped_up = true; } -void Popup::_popup_conditional_hide() { - if (!popped_up) { - hide(); - } -} - void Popup::_bind_methods() { ADD_SIGNAL(MethodInfo("popup_hide")); - ClassDB::bind_method(D_METHOD("_popup_conditional_hide"), &Popup::_popup_conditional_hide); } Rect2i Popup::_popup_adjust_rect() const { diff --git a/scene/gui/popup.h b/scene/gui/popup.h index 27f46d4a97..b53c8be50f 100644 --- a/scene/gui/popup.h +++ b/scene/gui/popup.h @@ -48,8 +48,6 @@ class Popup : public Window { void _initialize_visible_parents(); void _deinitialize_visible_parents(); - void _parent_focused(); - protected: void _close_pressed(); virtual Rect2i _popup_adjust_rect() const override; @@ -57,7 +55,7 @@ protected: void _notification(int p_what); static void _bind_methods(); - void _popup_conditional_hide(); + virtual void _parent_focused(); virtual void _post_popup() override; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 080e0c371c..c9eecf54dd 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -243,6 +243,29 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) { } } +void PopupMenu::_parent_focused() { + if (is_embedded()) { + Point2 mouse_pos_adjusted; + Window *window_parent = Object::cast_to<Window>(get_parent()->get_viewport()); + while (window_parent) { + if (!window_parent->is_embedded()) { + mouse_pos_adjusted += window_parent->get_position(); + break; + } + + window_parent = Object::cast_to<Window>(window_parent->get_parent()->get_viewport()); + } + + Rect2 safe_area = DisplayServer::get_singleton()->window_get_popup_safe_rect(get_window_id()); + Point2 pos = DisplayServer::get_singleton()->mouse_get_position() - mouse_pos_adjusted; + if (safe_area == Rect2i() || !safe_area.has_point(pos)) { + Popup::_parent_focused(); + } else { + grab_focus(); + } + } +} + void PopupMenu::_submenu_timeout() { if (mouse_over == submenu_over) { _activate_submenu(mouse_over); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index 12587b7e73..53bc5a8c22 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -148,6 +148,8 @@ public: // this value should be updated to reflect the new size. static const int ITEM_PROPERTY_SIZE = 10; + virtual void _parent_focused() override; + void add_item(const String &p_label, int p_id = -1, Key p_accel = Key::NONE); void add_icon_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id = -1, Key p_accel = Key::NONE); void add_check_item(const String &p_label, int p_id = -1, Key p_accel = Key::NONE); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index bfa439d2b1..4a0edd85f5 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1243,8 +1243,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o // Draw glyphs. for (int j = 0; j < glyphs[i].repeat; j++) { + bool skip = (trim_chars && l.char_offset + glyphs[i].end > visible_characters) || (trim_glyphs_ltr && (r_processed_glyphs >= visible_glyphs)) || (trim_glyphs_rtl && (r_processed_glyphs < total_glyphs - visible_glyphs)); if (visible) { - bool skip = (trim_chars && l.char_offset + glyphs[i].end > visible_characters) || (trim_glyphs_ltr && (r_processed_glyphs >= visible_glyphs)) || (trim_glyphs_rtl && (r_processed_glyphs < total_glyphs - visible_glyphs)); if (!skip) { if (frid != RID()) { TS->font_draw_glyph(frid, ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, selected ? selection_fg : font_color); @@ -1254,6 +1254,27 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } r_processed_glyphs++; } + if (skip) { + // End underline/overline/strikethrough is previous glyph is skipped. + if (ul_started) { + ul_started = false; + float y_off = TS->shaped_text_get_underline_position(rid); + float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale(); + draw_line(ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), ul_color, underline_width); + } + if (dot_ul_started) { + dot_ul_started = false; + float y_off = TS->shaped_text_get_underline_position(rid); + float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale(); + draw_dashed_line(dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), dot_ul_color, underline_width, underline_width * 2); + } + if (st_started) { + st_started = false; + float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2; + float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale(); + draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), st_color, underline_width); + } + } off.x += glyphs[i].advance; } } diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 927ba875d9..1d697a2176 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -165,14 +165,26 @@ void Window::set_flag(Flags p_flag, bool p_enabled) { embedder->_sub_window_update(this); } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { +#ifdef TOOLS_ENABLED + if ((p_flag != FLAG_POPUP) || !(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_ancestor_of(this))) { + DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id); + } +#else DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id); +#endif } } bool Window::get_flag(Flags p_flag) const { ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false); if (window_id != DisplayServer::INVALID_WINDOW_ID) { +#ifdef TOOLS_ENABLED + if ((p_flag != FLAG_POPUP) || !(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_ancestor_of(this))) { + flags[p_flag] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(p_flag), window_id); + } +#else flags[p_flag] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(p_flag), window_id); +#endif } return flags[p_flag]; } @@ -255,7 +267,15 @@ void Window::_make_window() { #endif DisplayServer::get_singleton()->window_set_title(tr_title, window_id); DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id); +#ifdef TOOLS_ENABLED + if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_ancestor_of(this))) { + DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive); + } else { + DisplayServer::get_singleton()->window_set_exclusive(window_id, false); + } +#else DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive); +#endif _update_window_size(); @@ -441,6 +461,8 @@ void Window::set_visible(bool p_visible) { ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child."); transient_parent->exclusive_child = this; } +#else + transient_parent->exclusive_child = this; #endif } else { if (transient_parent->exclusive_child == this) { @@ -488,7 +510,13 @@ void Window::_make_transient() { window->transient_children.insert(this); if (is_inside_tree() && is_visible() && exclusive) { if (transient_parent->exclusive_child == nullptr) { +#ifdef TOOLS_ENABLED + if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_ancestor_of(this))) { + transient_parent->exclusive_child = this; + } +#else transient_parent->exclusive_child = this; +#endif } else if (transient_parent->exclusive_child != this) { ERR_PRINT("Making child transient exclusive, but parent has another exclusive child"); } @@ -531,13 +559,27 @@ void Window::set_exclusive(bool p_exclusive) { exclusive = p_exclusive; if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID) { +#ifdef TOOLS_ENABLED + if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_ancestor_of(this))) { + DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive); + } else { + DisplayServer::get_singleton()->window_set_exclusive(window_id, false); + } +#else DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive); +#endif } if (transient_parent) { if (p_exclusive && is_inside_tree() && is_visible()) { ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child."); +#ifdef TOOLS_ENABLED + if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_ancestor_of(this))) { + transient_parent->exclusive_child = this; + } +#else transient_parent->exclusive_child = this; +#endif } else { if (transient_parent->exclusive_child == this) { transient_parent->exclusive_child = nullptr; diff --git a/scene/resources/animation_library.cpp b/scene/resources/animation_library.cpp index 361bfd0cb3..5f725b2fbe 100644 --- a/scene/resources/animation_library.cpp +++ b/scene/resources/animation_library.cpp @@ -143,9 +143,9 @@ void AnimationLibrary::_bind_methods() { ClassDB::bind_method(D_METHOD("_get_data"), &AnimationLibrary::_get_data); ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "_set_data", "_get_data"); - ADD_SIGNAL(MethodInfo("animation_added", PropertyInfo(Variant::OBJECT, "name", PROPERTY_HINT_RESOURCE_TYPE, "Animation"))); - ADD_SIGNAL(MethodInfo("animation_removed", PropertyInfo(Variant::OBJECT, "name", PROPERTY_HINT_RESOURCE_TYPE, "Animation"))); - ADD_SIGNAL(MethodInfo("animation_renamed", PropertyInfo(Variant::OBJECT, "name", PROPERTY_HINT_RESOURCE_TYPE, "Animation"), PropertyInfo(Variant::OBJECT, "to_name", PROPERTY_HINT_RESOURCE_TYPE, "Animation"))); + ADD_SIGNAL(MethodInfo("animation_added", PropertyInfo(Variant::STRING_NAME, "name"))); + ADD_SIGNAL(MethodInfo("animation_removed", PropertyInfo(Variant::STRING_NAME, "name"))); + ADD_SIGNAL(MethodInfo("animation_renamed", PropertyInfo(Variant::STRING_NAME, "name"), PropertyInfo(Variant::STRING_NAME, "to_name"))); } AnimationLibrary::AnimationLibrary() { } diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 7aaeb424ac..8a353f4b49 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -54,6 +54,7 @@ _FORCE_INLINE_ void FontData::_ensure_rid(int p_cache_index) const { if (unlikely(!cache[p_cache_index].is_valid())) { cache.write[p_cache_index] = TS->create_font(); TS->font_set_data_ptr(cache[p_cache_index], data_ptr, data_size); + TS->font_set_face_index(cache[p_cache_index], face_index); TS->font_set_antialiased(cache[p_cache_index], antialiased); TS->font_set_generate_mipmaps(cache[p_cache_index], mipmaps); TS->font_set_multichannel_signed_distance_field(cache[p_cache_index], msdf); @@ -76,6 +77,11 @@ void FontData::_bind_methods() { ClassDB::bind_method(D_METHOD("set_data", "data"), &FontData::set_data); ClassDB::bind_method(D_METHOD("get_data"), &FontData::get_data); + ClassDB::bind_method(D_METHOD("set_face_index", "face_index"), &FontData::set_face_index); + ClassDB::bind_method(D_METHOD("get_face_index"), &FontData::get_face_index); + + ClassDB::bind_method(D_METHOD("get_face_count"), &FontData::get_face_count); + ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontData::set_antialiased); ClassDB::bind_method(D_METHOD("is_antialiased"), &FontData::is_antialiased); @@ -217,6 +223,7 @@ void FontData::_bind_methods() { ClassDB::bind_method(D_METHOD("get_supported_variation_list"), &FontData::get_supported_variation_list); ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_data", "get_data"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "face_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_face_index", "get_face_index"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_generate_mipmaps", "get_generate_mipmaps"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_antialiased", "is_antialiased"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_name", "get_font_name"); @@ -445,6 +452,7 @@ void FontData::reset_state() { data.clear(); data_ptr = nullptr; data_size = 0; + face_index = 0; cache.clear(); antialiased = true; @@ -1244,6 +1252,31 @@ void FontData::set_data(const PackedByteArray &p_data) { } } +void FontData::set_face_index(int64_t p_index) { + ERR_FAIL_COND(p_index < 0); + ERR_FAIL_COND(p_index >= 0x7FFF); + + if (face_index != p_index) { + face_index = p_index; + if (data_ptr != nullptr) { + for (int i = 0; i < cache.size(); i++) { + if (cache[i].is_valid()) { + TS->font_set_face_index(cache[i], face_index); + } + } + } + } +} + +int64_t FontData::get_face_index() const { + return face_index; +} + +int64_t FontData::get_face_count() const { + _ensure_rid(0); + return TS->font_get_face_count(cache[0]); +} + PackedByteArray FontData::get_data() const { if (unlikely((size_t)data.size() != data_size)) { PackedByteArray *data_w = const_cast<PackedByteArray *>(&data); diff --git a/scene/resources/font.h b/scene/resources/font.h index 96bfe3678b..950959e054 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -46,6 +46,7 @@ class FontData : public Resource { // Font source data. const uint8_t *data_ptr = nullptr; size_t data_size = 0; + int face_index = 0; PackedByteArray data; bool antialiased = true; @@ -91,6 +92,11 @@ public: virtual void set_data(const PackedByteArray &p_data); virtual PackedByteArray get_data() const; + virtual void set_face_index(int64_t p_index); + virtual int64_t get_face_index() const; + + virtual int64_t get_face_count() const; + // Common properties. virtual void set_font_name(const String &p_name); virtual String get_font_name() const; diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index 005cb68302..e9a558ac5f 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -55,6 +55,11 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(font_set_data, "font_rid", "data"); GDVIRTUAL_BIND(font_set_data_ptr, "font_rid", "data_ptr", "data_size"); + GDVIRTUAL_BIND(font_set_face_index, "font_rid", "face_index"); + GDVIRTUAL_BIND(font_get_face_index, "font_rid"); + + GDVIRTUAL_BIND(font_get_face_count, "font_rid"); + GDVIRTUAL_BIND(font_set_style, "font_rid", "style"); GDVIRTUAL_BIND(font_get_style, "font_rid"); @@ -413,6 +418,26 @@ void TextServerExtension::font_set_data_ptr(const RID &p_font_rid, const uint8_t GDVIRTUAL_CALL(font_set_data_ptr, p_font_rid, p_data_ptr, p_data_size); } +void TextServerExtension::font_set_face_index(const RID &p_font_rid, int64_t p_index) { + GDVIRTUAL_CALL(font_set_face_index, p_font_rid, p_index); +} + +int64_t TextServerExtension::font_get_face_index(const RID &p_font_rid) const { + int64_t ret; + if (GDVIRTUAL_CALL(font_get_face_index, p_font_rid, ret)) { + return ret; + } + return 0; +} + +int64_t TextServerExtension::font_get_face_count(const RID &p_font_rid) const { + int64_t ret; + if (GDVIRTUAL_CALL(font_get_face_count, p_font_rid, ret)) { + return ret; + } + return 0; +} + void TextServerExtension::font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) { GDVIRTUAL_CALL(font_set_style, p_font_rid, p_style); } diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index 7b7fc61ed7..9ca0939247 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -84,6 +84,14 @@ public: GDVIRTUAL2(font_set_data, RID, const PackedByteArray &); GDVIRTUAL3(font_set_data_ptr, RID, GDNativeConstPtr<const uint8_t>, int64_t); + virtual void font_set_face_index(const RID &p_font_rid, int64_t p_index) override; + virtual int64_t font_get_face_index(const RID &p_font_rid) const override; + GDVIRTUAL2(font_set_face_index, RID, int64_t); + GDVIRTUAL1RC(int64_t, font_get_face_index, RID); + + virtual int64_t font_get_face_count(const RID &p_font_rid) const override; + GDVIRTUAL1RC(int64_t, font_get_face_count, RID); + virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) override; virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const override; GDVIRTUAL2(font_set_style, RID, int64_t); diff --git a/servers/text_server.cpp b/servers/text_server.cpp index 20e62037e6..41d9c74d82 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -208,6 +208,11 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("font_set_data", "font_rid", "data"), &TextServer::font_set_data); + ClassDB::bind_method(D_METHOD("font_set_face_index", "font_rid", "face_index"), &TextServer::font_set_face_index); + ClassDB::bind_method(D_METHOD("font_get_face_index", "font_rid"), &TextServer::font_get_face_index); + + ClassDB::bind_method(D_METHOD("font_get_face_count", "font_rid"), &TextServer::font_get_face_count); + ClassDB::bind_method(D_METHOD("font_set_style", "font_rid", "style"), &TextServer::font_set_style); ClassDB::bind_method(D_METHOD("font_get_style", "font_rid"), &TextServer::font_get_style); diff --git a/servers/text_server.h b/servers/text_server.h index f96146a549..a67ad8fc9e 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -189,6 +189,11 @@ public: virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) = 0; virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) = 0; + virtual void font_set_face_index(const RID &p_font_rid, int64_t p_index) = 0; + virtual int64_t font_get_face_index(const RID &p_font_rid) const = 0; + + virtual int64_t font_get_face_count(const RID &p_font_rid) const = 0; + virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) = 0; virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const = 0; |