diff options
Diffstat (limited to 'modules')
23 files changed, 569 insertions, 119 deletions
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index 93533e1690..6b05c146e6 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -729,7 +729,7 @@ void CSGBrushOperation::MeshMerge::mark_inside_faces() { } } -void CSGBrushOperation::MeshMerge::add_face(const Vector3 p_points[], const Vector2 p_uvs[], bool p_smooth, bool p_invert, const Ref<Material> &p_material, bool p_from_b) { +void CSGBrushOperation::MeshMerge::add_face(const Vector3 p_points[3], const Vector2 p_uvs[3], bool p_smooth, bool p_invert, const Ref<Material> &p_material, bool p_from_b) { int indices[3]; for (int i = 0; i < 3; i++) { VertexKey vk; diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub index 4b2ea6faa5..8efcd72fb6 100644 --- a/modules/freetype/SCsub +++ b/modules/freetype/SCsub @@ -58,22 +58,23 @@ if env["builtin_freetype"]: ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - thirdparty_brotli_dir = "#thirdparty/brotli/" - thirdparty_brotli_sources = [ - "common/constants.c", - "common/context.c", - "common/dictionary.c", - "common/platform.c", - "common/shared_dictionary.c", - "common/transform.c", - "dec/bit_reader.c", - "dec/decode.c", - "dec/huffman.c", - "dec/state.c", - ] - thirdparty_sources += [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources] - env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"]) - env_freetype.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"]) + if env["brotli"]: + thirdparty_brotli_dir = "#thirdparty/brotli/" + thirdparty_brotli_sources = [ + "common/constants.c", + "common/context.c", + "common/dictionary.c", + "common/platform.c", + "common/shared_dictionary.c", + "common/transform.c", + "dec/bit_reader.c", + "dec/decode.c", + "dec/huffman.c", + "dec/state.c", + ] + thirdparty_sources += [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources] + env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"]) + env_freetype.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"]) if env.get("use_ubsan") or env.get("use_asan") or env.get("use_tsan") or env.get("use_lsan") or env.get("use_msan"): env_freetype.Append(CPPDEFINES=["BROTLI_BUILD_PORTABLE"]) diff --git a/modules/freetype/config.py b/modules/freetype/config.py index d22f9454ed..c0586d5536 100644 --- a/modules/freetype/config.py +++ b/modules/freetype/config.py @@ -2,5 +2,13 @@ def can_build(env, platform): return True +def get_opts(platform): + from SCons.Variables import BoolVariable + + return [ + BoolVariable("brotli", "Enable Brotli decompressor for WOFF2 fonts support", True), + ] + + def configure(env): pass diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index ff4832bde0..e3b956369d 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -36,6 +36,7 @@ #include "../gdscript_parser.h" #include "core/config/project_settings.h" +#include "core/core_globals.h" #include "core/core_string_names.h" #include "core/io/dir_access.h" #include "core/io/file_access_pack.h" @@ -142,8 +143,8 @@ GDScriptTestRunner::GDScriptTestRunner(const String &p_source_dir, bool p_init_l #endif // Enable printing to show results - _print_line_enabled = true; - _print_error_enabled = true; + CoreGlobals::print_line_enabled = true; + CoreGlobals::print_error_enabled = true; } GDScriptTestRunner::~GDScriptTestRunner() { diff --git a/modules/lightmapper_rd/lightmapper_rd.h b/modules/lightmapper_rd/lightmapper_rd.h index 88860ad0d4..bf6b4399ca 100644 --- a/modules/lightmapper_rd/lightmapper_rd.h +++ b/modules/lightmapper_rd/lightmapper_rd.h @@ -183,7 +183,7 @@ class LightmapperRD : public Lightmapper { } }; - void _plot_triangle_into_triangle_index_list(int p_size, const Vector3i &p_ofs, const AABB &p_bounds, const Vector3 p_points[], uint32_t p_triangle_index, LocalVector<TriangleSort> &triangles, uint32_t p_grid_size); + void _plot_triangle_into_triangle_index_list(int p_size, const Vector3i &p_ofs, const AABB &p_bounds, const Vector3 p_points[3], uint32_t p_triangle_index, LocalVector<TriangleSort> &triangles, uint32_t p_grid_size); struct RasterPushConstant { float atlas_size[2] = {}; diff --git a/modules/mono/config.py b/modules/mono/config.py index 3e6584590c..d895d2d92d 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -5,52 +5,44 @@ def can_build(env, platform): return not env["arch"].startswith("rv") -def configure(env): - platform = env["platform"] - - if platform not in supported_platforms: - raise RuntimeError("This module does not currently support building for this platform") - - env.add_module_version_string("mono") - - from SCons.Script import BoolVariable, PathVariable, Variables, Help +def get_opts(platform): + from SCons.Variables import BoolVariable, PathVariable default_mono_static = platform in ["ios", "javascript"] default_mono_bundles_zlib = platform in ["javascript"] - envvars = Variables() - envvars.Add( + return [ PathVariable( "mono_prefix", "Path to the Mono installation directory for the target platform and architecture", "", PathVariable.PathAccept, - ) - ) - envvars.Add( + ), PathVariable( "mono_bcl", "Path to a custom Mono BCL (Base Class Library) directory for the target platform", "", PathVariable.PathAccept, - ) - ) - envvars.Add(BoolVariable("mono_static", "Statically link Mono", default_mono_static)) - envvars.Add(BoolVariable("mono_glue", "Build with the Mono glue sources", True)) - envvars.Add(BoolVariable("build_cil", "Build C# solutions", True)) - envvars.Add( - BoolVariable("copy_mono_root", "Make a copy of the Mono installation directory to bundle with the editor", True) - ) - - # TODO: It would be great if this could be detected automatically instead - envvars.Add( + ), + BoolVariable("mono_static", "Statically link Mono", default_mono_static), + BoolVariable("mono_glue", "Build with the Mono glue sources", True), + BoolVariable("build_cil", "Build C# solutions", True), + BoolVariable( + "copy_mono_root", "Make a copy of the Mono installation directory to bundle with the editor", True + ), BoolVariable( "mono_bundles_zlib", "Specify if the Mono runtime was built with bundled zlib", default_mono_bundles_zlib - ) - ) + ), + ] + + +def configure(env): + platform = env["platform"] - envvars.Update(env) - Help(envvars.GenerateHelpText(env)) + if platform not in supported_platforms: + raise RuntimeError("This module does not currently support building for this platform") + + env.add_module_version_string("mono") if env["mono_bundles_zlib"]: # Mono may come with zlib bundled for WASM or on newer version when built with MinGW. diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp index a1789412f4..7bce6f2c21 100644 --- a/modules/mono/editor/code_completion.cpp +++ b/modules/mono/editor/code_completion.cpp @@ -172,7 +172,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr } } break; case CompletionKind::SHADER_PARAMS: { - print_verbose("Shared params completion for C# not implemented."); + print_verbose("Shader uniforms completion for C# is not implemented yet."); } break; case CompletionKind::SIGNALS: { Ref<Script> script = ResourceLoader::load(p_script_file.simplify_path()); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index b1f1decd72..437878818c 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -828,6 +828,22 @@ namespace Godot } /// <summary> + /// Constructs a pure scale basis matrix with no rotation or shearing. + /// The scale values are set as the main diagonal of the matrix, + /// and all of the other parts of the matrix are zero. + /// </summary> + /// <param name="scale">The scale Vector3.</param> + /// <returns>A pure scale Basis matrix.</returns> + public static Basis FromScale(Vector3 scale) + { + return new Basis( + scale.x, 0, 0, + 0, scale.y, 0, + 0, 0, scale.z + ); + } + + /// <summary> /// Composes these two basis matrices by multiplying them /// together. This has the effect of transforming the second basis /// (the child) by the first basis (the parent). diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index 7861ece61b..68d097eb4e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -297,7 +297,9 @@ namespace Godot } /// <summary> - /// Rotates the transform by <paramref name="angle"/> (in radians), using matrix multiplication. + /// Rotates the transform by <paramref name="angle"/> (in radians). + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. /// </summary> /// <param name="angle">The angle to rotate, in radians.</param> /// <returns>The rotated transformation matrix.</returns> @@ -307,7 +309,21 @@ namespace Godot } /// <summary> - /// Scales the transform by the given scaling factor, using matrix multiplication. + /// Rotates the transform by <paramref name="angle"/> (in radians). + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. + /// </summary> + /// <param name="angle">The angle to rotate, in radians.</param> + /// <returns>The rotated transformation matrix.</returns> + public Transform2D RotatedLocal(real_t angle) + { + return new Transform2D(angle, new Vector2()) * this; + } + + /// <summary> + /// Scales the transform by the given scaling factor. + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. /// </summary> /// <param name="scale">The scale to introduce.</param> /// <returns>The scaled transformation matrix.</returns> @@ -320,12 +336,19 @@ namespace Godot return copy; } - private void ScaleBasis(Vector2 scale) + /// <summary> + /// Scales the transform by the given scaling factor. + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. + /// </summary> + /// <param name="scale">The scale to introduce.</param> + /// <returns>The scaled transformation matrix.</returns> + public Transform2D ScaledLocal(Vector2 scale) { - x.x *= scale.x; - x.y *= scale.y; - y.x *= scale.x; - y.y *= scale.y; + Transform2D copy = this; + copy.x *= scale; + copy.y *= scale; + return copy; } private real_t Tdotx(Vector2 with) @@ -339,11 +362,23 @@ namespace Godot } /// <summary> - /// Translates the transform by the given <paramref name="offset"/>, - /// relative to the transform's basis vectors. - /// - /// Unlike <see cref="Rotated"/> and <see cref="Scaled"/>, - /// this does not use matrix multiplication. + /// Translates the transform by the given <paramref name="offset"/>. + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. + /// </summary> + /// <param name="offset">The offset to translate by.</param> + /// <returns>The translated matrix.</returns> + public Transform2D Translated(Vector2 offset) + { + Transform2D copy = this; + copy.origin += offset; + return copy; + } + + /// <summary> + /// Translates the transform by the given <paramref name="offset"/>. + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. /// </summary> /// <param name="offset">The offset to translate by.</param> /// <returns>The translated matrix.</returns> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index 97b4a87713..9eaf4f3252 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -186,8 +186,10 @@ namespace Godot } /// <summary> - /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (in radians), - /// using matrix multiplication. The axis must be a normalized vector. + /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (in radians). + /// The axis must be a normalized vector. + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. /// </summary> /// <param name="axis">The axis to rotate around. Must be normalized.</param> /// <param name="angle">The angle to rotate, in radians.</param> @@ -198,7 +200,24 @@ namespace Godot } /// <summary> - /// Scales the transform by the given 3D scaling factor, using matrix multiplication. + /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (in radians). + /// The axis must be a normalized vector. + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. + /// </summary> + /// <param name="axis">The axis to rotate around. Must be normalized.</param> + /// <param name="angle">The angle to rotate, in radians.</param> + /// <returns>The rotated transformation matrix.</returns> + public Transform3D RotatedLocal(Vector3 axis, real_t angle) + { + Basis tmpBasis = new Basis(axis, angle); + return new Transform3D(basis * tmpBasis, origin); + } + + /// <summary> + /// Scales the transform by the given 3D <paramref name="scale"/> factor. + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. /// </summary> /// <param name="scale">The scale to introduce.</param> /// <returns>The scaled transformation matrix.</returns> @@ -207,6 +226,19 @@ namespace Godot return new Transform3D(basis.Scaled(scale), origin * scale); } + /// <summary> + /// Scales the transform by the given 3D <paramref name="scale"/> factor. + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. + /// </summary> + /// <param name="scale">The scale to introduce.</param> + /// <returns>The scaled transformation matrix.</returns> + public Transform3D ScaledLocal(Vector3 scale) + { + Basis tmpBasis = Basis.FromScale(scale); + return new Transform3D(basis * tmpBasis, origin); + } + private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up) { // Make rotation matrix @@ -231,11 +263,21 @@ namespace Godot } /// <summary> - /// Translates the transform by the given <paramref name="offset"/>, - /// relative to the transform's basis vectors. - /// - /// Unlike <see cref="Rotated"/> and <see cref="Scaled"/>, - /// this does not use matrix multiplication. + /// Translates the transform by the given <paramref name="offset"/>. + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. + /// </summary> + /// <param name="offset">The offset to translate by.</param> + /// <returns>The translated matrix.</returns> + public Transform3D Translated(Vector3 offset) + { + return new Transform3D(basis, origin + offset); + } + + /// <summary> + /// Translates the transform by the given <paramref name="offset"/>. + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. /// </summary> /// <param name="offset">The offset to translate by.</param> /// <returns>The translated matrix.</returns> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index ec2e724b10..c3d5fbfdef 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -620,22 +620,6 @@ namespace Godot ); } - /// <summary> - /// Returns a diagonal matrix with the vector as main diagonal. - /// - /// This is equivalent to a <see cref="Basis"/> with no rotation or shearing and - /// this vector's components set as the scale. - /// </summary> - /// <returns>A <see cref="Basis"/> with the vector as its main diagonal.</returns> - public Basis ToDiagonalMatrix() - { - return new Basis( - x, 0, 0, - 0, y, 0, - 0, 0, z - ); - } - // Constants private static readonly Vector3 _zero = new Vector3(0, 0, 0); private static readonly Vector3 _one = new Vector3(1, 1, 1); diff --git a/modules/multiplayer/editor/replication_editor_plugin.cpp b/modules/multiplayer/editor/replication_editor_plugin.cpp index c6484264d0..1f79b8c3e3 100644 --- a/modules/multiplayer/editor/replication_editor_plugin.cpp +++ b/modules/multiplayer/editor/replication_editor_plugin.cpp @@ -32,9 +32,12 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/inspector_dock.h" +#include "editor/scene_tree_editor.h" #include "modules/multiplayer/multiplayer_synchronizer.h" #include "scene/gui/dialogs.h" +#include "scene/gui/separator.h" #include "scene/gui/tree.h" void ReplicationEditor::_pick_node_filter_text_changed(const String &p_newtext) { diff --git a/modules/multiplayer/editor/replication_editor_plugin.h b/modules/multiplayer/editor/replication_editor_plugin.h index 0bb2cb888d..5cc2bbe937 100644 --- a/modules/multiplayer/editor/replication_editor_plugin.h +++ b/modules/multiplayer/editor/replication_editor_plugin.h @@ -40,7 +40,9 @@ class ConfirmationDialog; class MultiplayerSynchronizer; +class SceneTreeDialog; class Tree; +class TreeItem; class ReplicationEditor : public VBoxContainer { GDCLASS(ReplicationEditor, VBoxContainer); diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml index deabc5ccd3..52a7fe492f 100644 --- a/modules/regex/doc_classes/RegEx.xml +++ b/modules/regex/doc_classes/RegEx.xml @@ -62,6 +62,13 @@ Compiles and assign the search pattern to use. Returns [constant OK] if the compilation is successful. If an error is encountered, details are printed to standard output and an error is returned. </description> </method> + <method name="create_from_string" qualifiers="static"> + <return type="RegEx" /> + <argument index="0" name="pattern" type="String" /> + <description> + Creates and compiles a new [RegEx] object. + </description> + </method> <method name="get_group_count" qualifiers="const"> <return type="int" /> <description> @@ -96,7 +103,7 @@ </description> </method> <method name="search_all" qualifiers="const"> - <return type="Array" /> + <return type="RegExMatch[]" /> <argument index="0" name="subject" type="String" /> <argument index="1" name="offset" type="int" default="0" /> <argument index="2" name="end" type="int" default="-1" /> diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp index 67ce37219b..569066867a 100644 --- a/modules/regex/regex.cpp +++ b/modules/regex/regex.cpp @@ -159,6 +159,13 @@ void RegEx::_pattern_info(uint32_t what, void *where) const { pcre2_pattern_info_32((pcre2_code_32 *)code, what, where); } +Ref<RegEx> RegEx::create_from_string(const String &p_pattern) { + Ref<RegEx> ret; + ret.instantiate(); + ret->compile(p_pattern); + return ret; +} + void RegEx::clear() { if (code) { pcre2_code_free_32((pcre2_code_32 *)code); @@ -258,11 +265,11 @@ Ref<RegExMatch> RegEx::search(const String &p_subject, int p_offset, int p_end) return result; } -Array RegEx::search_all(const String &p_subject, int p_offset, int p_end) const { +TypedArray<RegExMatch> RegEx::search_all(const String &p_subject, int p_offset, int p_end) const { ERR_FAIL_COND_V_MSG(p_offset < 0, Array(), "RegEx search offset must be >= 0"); int last_end = -1; - Array result; + TypedArray<RegExMatch> result; Ref<RegExMatch> match = search(p_subject, p_offset, p_end); while (match.is_valid()) { if (last_end == match->get_end(0)) { @@ -384,6 +391,8 @@ RegEx::~RegEx() { } void RegEx::_bind_methods() { + ClassDB::bind_static_method("RegEx", D_METHOD("create_from_string", "pattern"), &RegEx::create_from_string); + ClassDB::bind_method(D_METHOD("clear"), &RegEx::clear); ClassDB::bind_method(D_METHOD("compile", "pattern"), &RegEx::compile); ClassDB::bind_method(D_METHOD("search", "subject", "offset", "end"), &RegEx::search, DEFVAL(0), DEFVAL(-1)); diff --git a/modules/regex/regex.h b/modules/regex/regex.h index 1455188670..9296de929f 100644 --- a/modules/regex/regex.h +++ b/modules/regex/regex.h @@ -37,6 +37,7 @@ #include "core/templates/vector.h" #include "core/variant/array.h" #include "core/variant/dictionary.h" +#include "core/variant/typed_array.h" class RegExMatch : public RefCounted { GDCLASS(RegExMatch, RefCounted); @@ -81,11 +82,13 @@ protected: static void _bind_methods(); public: + static Ref<RegEx> create_from_string(const String &p_pattern); + void clear(); Error compile(const String &p_pattern); Ref<RegExMatch> search(const String &p_subject, int p_offset = 0, int p_end = -1) const; - Array search_all(const String &p_subject, int p_offset = 0, int p_end = -1) const; + TypedArray<RegExMatch> search_all(const String &p_subject, int p_offset = 0, int p_end = -1) const; String sub(const String &p_subject, const String &p_replacement, bool p_all = false, int p_offset = 0, int p_end = -1) const; bool is_valid() const; diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub index 93fd8fe45f..81b8e1ea5d 100644 --- a/modules/text_server_adv/SCsub +++ b/modules/text_server_adv/SCsub @@ -113,15 +113,18 @@ if env["builtin_harfbuzz"]: if freetype_enabled: thirdparty_sources += [ "src/hb-ft.cc", - "src/hb-graphite2.cc", ] + if env["graphite"]: + thirdparty_sources += [ + "src/hb-graphite2.cc", + ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] env_harfbuzz.Prepend(CPPPATH=["#thirdparty/harfbuzz/src"]) env_harfbuzz.Append(CCFLAGS=["-DHAVE_ICU"]) if env["builtin_icu"]: - env_harfbuzz.Prepend(CPPPATH=["#thirdparty/icu4c/common/"]) + env_harfbuzz.Prepend(CPPPATH=["#thirdparty/icu4c/common/", "#thirdparty/icu4c/i18n/"]) env_harfbuzz.Append(CCFLAGS=["-DU_HAVE_LIB_SUFFIX=1", "-DU_LIB_SUFFIX_C_NAME=_godot", "-DHAVE_ICU_BUILTIN"]) if freetype_enabled: @@ -133,7 +136,7 @@ if env["builtin_harfbuzz"]: ) if env["builtin_freetype"]: env_harfbuzz.Prepend(CPPPATH=["#thirdparty/freetype/include"]) - if env["builtin_graphite"]: + if env["builtin_graphite"] and env["graphite"]: env_harfbuzz.Prepend(CPPPATH=["#thirdparty/graphite/include"]) env_harfbuzz.Append(CCFLAGS=["-DGRAPHITE2_STATIC"]) @@ -165,7 +168,7 @@ if env["builtin_harfbuzz"]: env.Append(LIBS=[lib]) -if env["builtin_graphite"] and freetype_enabled: +if env["builtin_graphite"] and freetype_enabled and env["graphite"]: env_graphite = env_modules.Clone() env_graphite.disable_warnings() @@ -439,6 +442,10 @@ if env["builtin_icu"]: "common/uvectr32.cpp", "common/uvectr64.cpp", "common/wintz.cpp", + "i18n/scriptset.cpp", + "i18n/ucln_in.cpp", + "i18n/uspoof.cpp", + "i18n/uspoof_impl.cpp", ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] @@ -451,7 +458,7 @@ if env["builtin_icu"]: else: thirdparty_sources += ["icu_data/icudata_stub.cpp"] - env_icu.Prepend(CPPPATH=["#thirdparty/icu4c/common/"]) + env_icu.Prepend(CPPPATH=["#thirdparty/icu4c/common/", "#thirdparty/icu4c/i18n/"]) env_icu.Append( CXXFLAGS=[ "-DU_STATIC_IMPLEMENTATION", @@ -463,6 +470,7 @@ if env["builtin_icu"]: "-DUCONFIG_NO_IDNA", "-DUCONFIG_NO_FILE_IO", "-DUCONFIG_NO_TRANSLITERATION", + "-DUCONFIG_NO_REGULAR_EXPRESSIONS", "-DPKGDATA_MODE=static", "-DU_ENABLE_DYLOAD=0", "-DU_HAVE_LIB_SUFFIX=1", @@ -480,7 +488,7 @@ if env["builtin_icu"]: if env_text_server_adv["tools"]: env_text_server_adv.Append(CXXFLAGS=["-DICU_STATIC_DATA"]) - env_text_server_adv.Prepend(CPPPATH=["#thirdparty/icu4c/common/"]) + env_text_server_adv.Prepend(CPPPATH=["#thirdparty/icu4c/common/", "#thirdparty/icu4c/i18n/"]) lib = env_icu.add_library("icu_builtin", thirdparty_sources) thirdparty_obj += lib @@ -510,7 +518,7 @@ if env["builtin_freetype"] and freetype_enabled: env_text_server_adv.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"]) env_text_server_adv.Prepend(CPPPATH=["#thirdparty/freetype/include"]) -if env["builtin_graphite"] and freetype_enabled: +if env["builtin_graphite"] and freetype_enabled and env["graphite"]: env_text_server_adv.Prepend(CPPPATH=["#thirdparty/graphite/include"]) env_text_server_adv.add_source_files(module_obj, "*.cpp") diff --git a/modules/text_server_adv/config.py b/modules/text_server_adv/config.py index 8c8df9b05e..179a2ff378 100644 --- a/modules/text_server_adv/config.py +++ b/modules/text_server_adv/config.py @@ -2,6 +2,14 @@ def can_build(env, platform): return True +def get_opts(platform): + from SCons.Variables import BoolVariable + + return [ + BoolVariable("graphite", "Enable SIL Graphite smart fonts support", True), + ] + + def configure(env): pass diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 64788bfeff..73dbf2f443 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -346,6 +346,8 @@ bool TextServerAdvanced::has_feature(Feature p_feature) const { case FEATURE_FONT_VARIABLE: case FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION: case FEATURE_USE_SUPPORT_DATA: + case FEATURE_UNICODE_IDENTIFIERS: + case FEATURE_UNICODE_SECURITY: return true; default: { } @@ -4243,7 +4245,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(const RID &p_shaped_l Glyph *sd_glyphs = sd->glyphs.ptrw(); - if (p_trim_flags.has_flag(OVERRUN_TRIM) || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) { + if ((p_trim_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIM || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) { sd->overrun_trim_data.trim_pos = -1; sd->overrun_trim_data.ellipsis_pos = -1; return; @@ -4704,7 +4706,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(const RID &p_shape for (int i = 0; i < sd_size; i++) { if (sd_glyphs[i].count > 0) { char32_t c = sd->text[sd_glyphs[i].start - sd->start]; - if (c == 0x0640) { + if (c == 0x0640 && sd_glyphs[i].start == sd_glyphs[i].end - 1) { sd_glyphs[i].flags |= GRAPHEME_IS_ELONGATION; } if (sd->jstops.has(sd_glyphs[i].start)) { @@ -4716,6 +4718,11 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(const RID &p_shape if (sd_glyphs[i].font_rid != RID()) { Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size); if ((sd_glyphs[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) { +#if HB_VERSION_ATLEAST(5, 1, 0) + if ((i > 0) && ((sd_glyphs[i - 1].flags & GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL) != GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL)) { + continue; + } +#endif gl.start = sd_glyphs[i].start; gl.end = sd_glyphs[i].end; gl.repeat = 0; @@ -4906,11 +4913,16 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star hb_buffer_clear_contents(p_sd->hb_buffer); hb_buffer_set_direction(p_sd->hb_buffer, p_direction); + int flags = (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0); if (p_sd->preserve_control) { - hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)(HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES | (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0))); + flags |= HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES; } else { - hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)(HB_BUFFER_FLAG_DEFAULT | (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0))); + flags |= HB_BUFFER_FLAG_DEFAULT; } +#if HB_VERSION_ATLEAST(5, 1, 0) + flags |= HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL; +#endif + hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)flags); hb_buffer_set_script(p_sd->hb_buffer, p_script); if (p_sd->spans[p_span].language.is_empty()) { @@ -4974,10 +4986,16 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star gl.font_rid = p_fonts[p_fb_index]; gl.font_size = fs; - if (glyph_info[i].mask & HB_GLYPH_FLAG_DEFINED) { + if (glyph_info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK) { gl.flags |= GRAPHEME_IS_CONNECTED; } +#if HB_VERSION_ATLEAST(5, 1, 0) + if (glyph_info[i].mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL) { + gl.flags |= GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL; + } +#endif + gl.index = glyph_info[i].codepoint; if (gl.index != 0) { _ensure_glyph(fd, fss, gl.index); @@ -5639,6 +5657,68 @@ String TextServerAdvanced::percent_sign(const String &p_language) const { return "%"; } +int TextServerAdvanced::is_confusable(const String &p_string, const PackedStringArray &p_dict) const { + UErrorCode status = U_ZERO_ERROR; + int match_index = -1; + + Char16String utf16 = p_string.utf16(); + Vector<UChar *> skeletons; + skeletons.resize(p_dict.size()); + + USpoofChecker *sc = uspoof_open(&status); + uspoof_setChecks(sc, USPOOF_CONFUSABLE, &status); + for (int i = 0; i < p_dict.size(); i++) { + Char16String word = p_dict[i].utf16(); + int32_t len = uspoof_getSkeleton(sc, 0, word.get_data(), -1, NULL, 0, &status); + skeletons.write[i] = (UChar *)memalloc(++len * sizeof(UChar)); + status = U_ZERO_ERROR; + uspoof_getSkeleton(sc, 0, word.get_data(), -1, skeletons.write[i], len, &status); + } + + int32_t len = uspoof_getSkeleton(sc, 0, utf16.get_data(), -1, NULL, 0, &status); + UChar *skel = (UChar *)memalloc(++len * sizeof(UChar)); + status = U_ZERO_ERROR; + uspoof_getSkeleton(sc, 0, utf16.get_data(), -1, skel, len, &status); + for (int i = 0; i < skeletons.size(); i++) { + if (u_strcmp(skel, skeletons[i]) == 0) { + match_index = i; + break; + } + } + memfree(skel); + + for (int i = 0; i < skeletons.size(); i++) { + memfree(skeletons.write[i]); + } + uspoof_close(sc); + + ERR_FAIL_COND_V_MSG(U_FAILURE(status), -1, u_errorName(status)); + + return match_index; +} + +bool TextServerAdvanced::spoof_check(const String &p_string) const { + UErrorCode status = U_ZERO_ERROR; + Char16String utf16 = p_string.utf16(); + + USet *allowed = uset_openEmpty(); + uset_addAll(allowed, uspoof_getRecommendedSet(&status)); + uset_addAll(allowed, uspoof_getInclusionSet(&status)); + + USpoofChecker *sc = uspoof_open(&status); + uspoof_setAllowedChars(sc, allowed, &status); + uspoof_setRestrictionLevel(sc, USPOOF_MODERATELY_RESTRICTIVE); + + int32_t bitmask = uspoof_check(sc, utf16.get_data(), -1, NULL, &status); + + uspoof_close(sc); + uset_close(allowed); + + ERR_FAIL_COND_V_MSG(U_FAILURE(status), false, u_errorName(status)); + + return (bitmask != 0); +} + String TextServerAdvanced::strip_diacritics(const String &p_string) const { UErrorCode err = U_ZERO_ERROR; @@ -5757,6 +5837,191 @@ PackedInt32Array TextServerAdvanced::string_get_word_breaks(const String &p_stri return ret; } +bool TextServerAdvanced::is_valid_identifier(const String &p_string) const { + enum UAX31SequenceStatus { + SEQ_NOT_STARTED, + SEQ_STARTED, + SEQ_STARTED_VIR, + SEQ_NEAR_END, + }; + + const char32_t *str = p_string.ptr(); + int len = p_string.length(); + + if (len == 0) { + return false; // Empty string. + } + + UErrorCode err = U_ZERO_ERROR; + Char16String utf16 = p_string.utf16(); + const UNormalizer2 *norm_c = unorm2_getNFCInstance(&err); + if (U_FAILURE(err)) { + return false; // Failed to load normalizer. + } + bool isnurom = unorm2_isNormalized(norm_c, utf16.ptr(), utf16.length(), &err); + if (U_FAILURE(err) || !isnurom) { + return false; // Do not conform to Normalization Form C. + } + + UAX31SequenceStatus A1_sequence_status = SEQ_NOT_STARTED; + UScriptCode A1_scr = USCRIPT_INHERITED; + UAX31SequenceStatus A2_sequence_status = SEQ_NOT_STARTED; + UScriptCode A2_scr = USCRIPT_INHERITED; + UAX31SequenceStatus B_sequence_status = SEQ_NOT_STARTED; + UScriptCode B_scr = USCRIPT_INHERITED; + + for (int i = 0; i < len; i++) { + err = U_ZERO_ERROR; + UScriptCode scr = uscript_getScript(str[i], &err); + if (U_FAILURE(err)) { + return false; // Invalid script. + } + if (uscript_getUsage(scr) != USCRIPT_USAGE_RECOMMENDED) { + return false; // Not a recommended script. + } + uint8_t cat = u_charType(str[i]); + int32_t jt = u_getIntPropertyValue(str[i], UCHAR_JOINING_TYPE); + + // UAX #31 section 2.3 subsections A1, A2 and B, check ZWNJ and ZWJ usage. + switch (A1_sequence_status) { + case SEQ_NEAR_END: { + if ((A1_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A1_scr)) { + return false; // Mixed script. + } + if (jt == U_JT_RIGHT_JOINING || jt == U_JT_DUAL_JOINING) { + A1_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset. + } else if (jt != U_JT_TRANSPARENT) { + return false; // Invalid end of sequence. + } + } break; + case SEQ_STARTED: { + if ((A1_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A1_scr)) { + A1_sequence_status = SEQ_NOT_STARTED; // Reset. + } else { + if (jt != U_JT_TRANSPARENT) { + if (str[i] == 0x200C /*ZWNJ*/) { + A1_sequence_status = SEQ_NEAR_END; + continue; + } else { + A1_sequence_status = SEQ_NOT_STARTED; // Reset. + } + } + } + } break; + default: + break; + } + if (A1_sequence_status == SEQ_NOT_STARTED) { + if (jt == U_JT_LEFT_JOINING || jt == U_JT_DUAL_JOINING) { + A1_sequence_status = SEQ_STARTED; + A1_scr = scr; + } + }; + + switch (A2_sequence_status) { + case SEQ_NEAR_END: { + if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) { + return false; // Mixed script. + } + if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) { + A2_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset. + } else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) { + return false; // Invalid end of sequence. + } + } break; + case SEQ_STARTED_VIR: { + if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) { + A2_sequence_status = SEQ_NOT_STARTED; // Reset. + } else { + if (str[i] == 0x200C /*ZWNJ*/) { + A2_sequence_status = SEQ_NEAR_END; + continue; + } else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) { + A2_sequence_status = SEQ_NOT_STARTED; // Reset. + } + } + } break; + case SEQ_STARTED: { + if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) { + A2_sequence_status = SEQ_NOT_STARTED; // Reset. + } else { + if (u_getCombiningClass(str[i]) == 9 /*Virama Combining Class*/) { + A2_sequence_status = SEQ_STARTED_VIR; + } else if (cat != U_MODIFIER_LETTER) { + A2_sequence_status = SEQ_NOT_STARTED; // Reset. + } + } + } break; + default: + break; + } + if (A2_sequence_status == SEQ_NOT_STARTED) { + if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) { + A2_sequence_status = SEQ_STARTED; + A2_scr = scr; + } + } + + switch (B_sequence_status) { + case SEQ_NEAR_END: { + if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) { + return false; // Mixed script. + } + if (u_getIntPropertyValue(str[i], UCHAR_INDIC_SYLLABIC_CATEGORY) != U_INSC_VOWEL_DEPENDENT) { + B_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset. + } else { + return false; // Invalid end of sequence. + } + } break; + case SEQ_STARTED_VIR: { + if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) { + B_sequence_status = SEQ_NOT_STARTED; // Reset. + } else { + if (str[i] == 0x200D /*ZWJ*/) { + B_sequence_status = SEQ_NEAR_END; + continue; + } else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) { + B_sequence_status = SEQ_NOT_STARTED; // Reset. + } + } + } break; + case SEQ_STARTED: { + if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) { + B_sequence_status = SEQ_NOT_STARTED; // Reset. + } else { + if (u_getCombiningClass(str[i]) == 9 /*Virama Combining Class*/) { + B_sequence_status = SEQ_STARTED_VIR; + } else if (cat != U_MODIFIER_LETTER) { + B_sequence_status = SEQ_NOT_STARTED; // Reset. + } + } + } break; + default: + break; + } + if (B_sequence_status == SEQ_NOT_STARTED) { + if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) { + B_sequence_status = SEQ_STARTED; + B_scr = scr; + } + } + + if (u_hasBinaryProperty(str[i], UCHAR_PATTERN_SYNTAX) || u_hasBinaryProperty(str[i], UCHAR_PATTERN_WHITE_SPACE) || u_hasBinaryProperty(str[i], UCHAR_NONCHARACTER_CODE_POINT)) { + return false; // Not a XID_Start or XID_Continue character. + } + if (i == 0) { + if (!(cat == U_LOWERCASE_LETTER || cat == U_UPPERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_OTHER_LETTER || cat == U_MODIFIER_LETTER || cat == U_LETTER_NUMBER || str[0] == 0x2118 || str[0] == 0x212E || str[0] == 0x309B || str[0] == 0x309C || str[0] == 0x005F)) { + return false; // Not a XID_Start character. + } + } else { + if (!(cat == U_LOWERCASE_LETTER || cat == U_UPPERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_OTHER_LETTER || cat == U_MODIFIER_LETTER || cat == U_LETTER_NUMBER || cat == U_NON_SPACING_MARK || cat == U_COMBINING_SPACING_MARK || cat == U_DECIMAL_DIGIT_NUMBER || cat == U_CONNECTOR_PUNCTUATION || str[i] == 0x2118 || str[i] == 0x212E || str[i] == 0x309B || str[i] == 0x309C || str[i] == 0x1369 || str[i] == 0x1371 || str[i] == 0x00B7 || str[i] == 0x0387 || str[i] == 0x19DA || str[i] == 0x0E33 || str[i] == 0x0EB3 || str[i] == 0xFF9E || str[i] == 0xFF9F)) { + return false; // Not a XID_Continue character. + } + } + } + return true; +} + TextServerAdvanced::TextServerAdvanced() { _insert_num_systems_lang(); _insert_feature_sets(); diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 8852c40406..7ae329d616 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -101,6 +101,7 @@ using namespace godot; #include <unicode/uloc.h> #include <unicode/unorm2.h> #include <unicode/uscript.h> +#include <unicode/uspoof.h> #include <unicode/ustring.h> #include <unicode/utypes.h> @@ -704,7 +705,11 @@ public: virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override; + virtual int is_confusable(const String &p_string, const PackedStringArray &p_dict) const override; + virtual bool spoof_check(const String &p_string) const override; + virtual String strip_diacritics(const String &p_string) const override; + virtual bool is_valid_identifier(const String &p_string) const override; virtual String string_to_upper(const String &p_string, const String &p_language = "") const override; virtual String string_to_lower(const String &p_string, const String &p_language = "") const override; diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 50ea4677b1..55d912a10a 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -3204,7 +3204,7 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(const RID &p_shaped_l Glyph *sd_glyphs = sd->glyphs.ptrw(); - if (p_trim_flags.has_flag(OVERRUN_TRIM) || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) { + if ((p_trim_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIM || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) { sd->overrun_trim_data.trim_pos = -1; sd->overrun_trim_data.ellipsis_pos = -1; return; diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp index 1e9755f45f..7f8e9d8254 100644 --- a/modules/visual_script/editor/visual_script_editor.cpp +++ b/modules/visual_script/editor/visual_script_editor.cpp @@ -42,10 +42,32 @@ #include "editor/editor_node.h" #include "editor/editor_resource_preview.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" +#include "scene/gui/check_button.h" +#include "scene/gui/graph_edit.h" +#include "scene/gui/separator.h" #include "scene/gui/view_panner.h" #include "scene/main/window.h" #ifdef TOOLS_ENABLED + +void VisualScriptEditedProperty::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_edited_property", "value"), &VisualScriptEditedProperty::set_edited_property); + ClassDB::bind_method(D_METHOD("get_edited_property"), &VisualScriptEditedProperty::get_edited_property); + + ADD_PROPERTY(PropertyInfo(Variant::NIL, "edited_property", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_edited_property", "get_edited_property"); +} + +void VisualScriptEditedProperty::set_edited_property(Variant p_variant) { + edited_property = p_variant; +} + +Variant VisualScriptEditedProperty::get_edited_property() const { + return edited_property; +} + +///////////////// + class VisualScriptEditorSignalEdit : public Object { GDCLASS(VisualScriptEditorSignalEdit, Object); @@ -3898,14 +3920,14 @@ int VisualScriptEditor::_create_new_node_from_name(const String &p_text, const V return new_id; } -void VisualScriptEditor::_default_value_changed() { +void VisualScriptEditor::_default_value_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing) { Ref<VisualScriptNode> vsn = script->get_node(editing_id); if (vsn.is_null()) { return; } undo_redo->create_action(TTR("Change Input Value")); - undo_redo->add_do_method(vsn.ptr(), "set_default_input_value", editing_input, default_value_edit->get_variant()); + undo_redo->add_do_method(vsn.ptr(), "set_default_input_value", editing_input, p_value); undo_redo->add_undo_method(vsn.ptr(), "set_default_input_value", editing_input, vsn->get_default_input_value(editing_input)); undo_redo->add_do_method(this, "_update_graph", editing_id); @@ -3928,9 +3950,6 @@ void VisualScriptEditor::_default_value_edited(Node *p_button, int p_id, int p_i Variant::construct(pinfo.type, existing, &existingp, 1, ce); } - default_value_edit->set_position(Object::cast_to<Control>(p_button)->get_screen_position() + Vector2(0, Object::cast_to<Control>(p_button)->get_size().y) * graph->get_zoom()); - default_value_edit->reset_size(); - if (pinfo.type == Variant::NODE_PATH) { Node *edited_scene = get_tree()->get_edited_scene_root(); if (edited_scene) { // Fixing an old crash bug ( Visual Script Crashes on editing NodePath with an empty scene open). @@ -3948,11 +3967,33 @@ void VisualScriptEditor::_default_value_edited(Node *p_button, int p_id, int p_i } } - if (default_value_edit->edit(nullptr, pinfo.name, pinfo.type, existing, pinfo.hint, pinfo.hint_string)) { - if (pinfo.hint == PROPERTY_HINT_MULTILINE_TEXT) { - default_value_edit->popup_centered_ratio(); + edited_default_property_holder->set_edited_property(existing); + + if (default_property_editor) { + default_property_editor->disconnect("property_changed", callable_mp(this, &VisualScriptEditor::_default_value_changed)); + default_property_editor_popup->remove_child(default_property_editor); + } + + default_property_editor = EditorInspector::instantiate_property_editor(edited_default_property_holder.ptr(), pinfo.type, "edited_property", pinfo.hint, pinfo.hint_string, PROPERTY_USAGE_NONE); + if (default_property_editor) { + default_property_editor->set_object_and_property(edited_default_property_holder.ptr(), "edited_property"); + default_property_editor->update_property(); + default_property_editor->set_name_split_ratio(0); + default_property_editor_popup->add_child(default_property_editor); + + default_property_editor->connect("property_changed", callable_mp(this, &VisualScriptEditor::_default_value_changed)); + + Button *button = Object::cast_to<Button>(p_button); + if (button) { + default_property_editor_popup->set_position(button->get_screen_position() + Vector2(0, button->get_size().height) * graph->get_zoom()); + } + + default_property_editor_popup->reset_size(); + + if (pinfo.hint == PROPERTY_HINT_MULTILINE_TEXT || !button) { + default_property_editor_popup->popup_centered_ratio(); } else { - default_value_edit->popup(); + default_property_editor_popup->popup(); } } @@ -4795,9 +4836,11 @@ VisualScriptEditor::VisualScriptEditor() { set_process_input(true); - default_value_edit = memnew(CustomPropertyEditor); - add_child(default_value_edit); - default_value_edit->connect("variant_changed", callable_mp(this, &VisualScriptEditor::_default_value_changed)); + default_property_editor_popup = memnew(PopupPanel); + default_property_editor_popup->set_min_size(Size2i(180, 0) * EDSCALE); + add_child(default_property_editor_popup); + + edited_default_property_holder.instantiate(); new_connect_node_select = memnew(VisualScriptPropertySelector); add_child(new_connect_node_select); diff --git a/modules/visual_script/editor/visual_script_editor.h b/modules/visual_script/editor/visual_script_editor.h index a6df7bba73..6b337e52f6 100644 --- a/modules/visual_script/editor/visual_script_editor.h +++ b/modules/visual_script/editor/visual_script_editor.h @@ -34,15 +34,31 @@ #include "../visual_script.h" #include "editor/create_dialog.h" #include "editor/plugins/script_editor_plugin.h" -#include "editor/property_editor.h" -#include "scene/gui/graph_edit.h" #include "visual_script_property_selector.h" +class GraphEdit; + class VisualScriptEditorSignalEdit; class VisualScriptEditorVariableEdit; #ifdef TOOLS_ENABLED +class VisualScriptEditedProperty : public RefCounted { + GDCLASS(VisualScriptEditedProperty, RefCounted); + +private: + Variant edited_property; + +protected: + static void _bind_methods(); + +public: + void set_edited_property(Variant p_variant); + Variant get_edited_property() const; + + VisualScriptEditedProperty() {} +}; + // TODO: Maybe this class should be refactored. // See https://github.com/godotengine/godot/issues/51913 class VisualScriptEditor : public ScriptEditorBase { @@ -115,7 +131,9 @@ class VisualScriptEditor : public ScriptEditorBase { AcceptDialog *edit_variable_dialog = nullptr; EditorInspector *edit_variable_edit = nullptr; - CustomPropertyEditor *default_value_edit = nullptr; + PopupPanel *default_property_editor_popup = nullptr; + EditorProperty *default_property_editor = nullptr; + Ref<VisualScriptEditedProperty> edited_default_property_holder; UndoRedo *undo_redo = nullptr; @@ -276,7 +294,7 @@ class VisualScriptEditor : public ScriptEditorBase { int data_disconnect_node = 0; int data_disconnect_port = 0; - void _default_value_changed(); + void _default_value_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing); void _default_value_edited(Node *p_button, int p_id, int p_input_port); void _menu_option(int p_what); |