Merge pull request #59328 from raulsntos/csharp-flag-enums-3.x
This commit is contained in:
commit
1b7037807f
10 changed files with 101 additions and 36 deletions
|
@ -628,14 +628,12 @@ EditorPropertyEnum::EditorPropertyEnum() {
|
||||||
|
|
||||||
///////////////////// FLAGS /////////////////////////
|
///////////////////// FLAGS /////////////////////////
|
||||||
|
|
||||||
void EditorPropertyFlags::_flag_toggled() {
|
void EditorPropertyFlags::_flag_toggled(int p_index) {
|
||||||
uint32_t value = 0;
|
uint32_t value = get_edited_object()->get(get_edited_property());
|
||||||
for (int i = 0; i < flags.size(); i++) {
|
if (flags[p_index]->is_pressed()) {
|
||||||
if (flags[i]->is_pressed()) {
|
value |= flag_values[p_index];
|
||||||
uint32_t val = 1;
|
} else {
|
||||||
val <<= flag_indices[i];
|
value &= ~flag_values[p_index];
|
||||||
value |= val;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emit_changed(get_edited_property(), value);
|
emit_changed(get_edited_property(), value);
|
||||||
|
@ -645,13 +643,7 @@ void EditorPropertyFlags::update_property() {
|
||||||
uint32_t value = get_edited_object()->get(get_edited_property());
|
uint32_t value = get_edited_object()->get(get_edited_property());
|
||||||
|
|
||||||
for (int i = 0; i < flags.size(); i++) {
|
for (int i = 0; i < flags.size(); i++) {
|
||||||
uint32_t val = 1;
|
flags[i]->set_pressed((value & flag_values[i]) == flag_values[i]);
|
||||||
val <<= flag_indices[i];
|
|
||||||
if (value & val) {
|
|
||||||
flags[i]->set_pressed(true);
|
|
||||||
} else {
|
|
||||||
flags[i]->set_pressed(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -659,17 +651,24 @@ void EditorPropertyFlags::setup(const Vector<String> &p_options) {
|
||||||
ERR_FAIL_COND(flags.size());
|
ERR_FAIL_COND(flags.size());
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
uint32_t current_val;
|
||||||
for (int i = 0; i < p_options.size(); i++) {
|
for (int i = 0; i < p_options.size(); i++) {
|
||||||
String option = p_options[i].strip_edges();
|
String option = p_options[i].strip_edges();
|
||||||
if (option != "") {
|
if (option != "") {
|
||||||
CheckBox *cb = memnew(CheckBox);
|
CheckBox *cb = memnew(CheckBox);
|
||||||
cb->set_text(option);
|
cb->set_text(option);
|
||||||
cb->set_clip_text(true);
|
cb->set_clip_text(true);
|
||||||
cb->connect("pressed", this, "_flag_toggled");
|
cb->connect("pressed", this, "_flag_toggled", varray(i));
|
||||||
add_focusable(cb);
|
add_focusable(cb);
|
||||||
vbox->add_child(cb);
|
vbox->add_child(cb);
|
||||||
flags.push_back(cb);
|
flags.push_back(cb);
|
||||||
flag_indices.push_back(i);
|
Vector<String> text_split = p_options[i].split(":");
|
||||||
|
if (text_split.size() != 1) {
|
||||||
|
current_val = text_split[1].to_int();
|
||||||
|
} else {
|
||||||
|
current_val = 1 << i;
|
||||||
|
}
|
||||||
|
flag_values.push_back(current_val);
|
||||||
if (first) {
|
if (first) {
|
||||||
set_label_reference(cb);
|
set_label_reference(cb);
|
||||||
first = false;
|
first = false;
|
||||||
|
|
|
@ -234,9 +234,9 @@ class EditorPropertyFlags : public EditorProperty {
|
||||||
GDCLASS(EditorPropertyFlags, EditorProperty);
|
GDCLASS(EditorPropertyFlags, EditorProperty);
|
||||||
VBoxContainer *vbox;
|
VBoxContainer *vbox;
|
||||||
Vector<CheckBox *> flags;
|
Vector<CheckBox *> flags;
|
||||||
Vector<int> flag_indices;
|
Vector<uint32_t> flag_values;
|
||||||
|
|
||||||
void _flag_toggled();
|
void _flag_toggled(int p_index);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
|
@ -114,15 +114,16 @@ void CustomPropertyEditor::_menu_option(int p_which) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Variant::INT: {
|
case Variant::INT: {
|
||||||
if (hint == PROPERTY_HINT_FLAGS) {
|
if (hint == PROPERTY_HINT_FLAGS) {
|
||||||
int val = v;
|
int idx = menu->get_item_index(p_which);
|
||||||
|
uint32_t item_value = menu->get_item_metadata(idx);
|
||||||
if (val & (1 << p_which)) {
|
uint32_t value = v;
|
||||||
val &= ~(1 << p_which);
|
// If the item wasn't previously checked it means it was pressed,
|
||||||
|
// otherwise it was unpressed.
|
||||||
|
if (!menu->is_item_checked(idx)) {
|
||||||
|
v = value | item_value;
|
||||||
} else {
|
} else {
|
||||||
val |= (1 << p_which);
|
v = value & ~item_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
v = val;
|
|
||||||
emit_signal("variant_changed");
|
emit_signal("variant_changed");
|
||||||
} else if (hint == PROPERTY_HINT_ENUM) {
|
} else if (hint == PROPERTY_HINT_ENUM) {
|
||||||
v = menu->get_item_metadata(p_which);
|
v = menu->get_item_metadata(p_which);
|
||||||
|
@ -488,15 +489,19 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
|
||||||
set_size(Size2(200, 150) * EDSCALE);
|
set_size(Size2(200, 150) * EDSCALE);
|
||||||
} else if (hint == PROPERTY_HINT_FLAGS) {
|
} else if (hint == PROPERTY_HINT_FLAGS) {
|
||||||
Vector<String> flags = hint_text.split(",");
|
Vector<String> flags = hint_text.split(",");
|
||||||
|
uint32_t value = v;
|
||||||
for (int i = 0; i < flags.size(); i++) {
|
for (int i = 0; i < flags.size(); i++) {
|
||||||
String flag = flags[i];
|
uint32_t current_val;
|
||||||
if (flag == "") {
|
Vector<String> text_split = flags[i].split(":");
|
||||||
continue;
|
if (text_split.size() != 1) {
|
||||||
|
current_val = text_split[1].to_int();
|
||||||
|
} else {
|
||||||
|
current_val = 1 << i;
|
||||||
}
|
}
|
||||||
menu->add_check_item(flag, i);
|
menu->add_check_item(text_split[0], current_val);
|
||||||
int f = v;
|
menu->set_item_metadata(i, current_val);
|
||||||
if (f & (1 << i)) {
|
if ((value & current_val) == current_val) {
|
||||||
menu->set_item_checked(menu->get_item_index(i), true);
|
menu->set_item_checked(menu->get_item_index(current_val), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
menu->set_position(get_position());
|
menu->set_position(get_position());
|
||||||
|
|
|
@ -2618,7 +2618,8 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
|
||||||
GD_MONO_ASSERT_THREAD_ATTACHED;
|
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())) {
|
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();
|
Vector<MonoClassField *> fields = p_type.type_class->get_enum_fields();
|
||||||
|
|
||||||
|
@ -2655,7 +2656,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);
|
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.");
|
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;
|
uses_default_values = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,11 @@ namespace Godot
|
||||||
/// </exception>
|
/// </exception>
|
||||||
private static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>);
|
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>
|
/// <summary>
|
||||||
/// Returns the generic type definition of <paramref name="type"/>.
|
/// Returns the generic type definition of <paramref name="type"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -166,6 +166,7 @@ void CachedData::clear_godot_api_cache() {
|
||||||
methodthunk_MarshalUtils_TypeIsGenericIEnumerable.nullify();
|
methodthunk_MarshalUtils_TypeIsGenericIEnumerable.nullify();
|
||||||
methodthunk_MarshalUtils_TypeIsGenericICollection.nullify();
|
methodthunk_MarshalUtils_TypeIsGenericICollection.nullify();
|
||||||
methodthunk_MarshalUtils_TypeIsGenericIDictionary.nullify();
|
methodthunk_MarshalUtils_TypeIsGenericIDictionary.nullify();
|
||||||
|
methodthunk_MarshalUtils_TypeHasFlagsAttribute.nullify();
|
||||||
|
|
||||||
methodthunk_MarshalUtils_GetGenericTypeDefinition.nullify();
|
methodthunk_MarshalUtils_GetGenericTypeDefinition.nullify();
|
||||||
|
|
||||||
|
@ -280,6 +281,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, 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, 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, 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));
|
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GetGenericTypeDefinition, GODOT_API_CLASS(MarshalUtils)->get_method("GetGenericTypeDefinition", 2));
|
||||||
|
|
||||||
|
|
|
@ -137,6 +137,7 @@ struct CachedData {
|
||||||
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIEnumerable;
|
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIEnumerable;
|
||||||
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericICollection;
|
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericICollection;
|
||||||
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIDictionary;
|
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIDictionary;
|
||||||
|
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeHasFlagsAttribute;
|
||||||
|
|
||||||
GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_GetGenericTypeDefinition;
|
GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_GetGenericTypeDefinition;
|
||||||
|
|
||||||
|
|
|
@ -587,6 +587,14 @@ bool type_is_generic_idictionary(MonoReflectionType *p_reftype) {
|
||||||
return (bool)res;
|
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) {
|
void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype) {
|
||||||
MonoException *exc = nullptr;
|
MonoException *exc = nullptr;
|
||||||
CACHED_METHOD_THUNK(MarshalUtils, GetGenericTypeDefinition).invoke(p_reftype, r_generic_reftype, &exc);
|
CACHED_METHOD_THUNK(MarshalUtils, GetGenericTypeDefinition).invoke(p_reftype, r_generic_reftype, &exc);
|
||||||
|
|
|
@ -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_ienumerable(MonoReflectionType *p_reftype);
|
||||||
bool type_is_generic_icollection(MonoReflectionType *p_reftype);
|
bool type_is_generic_icollection(MonoReflectionType *p_reftype);
|
||||||
bool type_is_generic_idictionary(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);
|
void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype);
|
||||||
|
|
||||||
|
|
|
@ -869,7 +869,49 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
|
||||||
EditorResourcePreview::get_singleton()->queue_edited_resource_preview(res, this, "_button_resource_previewed", arr);
|
EditorResourcePreview::get_singleton()->queue_edited_resource_preview(res, this, "_button_resource_previewed", arr);
|
||||||
|
|
||||||
} else if (pi.type == Variant::INT && pi.hint == PROPERTY_HINT_ENUM) {
|
} else if (pi.type == Variant::INT && pi.hint == PROPERTY_HINT_ENUM) {
|
||||||
button->set_text(pi.hint_string.get_slice(",", value));
|
bool found = false;
|
||||||
|
Vector<String> options = pi.hint_string.split(",");
|
||||||
|
int64_t current_val = 0;
|
||||||
|
for (int j = 0; j < options.size(); j++) {
|
||||||
|
const Vector<String> text_split = options[j].split(":");
|
||||||
|
if (text_split.size() != 1) {
|
||||||
|
current_val = text_split[1].to_int64();
|
||||||
|
}
|
||||||
|
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 (int j = 0; j < options.size(); j++) {
|
||||||
|
uint32_t current_val;
|
||||||
|
Vector<String> text_split = options[j].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 (int j = 1; j < value_texts.size(); j++) {
|
||||||
|
value_text += " | " + value_texts[j];
|
||||||
|
}
|
||||||
|
button->set_text(value_text);
|
||||||
|
} else {
|
||||||
|
button->set_text(value);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
button->set_text(value);
|
button->set_text(value);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue