diff options
-rw-r--r-- | doc/classes/Array.xml | 7 | ||||
-rw-r--r-- | doc/classes/CanvasItem.xml | 1 | ||||
-rw-r--r-- | doc/classes/Control.xml | 2 | ||||
-rw-r--r-- | doc/classes/Font.xml | 1 | ||||
-rw-r--r-- | doc/classes/InputMap.xml | 1 | ||||
-rw-r--r-- | doc/classes/LineEdit.xml | 5 | ||||
-rw-r--r-- | doc/classes/MainLoop.xml | 2 | ||||
-rw-r--r-- | doc/classes/NinePatchRect.xml | 2 | ||||
-rw-r--r-- | editor/editor_data.cpp | 2 | ||||
-rw-r--r-- | editor/import/editor_scene_importer_gltf.cpp | 10 | ||||
-rw-r--r-- | editor/import/editor_scene_importer_gltf.h | 1 | ||||
-rw-r--r-- | modules/assimp/editor_scene_importer_assimp.cpp | 4 | ||||
-rw-r--r-- | platform/android/export/export.cpp | 270 | ||||
-rw-r--r-- | scene/gui/line_edit.cpp | 11 |
14 files changed, 194 insertions, 125 deletions
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index 2d330fc935..c192cee1fe 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -331,17 +331,18 @@ <argument index="1" name="func" type="String"> </argument> <description> - Sorts the array using a custom method. The arguments are an object that holds the method and the name of such method. The custom method receives two arguments (a pair of elements from the array) and must return [code]true[/code] if the first argument is less than the second, and return [code]false[/code] otherwise. + Sorts the array using a custom method. The arguments are an object that holds the method and the name of such method. The custom method receives two arguments (a pair of elements from the array) and must return either [code]true[/code] or [code]false[/code]. [b]Note:[/b] you cannot randomize the return value as the heapsort algorithm expects a deterministic result. Doing so will result in unexpected behavior. [codeblock] class MyCustomSorter: - static func sort(a, b): + static func sort_ascending(a, b): if a[0] < b[0]: return true return false var my_items = [[5, "Potato"], [9, "Rice"], [4, "Tomato"]] - my_items.sort_custom(MyCustomSorter, "sort") + my_items.sort_custom(MyCustomSorter, "sort_ascending") + print(my_items) # Prints [[4, Tomato], [5, Potato], [9, Rice]] [/codeblock] </description> </method> diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index 8372d15324..54d917c931 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -42,6 +42,7 @@ <argument index="7" name="antialiased" type="bool" default="false"> </argument> <description> + Draws an arc between the given angles. The larger the value of [code]point_count[/code], the smoother the curve. </description> </method> <method name="draw_char"> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 75d5a72fb1..d309015453 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -504,7 +504,7 @@ <description> Virtual method to be implemented by the user. Returns whether the given [code]point[/code] is inside this control. If not overridden, default behavior is checking if the point is within control's Rect. - [b]Node:[/b] If you want to check if a point is inside the control, you can use [code]get_rect().has_point(point)[/code]. + [b]Note:[/b] If you want to check if a point is inside the control, you can use [code]get_rect().has_point(point)[/code]. </description> </method> <method name="has_shader_override" qualifiers="const"> diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml index f7de79913c..e751a07082 100644 --- a/doc/classes/Font.xml +++ b/doc/classes/Font.xml @@ -91,6 +91,7 @@ <return type="bool"> </return> <description> + Returns [code]true[/code] if the font has an outline. </description> </method> <method name="is_distance_field_hint" qualifiers="const"> diff --git a/doc/classes/InputMap.xml b/doc/classes/InputMap.xml index 6bbb402b15..5b83f943cf 100644 --- a/doc/classes/InputMap.xml +++ b/doc/classes/InputMap.xml @@ -60,6 +60,7 @@ <argument index="1" name="deadzone" type="float"> </argument> <description> + Sets a deadzone value for the action. </description> </method> <method name="add_action"> diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index a360010b7e..d428c133af 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -145,6 +145,11 @@ Emitted when the text changes. </description> </signal> + <signal name="text_change_rejected"> + <description> + Emitted when trying to append text that would overflow the [member max_length]. + </description> + </signal> <signal name="text_entered"> <argument index="0" name="new_text" type="String"> </argument> diff --git a/doc/classes/MainLoop.xml b/doc/classes/MainLoop.xml index 9457800825..d5ca39e09a 100644 --- a/doc/classes/MainLoop.xml +++ b/doc/classes/MainLoop.xml @@ -174,7 +174,7 @@ <argument index="1" name="granted" type="bool"> </argument> <description> - Emitted when an user responds to permission request. + Emitted when a user responds to a permission request. </description> </signal> </signals> diff --git a/doc/classes/NinePatchRect.xml b/doc/classes/NinePatchRect.xml index 221a3c22c1..8935ac9d94 100644 --- a/doc/classes/NinePatchRect.xml +++ b/doc/classes/NinePatchRect.xml @@ -61,7 +61,7 @@ <signals> <signal name="texture_changed"> <description> - Fired when the node's texture changes. + Emitted when the node's texture changes. </description> </signal> </signals> diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 8ca202a411..0b43fd5ac0 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -314,7 +314,7 @@ void EditorData::copy_object_params(Object *p_object) { for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { - if (!(E->get().usage & PROPERTY_USAGE_EDITOR)) + if (!(E->get().usage & PROPERTY_USAGE_EDITOR) || E->get().name == "script" || E->get().name == "scripts") continue; PropertyData pd; diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index f5128103f3..7de6db7add 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -2329,7 +2329,11 @@ Error EditorSceneImporterGLTF::_parse_animations(GLTFState &state) { Array samplers = d["samplers"]; if (d.has("name")) { - animation.name = _sanitize_scene_name(d["name"]); + String name = d["name"]; + if (name.begins_with("loop") || name.ends_with("loop") || name.begins_with("cycle") || name.ends_with("cycle")) { + animation.loop = true; + } + animation.name = _sanitize_scene_name(name); } for (int j = 0; j < channels.size(); j++) { @@ -2735,6 +2739,10 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye animation.instance(); animation->set_name(name); + if (anim.loop) { + animation->set_loop(true); + } + float length = 0; for (Map<int, GLTFAnimation::Track>::Element *E = anim.tracks.front(); E; E = E->next()) { diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h index 4a91b99aa7..78d7106b0d 100644 --- a/editor/import/editor_scene_importer_gltf.h +++ b/editor/import/editor_scene_importer_gltf.h @@ -262,6 +262,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { }; struct GLTFAnimation { + bool loop = false; enum Interpolation { INTERP_LINEAR, diff --git a/modules/assimp/editor_scene_importer_assimp.cpp b/modules/assimp/editor_scene_importer_assimp.cpp index 1bc84ce3a0..726f4c1ed0 100644 --- a/modules/assimp/editor_scene_importer_assimp.cpp +++ b/modules/assimp/editor_scene_importer_assimp.cpp @@ -732,6 +732,10 @@ void EditorSceneImporterAssimp::_import_animation(ImportState &state, int p_anim animation->set_name(name); animation->set_length(anim->mDuration / ticks_per_second); + if (name.begins_with("loop") || name.ends_with("loop") || name.begins_with("cycle") || name.ends_with("cycle")) { + animation->set_loop(true); + } + // generate bone stack for animation import RegenerateBoneStack(state); diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index b4b38ac450..8f784dd943 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -680,7 +680,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { bool screen_support_large = p_preset->get("screen/support_large"); bool screen_support_xlarge = p_preset->get("screen/support_xlarge"); - int xr_mode_index = p_preset->get("graphics/xr_mode"); + int xr_mode_index = p_preset->get("xr_features/xr_mode"); Vector<String> perms; @@ -859,135 +859,174 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { uint32_t name = decode_uint32(&p_manifest[iofs + 12]); String tname = string_table[name]; - int dof_index = p_preset->get("graphics/degrees_of_freedom"); // 0: none, 1: 3dof and 6dof, 2: 6dof + if (tname == "uses-feature") { + Vector<String> feature_names; + Vector<bool> feature_required_list; + Vector<int> feature_versions; - if (tname == "uses-feature" && dof_index > 0) { - if (xr_mode_index == 0) { - WARN_PRINT("VR DOF feature setting is only valid for oculus HMDs with an XR mode set to VR"); + if (xr_mode_index == 1 /* XRMode.OVR */) { + // Check for degrees of freedom + int dof_index = p_preset->get("xr_features/degrees_of_freedom"); // 0: none, 1: 3dof and 6dof, 2: 6dof + + if (dof_index > 0) { + feature_names.push_back("android.hardware.vr.headtracking"); + feature_required_list.push_back(dof_index == 2); + feature_versions.push_back(1); + } + + // Check for hand tracking + int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required + if (hand_tracking_index > 0) { + feature_names.push_back("oculus.software.handtracking"); + feature_required_list.push_back(hand_tracking_index == 2); + feature_versions.push_back(-1); // no version attribute should be added. + + if (perms.find("oculus.permission.handtracking") == -1) { + perms.push_back("oculus.permission.handtracking"); + } + } } - ofs += 24; // skip over end tag - // save manifest ending so we can restore it - Vector<uint8_t> manifest_end; - uint32_t manifest_cur_size = p_manifest.size(); + if (feature_names.size() > 0) { + ofs += 24; // skip over end tag - manifest_end.resize(p_manifest.size() - ofs); - memcpy(manifest_end.ptrw(), &p_manifest[ofs], manifest_end.size()); + // save manifest ending so we can restore it + Vector<uint8_t> manifest_end; + uint32_t manifest_cur_size = p_manifest.size(); - int32_t attr_name_string = string_table.find("name"); - ERR_FAIL_COND_MSG(attr_name_string == -1, "Template does not have 'name' attribute."); + manifest_end.resize(p_manifest.size() - ofs); + memcpy(manifest_end.ptrw(), &p_manifest[ofs], manifest_end.size()); - int32_t ns_android_string = string_table.find("http://schemas.android.com/apk/res/android"); - if (ns_android_string == -1) { - string_table.push_back("http://schemas.android.com/apk/res/android"); - ns_android_string = string_table.size() - 1; - } + int32_t attr_name_string = string_table.find("name"); + ERR_FAIL_COND_MSG(attr_name_string == -1, "Template does not have 'name' attribute."); - int32_t attr_uses_feature_string = string_table.find("uses-feature"); - if (attr_uses_feature_string == -1) { - string_table.push_back("uses-feature"); - attr_uses_feature_string = string_table.size() - 1; - } + int32_t ns_android_string = string_table.find("http://schemas.android.com/apk/res/android"); + if (ns_android_string == -1) { + string_table.push_back("http://schemas.android.com/apk/res/android"); + ns_android_string = string_table.size() - 1; + } - int32_t attr_required_string = string_table.find("required"); - if (attr_required_string == -1) { - string_table.push_back("required"); - attr_required_string = string_table.size() - 1; - } + int32_t attr_uses_feature_string = string_table.find("uses-feature"); + if (attr_uses_feature_string == -1) { + string_table.push_back("uses-feature"); + attr_uses_feature_string = string_table.size() - 1; + } - int32_t attr_version_string = string_table.find("version"); - if (attr_version_string == -1) { - string_table.push_back("version"); - attr_version_string = string_table.size() - 1; - } + int32_t attr_required_string = string_table.find("required"); + if (attr_required_string == -1) { + string_table.push_back("required"); + attr_required_string = string_table.size() - 1; + } - String required_value_string; - if (dof_index == 1) { - required_value_string = "false"; - } else if (dof_index == 2) { - required_value_string = "true"; - } else { - ERR_FAIL_MSG("Unknown DoF index: " + itos(dof_index) + "."); - } - int32_t required_value = string_table.find(required_value_string); - if (required_value == -1) { - string_table.push_back(required_value_string); - required_value = string_table.size() - 1; - } + for (int i = 0; i < feature_names.size(); i++) { + String feature_name = feature_names[i]; + bool feature_required = feature_required_list[i]; + int feature_version = feature_versions[i]; + bool has_version_attribute = feature_version != -1; - int32_t version_value = string_table.find("1"); - if (version_value == -1) { - string_table.push_back("1"); - version_value = string_table.size() - 1; - } + print_line("Adding feature " + feature_name); - int32_t feature_string = string_table.find("android.hardware.vr.headtracking"); - if (feature_string == -1) { - string_table.push_back("android.hardware.vr.headtracking"); - feature_string = string_table.size() - 1; - } + int32_t feature_string = string_table.find(feature_name); + if (feature_string == -1) { + string_table.push_back(feature_name); + feature_string = string_table.size() - 1; + } - { - manifest_cur_size += 96 + 24; // node and three attrs + end node - p_manifest.resize(manifest_cur_size); + String required_value_string = feature_required ? "true" : "false"; + int32_t required_value = string_table.find(required_value_string); + if (required_value == -1) { + string_table.push_back(required_value_string); + required_value = string_table.size() - 1; + } - // start tag - encode_uint16(0x102, &p_manifest.write[ofs]); // type - encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize - encode_uint32(96, &p_manifest.write[ofs + 4]); // size - encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno - encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment - encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns - encode_uint32(attr_uses_feature_string, &p_manifest.write[ofs + 20]); // name - encode_uint16(20, &p_manifest.write[ofs + 24]); // attr_start - encode_uint16(20, &p_manifest.write[ofs + 26]); // attr_size - encode_uint16(3, &p_manifest.write[ofs + 28]); // num_attrs - encode_uint16(0, &p_manifest.write[ofs + 30]); // id_index - encode_uint16(0, &p_manifest.write[ofs + 32]); // class_index - encode_uint16(0, &p_manifest.write[ofs + 34]); // style_index + int32_t attr_version_string = -1; + int32_t version_value = -1; + int tag_size; + int attr_count; + if (has_version_attribute) { + attr_version_string = string_table.find("version"); + if (attr_version_string == -1) { + string_table.push_back("version"); + attr_version_string = string_table.size() - 1; + } - // android:name attribute - encode_uint32(ns_android_string, &p_manifest.write[ofs + 36]); // ns - encode_uint32(attr_name_string, &p_manifest.write[ofs + 40]); // 'name' - encode_uint32(feature_string, &p_manifest.write[ofs + 44]); // raw_value - encode_uint16(8, &p_manifest.write[ofs + 48]); // typedvalue_size - p_manifest.write[ofs + 50] = 0; // typedvalue_always0 - p_manifest.write[ofs + 51] = 0x03; // typedvalue_type (string) - encode_uint32(feature_string, &p_manifest.write[ofs + 52]); // typedvalue reference - - // android:required attribute - encode_uint32(ns_android_string, &p_manifest.write[ofs + 56]); // ns - encode_uint32(attr_required_string, &p_manifest.write[ofs + 60]); // 'name' - encode_uint32(required_value, &p_manifest.write[ofs + 64]); // raw_value - encode_uint16(8, &p_manifest.write[ofs + 68]); // typedvalue_size - p_manifest.write[ofs + 70] = 0; // typedvalue_always0 - p_manifest.write[ofs + 71] = 0x03; // typedvalue_type (string) - encode_uint32(required_value, &p_manifest.write[ofs + 72]); // typedvalue reference - - // android:version attribute - encode_uint32(ns_android_string, &p_manifest.write[ofs + 76]); // ns - encode_uint32(attr_version_string, &p_manifest.write[ofs + 80]); // 'name' - encode_uint32(version_value, &p_manifest.write[ofs + 84]); // raw_value - encode_uint16(8, &p_manifest.write[ofs + 88]); // typedvalue_size - p_manifest.write[ofs + 90] = 0; // typedvalue_always0 - p_manifest.write[ofs + 91] = 0x03; // typedvalue_type (string) - encode_uint32(version_value, &p_manifest.write[ofs + 92]); // typedvalue reference - - ofs += 96; + version_value = string_table.find(itos(feature_version)); + if (version_value == -1) { + string_table.push_back(itos(feature_version)); + version_value = string_table.size() - 1; + } - // end tag - encode_uint16(0x103, &p_manifest.write[ofs]); // type - encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize - encode_uint32(24, &p_manifest.write[ofs + 4]); // size - encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno - encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment - encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns - encode_uint32(attr_uses_feature_string, &p_manifest.write[ofs + 20]); // name + tag_size = 96; // node and three attrs + end node + attr_count = 3; + } else { + tag_size = 76; // node and two attrs + end node + attr_count = 2; + } + manifest_cur_size += tag_size + 24; + p_manifest.resize(manifest_cur_size); + + // start tag + encode_uint16(0x102, &p_manifest.write[ofs]); // type + encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize + encode_uint32(tag_size, &p_manifest.write[ofs + 4]); // size + encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno + encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment + encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns + encode_uint32(attr_uses_feature_string, &p_manifest.write[ofs + 20]); // name + encode_uint16(20, &p_manifest.write[ofs + 24]); // attr_start + encode_uint16(20, &p_manifest.write[ofs + 26]); // attr_size + encode_uint16(attr_count, &p_manifest.write[ofs + 28]); // num_attrs + encode_uint16(0, &p_manifest.write[ofs + 30]); // id_index + encode_uint16(0, &p_manifest.write[ofs + 32]); // class_index + encode_uint16(0, &p_manifest.write[ofs + 34]); // style_index + + // android:name attribute + encode_uint32(ns_android_string, &p_manifest.write[ofs + 36]); // ns + encode_uint32(attr_name_string, &p_manifest.write[ofs + 40]); // 'name' + encode_uint32(feature_string, &p_manifest.write[ofs + 44]); // raw_value + encode_uint16(8, &p_manifest.write[ofs + 48]); // typedvalue_size + p_manifest.write[ofs + 50] = 0; // typedvalue_always0 + p_manifest.write[ofs + 51] = 0x03; // typedvalue_type (string) + encode_uint32(feature_string, &p_manifest.write[ofs + 52]); // typedvalue reference + + // android:required attribute + encode_uint32(ns_android_string, &p_manifest.write[ofs + 56]); // ns + encode_uint32(attr_required_string, &p_manifest.write[ofs + 60]); // 'name' + encode_uint32(required_value, &p_manifest.write[ofs + 64]); // raw_value + encode_uint16(8, &p_manifest.write[ofs + 68]); // typedvalue_size + p_manifest.write[ofs + 70] = 0; // typedvalue_always0 + p_manifest.write[ofs + 71] = 0x03; // typedvalue_type (string) + encode_uint32(required_value, &p_manifest.write[ofs + 72]); // typedvalue reference + + ofs += 76; + + if (has_version_attribute) { + // android:version attribute + encode_uint32(ns_android_string, &p_manifest.write[ofs]); // ns + encode_uint32(attr_version_string, &p_manifest.write[ofs + 4]); // 'name' + encode_uint32(version_value, &p_manifest.write[ofs + 8]); // raw_value + encode_uint16(8, &p_manifest.write[ofs + 12]); // typedvalue_size + p_manifest.write[ofs + 14] = 0; // typedvalue_always0 + p_manifest.write[ofs + 15] = 0x03; // typedvalue_type (string) + encode_uint32(version_value, &p_manifest.write[ofs + 16]); // typedvalue reference + + ofs += 20; + } - ofs += 24; + // end tag + encode_uint16(0x103, &p_manifest.write[ofs]); // type + encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize + encode_uint32(24, &p_manifest.write[ofs + 4]); // size + encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno + encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment + encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns + encode_uint32(attr_uses_feature_string, &p_manifest.write[ofs + 20]); // name + + ofs += 24; + } + memcpy(&p_manifest.write[ofs], manifest_end.ptr(), manifest_end.size()); + ofs -= 24; // go back over back end } - memcpy(&p_manifest.write[ofs], manifest_end.ptr(), manifest_end.size()); - ofs -= 24; // go back over back end } if (tname == "manifest") { @@ -1295,9 +1334,10 @@ public: virtual void get_export_options(List<ExportOption> *r_options) { - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "graphics/xr_mode", PROPERTY_HINT_ENUM, "Regular,Oculus Mobile VR"), 0)); - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "graphics/degrees_of_freedom", PROPERTY_HINT_ENUM, "None,3DOF and 6DOF,6DOF"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/32_bits_framebuffer"), true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/xr_mode", PROPERTY_HINT_ENUM, "Regular,Oculus Mobile VR"), 0)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/degrees_of_freedom", PROPERTY_HINT_ENUM, "None,3DOF and 6DOF,6DOF"), 0)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/hand_tracking", PROPERTY_HINT_ENUM, "None,Optional,Required"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); @@ -2264,7 +2304,7 @@ public: } } - int xr_mode_index = p_preset->get("graphics/xr_mode"); + int xr_mode_index = p_preset->get("xr_features/xr_mode"); if (xr_mode_index == 1 /* XRMode.OVR */) { cl.push_back("--xr_mode_ovr"); } else { diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 8f5f6beac3..5351b6cadc 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -557,8 +557,11 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { if (editable) { selection_delete(); CharType ucodestr[2] = { (CharType)k->get_unicode(), 0 }; + int prev_len = text.length(); append_at_cursor(ucodestr); - _text_changed(); + if (text.length() != prev_len) { + _text_changed(); + } accept_event(); } @@ -961,11 +964,12 @@ void LineEdit::paste_text() { if (paste_buffer != "") { + int prev_len = text.length(); if (selection.enabled) selection_delete(); append_at_cursor(paste_buffer); if (!text_changed_dirty) { - if (is_inside_tree()) { + if (is_inside_tree() && text.length() != prev_len) { MessageQueue::get_singleton()->push_call(this, "_text_changed"); } text_changed_dirty = true; @@ -1362,6 +1366,8 @@ void LineEdit::append_at_cursor(String p_text) { String post = text.substr(cursor_pos, text.length() - cursor_pos); text = pre + p_text + post; set_cursor_position(cursor_pos + p_text.length()); + } else { + emit_signal("text_change_rejected"); } } @@ -1781,6 +1787,7 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_right_icon"), &LineEdit::get_right_icon); ADD_SIGNAL(MethodInfo("text_changed", PropertyInfo(Variant::STRING, "new_text"))); + ADD_SIGNAL(MethodInfo("text_change_rejected")); ADD_SIGNAL(MethodInfo("text_entered", PropertyInfo(Variant::STRING, "new_text"))); BIND_ENUM_CONSTANT(ALIGN_LEFT); |