summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorRaul Santos <raulsntos@gmail.com>2022-03-06 18:04:29 +0100
committerRaul Santos <raulsntos@gmail.com>2022-06-03 05:19:01 +0200
commit329818f20b455bd5026878ee4ed15df4d50abc62 (patch)
tree89bee7b1fbddcf407dc1d358b03980143d93b48f /modules
parent1baee2189c21ae36c852ddff10f769b1134509ca (diff)
Support explicit values in flag properties, add C# flags support
- Add support for explicit values in properties using `PROPERTY_HINT_FLAGS` that works the same way it does for enums. - Fix enums and flags in VisualScriptEditor (it wasn't considering the explicit value). - Use `PROPERTY_HINT_FLAGS` for C# enums with the FlagsAttribute instead of `PROPERTY_HINT_ENUM`.
Diffstat (limited to 'modules')
-rw-r--r--modules/mono/csharp_script.cpp6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs5
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.cpp2
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h1
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp8
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h1
-rw-r--r--modules/visual_script/editor/visual_script_editor.cpp44
7 files changed, 64 insertions, 3 deletions
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index bee4e0e1fb..622838b308 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -2807,7 +2807,8 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
GD_MONO_ASSERT_THREAD_ATTACHED;
if (p_variant_type == Variant::INT && p_type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(p_type.type_class->get_mono_ptr())) {
- r_hint = PROPERTY_HINT_ENUM;
+ MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
+ r_hint = GDMonoUtils::Marshal::type_has_flags_attribute(reftype) ? PROPERTY_HINT_FLAGS : PROPERTY_HINT_ENUM;
Vector<MonoClassField *> fields = p_type.type_class->get_enum_fields();
@@ -2844,7 +2845,8 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
uint64_t val = GDMonoUtils::unbox_enum_value(val_obj, enum_basetype, r_error);
ERR_FAIL_COND_V_MSG(r_error, -1, "Failed to unbox '" + enum_field_name + "' constant enum value.");
- if (val != (unsigned int)i) {
+ unsigned int expected_val = r_hint == PROPERTY_HINT_FLAGS ? 1 << i : i;
+ if (val != expected_val) {
uses_default_values = false;
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
index ee4d0eed08..50ae2eb112 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
@@ -80,6 +80,11 @@ namespace Godot
private static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>);
/// <summary>
+ /// Returns <see langword="true"/> if the <see cref="FlagsAttribute"/> is applied to the given type.
+ /// </summary>
+ private static bool TypeHasFlagsAttribute(Type type) => type.IsDefined(typeof(FlagsAttribute), false);
+
+ /// <summary>
/// Returns the generic type definition of <paramref name="type"/>.
/// </summary>
/// <exception cref="InvalidOperationException">
diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp
index d8fd244067..44a8e26b8f 100644
--- a/modules/mono/mono_gd/gd_mono_cache.cpp
+++ b/modules/mono/mono_gd/gd_mono_cache.cpp
@@ -176,6 +176,7 @@ void CachedData::clear_godot_api_cache() {
methodthunk_MarshalUtils_TypeIsGenericIEnumerable.nullify();
methodthunk_MarshalUtils_TypeIsGenericICollection.nullify();
methodthunk_MarshalUtils_TypeIsGenericIDictionary.nullify();
+ methodthunk_MarshalUtils_TypeHasFlagsAttribute.nullify();
methodthunk_MarshalUtils_GetGenericTypeDefinition.nullify();
@@ -300,6 +301,7 @@ void update_godot_api_cache() {
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIEnumerable, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIEnumerable", 1));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericICollection, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericICollection", 1));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIDictionary", 1));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeHasFlagsAttribute, GODOT_API_CLASS(MarshalUtils)->get_method("TypeHasFlagsAttribute", 1));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GetGenericTypeDefinition, GODOT_API_CLASS(MarshalUtils)->get_method("GetGenericTypeDefinition", 2));
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index 4000342c94..92136e1f41 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -147,6 +147,7 @@ struct CachedData {
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIEnumerable;
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericICollection;
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIDictionary;
+ GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeHasFlagsAttribute;
GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_GetGenericTypeDefinition;
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index 25678be624..1983d6ebe2 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -614,6 +614,14 @@ bool type_is_generic_idictionary(MonoReflectionType *p_reftype) {
return (bool)res;
}
+bool type_has_flags_attribute(MonoReflectionType *p_reftype) {
+ NO_GLUE_RET(false);
+ MonoException *exc = nullptr;
+ MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeHasFlagsAttribute).invoke(p_reftype, &exc);
+ UNHANDLED_EXCEPTION(exc);
+ return (bool)res;
+}
+
void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype) {
MonoException *exc = nullptr;
CACHED_METHOD_THUNK(MarshalUtils, GetGenericTypeDefinition).invoke(p_reftype, r_generic_reftype, &exc);
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index 4c2c2c93c2..246a1cd31e 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -61,6 +61,7 @@ bool type_is_system_generic_dictionary(MonoReflectionType *p_reftype);
bool type_is_generic_ienumerable(MonoReflectionType *p_reftype);
bool type_is_generic_icollection(MonoReflectionType *p_reftype);
bool type_is_generic_idictionary(MonoReflectionType *p_reftype);
+bool type_has_flags_attribute(MonoReflectionType *p_reftype);
void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype);
diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp
index 684faf7c8e..4741c7f887 100644
--- a/modules/visual_script/editor/visual_script_editor.cpp
+++ b/modules/visual_script/editor/visual_script_editor.cpp
@@ -889,7 +889,49 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
EditorResourcePreview::get_singleton()->queue_edited_resource_preview(res, this, "_button_resource_previewed", arr);
} else if (pi.type == Variant::INT && pi.hint == PROPERTY_HINT_ENUM) {
- button->set_text(pi.hint_string.get_slice(",", value));
+ bool found = false;
+ const Vector<String> options = pi.hint_string.split(",");
+ int64_t current_val = 0;
+ for (const String &option : options) {
+ Vector<String> text_split = option.split(":");
+ if (text_split.size() != 1) {
+ current_val = text_split[1].to_int();
+ }
+ if (value.operator int() == current_val) {
+ button->set_text(text_split[0]);
+ found = true;
+ break;
+ }
+ current_val += 1;
+ }
+ if (!found) {
+ button->set_text(value);
+ }
+ } else if (pi.type == Variant::INT && pi.hint == PROPERTY_HINT_FLAGS) {
+ Vector<String> value_texts;
+ const Vector<String> options = pi.hint_string.split(",");
+ uint32_t v = value;
+ for (const String &option : options) {
+ uint32_t current_val;
+ Vector<String> text_split = option.split(":");
+ if (text_split.size() != -1) {
+ current_val = text_split[1].to_int();
+ } else {
+ current_val = 1 << i;
+ }
+ if ((v & current_val) == current_val) {
+ value_texts.push_back(text_split[0]);
+ }
+ }
+ if (value_texts.size() != 0) {
+ String value_text = value_texts[0];
+ for (const String &text : value_texts) {
+ value_text += " | " + text;
+ }
+ button->set_text(value_text);
+ } else {
+ button->set_text(value);
+ }
} else {
button->set_text(value);
}