diff options
author | reduz <reduzio@gmail.com> | 2022-06-24 11:16:37 +0200 |
---|---|---|
committer | RĂ©mi Verschelde <rverschelde@gmail.com> | 2022-07-05 22:13:37 +0200 |
commit | 5ac42cf5766cd60a9c41bdd6045c8ccfd35d62c1 (patch) | |
tree | e45f9babe2ca97b620aabb0e0ac3ae4bbaae492a | |
parent | 9de5698ee21c2e834eec9b39c2f9e1492ff018d4 (diff) |
Implement a BitField hint
Allows to specify the binder that an enum must be treated as a bitfield.
-rw-r--r-- | core/core_bind.cpp | 18 | ||||
-rw-r--r-- | core/core_bind.h | 4 | ||||
-rw-r--r-- | core/doc_data.cpp | 4 | ||||
-rw-r--r-- | core/doc_data.h | 2 | ||||
-rw-r--r-- | core/extension/extension_api_dump.cpp | 3 | ||||
-rw-r--r-- | core/object/class_db.cpp | 41 | ||||
-rw-r--r-- | core/object/class_db.h | 17 | ||||
-rw-r--r-- | core/object/object.h | 1 | ||||
-rw-r--r-- | core/variant/binder_common.h | 23 | ||||
-rw-r--r-- | core/variant/type_info.h | 45 | ||||
-rw-r--r-- | doc/class.xsd | 1 | ||||
-rw-r--r-- | doc/classes/ResourceSaver.xml | 18 | ||||
-rwxr-xr-x | doc/tools/make_rst.py | 17 | ||||
-rw-r--r-- | editor/doc_tools.cpp | 12 | ||||
-rw-r--r-- | editor/editor_help.cpp | 6 | ||||
-rw-r--r-- | modules/gdscript/gdscript_editor.cpp | 6 | ||||
-rw-r--r-- | modules/mono/editor/bindings_generator.cpp | 12 | ||||
-rw-r--r-- | tests/core/object/test_class_db.h | 12 |
18 files changed, 184 insertions, 58 deletions
diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 24b27d2692..26ecd41353 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -147,7 +147,7 @@ void ResourceLoader::_bind_methods() { ////// ResourceSaver ////// -Error ResourceSaver::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) { +Error ResourceSaver::save(const String &p_path, const Ref<Resource> &p_resource, BitField<SaverFlags> p_flags) { ERR_FAIL_COND_V_MSG(p_resource.is_null(), ERR_INVALID_PARAMETER, "Can't save empty resource to path '" + String(p_path) + "'."); return ::ResourceSaver::save(p_path, p_resource, p_flags); } @@ -179,14 +179,14 @@ void ResourceSaver::_bind_methods() { ClassDB::bind_method(D_METHOD("add_resource_format_saver", "format_saver", "at_front"), &ResourceSaver::add_resource_format_saver, DEFVAL(false)); ClassDB::bind_method(D_METHOD("remove_resource_format_saver", "format_saver"), &ResourceSaver::remove_resource_format_saver); - BIND_ENUM_CONSTANT(FLAG_NONE); - BIND_ENUM_CONSTANT(FLAG_RELATIVE_PATHS); - BIND_ENUM_CONSTANT(FLAG_BUNDLE_RESOURCES); - BIND_ENUM_CONSTANT(FLAG_CHANGE_PATH); - BIND_ENUM_CONSTANT(FLAG_OMIT_EDITOR_PROPERTIES); - BIND_ENUM_CONSTANT(FLAG_SAVE_BIG_ENDIAN); - BIND_ENUM_CONSTANT(FLAG_COMPRESS); - BIND_ENUM_CONSTANT(FLAG_REPLACE_SUBRESOURCE_PATHS); + BIND_BITFIELD_FLAG(FLAG_NONE); + BIND_BITFIELD_FLAG(FLAG_RELATIVE_PATHS); + BIND_BITFIELD_FLAG(FLAG_BUNDLE_RESOURCES); + BIND_BITFIELD_FLAG(FLAG_CHANGE_PATH); + BIND_BITFIELD_FLAG(FLAG_OMIT_EDITOR_PROPERTIES); + BIND_BITFIELD_FLAG(FLAG_SAVE_BIG_ENDIAN); + BIND_BITFIELD_FLAG(FLAG_COMPRESS); + BIND_BITFIELD_FLAG(FLAG_REPLACE_SUBRESOURCE_PATHS); } ////// OS ////// diff --git a/core/core_bind.h b/core/core_bind.h index 99e14a75f5..c116ac4986 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -109,7 +109,7 @@ public: static ResourceSaver *get_singleton() { return singleton; } - Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags); + Error save(const String &p_path, const Ref<Resource> &p_resource, BitField<SaverFlags> p_flags); Vector<String> get_recognized_extensions(const Ref<Resource> &p_resource); void add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front); void remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver); @@ -719,7 +719,7 @@ public: VARIANT_ENUM_CAST(core_bind::ResourceLoader::ThreadLoadStatus); VARIANT_ENUM_CAST(core_bind::ResourceLoader::CacheMode); -VARIANT_ENUM_CAST(core_bind::ResourceSaver::SaverFlags); +VARIANT_BITFIELD_CAST(core_bind::ResourceSaver::SaverFlags); VARIANT_ENUM_CAST(core_bind::OS::VideoDriver); VARIANT_ENUM_CAST(core_bind::OS::Weekday); diff --git a/core/doc_data.cpp b/core/doc_data.cpp index 1e72ad1090..89e7a8dc71 100644 --- a/core/doc_data.cpp +++ b/core/doc_data.cpp @@ -38,7 +38,7 @@ void DocData::return_doc_from_retinfo(DocData::MethodDoc &p_method, const Proper } else { p_method.return_type += "*"; } - } else if (p_retinfo.type == Variant::INT && p_retinfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + } else if (p_retinfo.type == Variant::INT && p_retinfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { p_method.return_enum = p_retinfo.class_name; if (p_method.return_enum.begins_with("_")) { //proxy class p_method.return_enum = p_method.return_enum.substr(1, p_method.return_enum.length()); @@ -69,7 +69,7 @@ void DocData::argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const } else { p_argument.type += "*"; } - } else if (p_arginfo.type == Variant::INT && p_arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + } else if (p_arginfo.type == Variant::INT && p_arginfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { p_argument.enumeration = p_arginfo.class_name; if (p_argument.enumeration.begins_with("_")) { //proxy class p_argument.enumeration = p_argument.enumeration.substr(1, p_argument.enumeration.length()); diff --git a/core/doc_data.h b/core/doc_data.h index af20b717d7..6fd01b0c52 100644 --- a/core/doc_data.h +++ b/core/doc_data.h @@ -103,6 +103,7 @@ public: String value; bool is_value_valid = false; String enumeration; + bool is_bitfield = false; String description; bool operator<(const ConstantDoc &p_const) const { return name < p_const.name; @@ -111,6 +112,7 @@ public: struct EnumDoc { String name = "@unnamed_enum"; + bool is_bitfield = false; String description; Vector<DocData::ConstantDoc> values; }; diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp index 9d846f87c2..d5c49b01e9 100644 --- a/core/extension/extension_api_dump.cpp +++ b/core/extension/extension_api_dump.cpp @@ -46,7 +46,7 @@ static String get_type_name(const PropertyInfo &p_info) { return p_info.hint_string + "*"; } } - if (p_info.type == Variant::INT && (p_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM)) { + if (p_info.type == Variant::INT && (p_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD))) { return String("enum::") + String(p_info.class_name); } if (p_info.class_name != StringName()) { @@ -665,6 +665,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() { for (const StringName &F : enum_list) { Dictionary d2; d2["name"] = String(F); + d2["is_bitfield"] = ClassDB::is_enum_bitfield(class_name, F); Array values; List<StringName> enum_constant_list; diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index 3c9f373d12..ac008dad88 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -536,7 +536,7 @@ MethodBind *ClassDB::get_method(const StringName &p_class, const StringName &p_n return nullptr; } -void ClassDB::bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int64_t p_constant) { +void ClassDB::bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int64_t p_constant, bool p_is_bitfield) { OBJTYPE_WLOCK; ClassInfo *type = classes.getptr(p_class); @@ -555,13 +555,15 @@ void ClassDB::bind_integer_constant(const StringName &p_class, const StringName enum_name = enum_name.get_slicec('.', 1); } - List<StringName> *constants_list = type->enum_map.getptr(enum_name); + ClassInfo::EnumInfo *constants_list = type->enum_map.getptr(enum_name); if (constants_list) { - constants_list->push_back(p_name); + constants_list->constants.push_back(p_name); + constants_list->is_bitfield = p_is_bitfield; } else { - List<StringName> new_list; - new_list.push_back(p_name); + ClassInfo::EnumInfo new_list; + new_list.is_bitfield = p_is_bitfield; + new_list.constants.push_back(p_name); type->enum_map[enum_name] = new_list; } } @@ -645,8 +647,8 @@ StringName ClassDB::get_integer_constant_enum(const StringName &p_class, const S ClassInfo *type = classes.getptr(p_class); while (type) { - for (KeyValue<StringName, List<StringName>> &E : type->enum_map) { - List<StringName> &constants_list = E.value; + for (KeyValue<StringName, ClassInfo::EnumInfo> &E : type->enum_map) { + List<StringName> &constants_list = E.value.constants; const List<StringName>::Element *found = constants_list.find(p_name); if (found) { return E.key; @@ -669,7 +671,7 @@ void ClassDB::get_enum_list(const StringName &p_class, List<StringName> *p_enums ClassInfo *type = classes.getptr(p_class); while (type) { - for (KeyValue<StringName, List<StringName>> &E : type->enum_map) { + for (KeyValue<StringName, ClassInfo::EnumInfo> &E : type->enum_map) { p_enums->push_back(E.key); } @@ -687,10 +689,10 @@ void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_ ClassInfo *type = classes.getptr(p_class); while (type) { - const List<StringName> *constants = type->enum_map.getptr(p_enum); + const ClassInfo::EnumInfo *constants = type->enum_map.getptr(p_enum); if (constants) { - for (const List<StringName>::Element *E = constants->front(); E; E = E->next()) { + for (const List<StringName>::Element *E = constants->constants.front(); E; E = E->next()) { p_constants->push_back(E->get()); } } @@ -748,6 +750,25 @@ bool ClassDB::has_enum(const StringName &p_class, const StringName &p_name, bool return false; } +bool ClassDB::is_enum_bitfield(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) { + OBJTYPE_RLOCK; + + ClassInfo *type = classes.getptr(p_class); + + while (type) { + if (type->enum_map.has(p_name) && type->enum_map[p_name].is_bitfield) { + return true; + } + if (p_no_inheritance) { + return false; + } + + type = type->inherits_ptr; + } + + return false; +} + void ClassDB::add_signal(const StringName &p_class, const MethodInfo &p_signal) { OBJTYPE_WLOCK; diff --git a/core/object/class_db.h b/core/object/class_db.h index f2f73dc674..1d26eb18f1 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -104,7 +104,12 @@ public: HashMap<StringName, MethodBind *> method_map; HashMap<StringName, int64_t> constant_map; - HashMap<StringName, List<StringName>> enum_map; + struct EnumInfo { + List<StringName> constants; + bool is_bitfield = false; + }; + + HashMap<StringName, EnumInfo> enum_map; HashMap<StringName, MethodInfo> signal_map; List<PropertyInfo> property_list; HashMap<StringName, PropertyInfo> property_map; @@ -325,15 +330,17 @@ public: static void add_virtual_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual = true, const Vector<String> &p_arg_names = Vector<String>(), bool p_object_core = false); static void get_virtual_methods(const StringName &p_class, List<MethodInfo> *p_methods, bool p_no_inheritance = false); - static void bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int64_t p_constant); + static void bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int64_t p_constant, bool p_is_bitfield = false); static void get_integer_constant_list(const StringName &p_class, List<String> *p_constants, bool p_no_inheritance = false); static int64_t get_integer_constant(const StringName &p_class, const StringName &p_name, bool *p_success = nullptr); static bool has_integer_constant(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false); static StringName get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false); + static StringName get_integer_constant_bitfield(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false); static void get_enum_list(const StringName &p_class, List<StringName> *p_enums, bool p_no_inheritance = false); static void get_enum_constants(const StringName &p_class, const StringName &p_enum, List<StringName> *p_constants, bool p_no_inheritance = false); static bool has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false); + static bool is_enum_bitfield(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false); static void set_method_error_return_values(const StringName &p_class, const StringName &p_method, const Vector<Error> &p_values); static Vector<Error> get_method_error_return_values(const StringName &p_class, const StringName &p_method); @@ -370,6 +377,9 @@ public: #define BIND_ENUM_CONSTANT(m_constant) \ ::ClassDB::bind_integer_constant(get_class_static(), __constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant); +#define BIND_BITFIELD_FLAG(m_constant) \ + ::ClassDB::bind_integer_constant(get_class_static(), __constant_get_bitfield_name(m_constant, #m_constant), #m_constant, m_constant, true); + _FORCE_INLINE_ void errarray_add_str(Vector<Error> &arr) { } @@ -401,6 +411,9 @@ _FORCE_INLINE_ Vector<Error> errarray(P... p_args) { #define BIND_ENUM_CONSTANT(m_constant) \ ::ClassDB::bind_integer_constant(get_class_static(), StringName(), #m_constant, m_constant); +#define BIND_BITFIELD_FLAG(m_constant) \ + ::ClassDB::bind_integer_constant(get_class_static(), StringName(), #m_constant, m_constant, true); + #define BIND_METHOD_ERR_RETURN_DOC(m_method, ...) #endif diff --git a/core/object/object.h b/core/object/object.h index 1f6386e6b4..87d042dd7e 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -109,6 +109,7 @@ enum PropertyUsageFlags { PROPERTY_USAGE_GROUP = 128, //used for grouping props in the editor PROPERTY_USAGE_CATEGORY = 256, PROPERTY_USAGE_SUBGROUP = 512, + PROPERTY_USAGE_CLASS_IS_BITFIELD = 1024, PROPERTY_USAGE_NO_INSTANCE_STATE = 2048, PROPERTY_USAGE_RESTART_IF_CHANGED = 4096, PROPERTY_USAGE_SCRIPT_VARIABLE = 8192, diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h index 22a13b0fab..84f894dcbf 100644 --- a/core/variant/binder_common.h +++ b/core/variant/binder_common.h @@ -106,6 +106,29 @@ struct VariantCaster<const T &> { static void initialize(m_enum &value) { value = (m_enum)0; } \ }; +#define VARIANT_BITFIELD_CAST(m_enum) \ + MAKE_BITFIELD_TYPE_INFO(m_enum) \ + template <> \ + struct VariantCaster<BitField<m_enum>> { \ + static _FORCE_INLINE_ BitField<m_enum> cast(const Variant &p_variant) { \ + return BitField<m_enum>(p_variant.operator int64_t()); \ + } \ + }; \ + template <> \ + struct PtrToArg<BitField<m_enum>> { \ + _FORCE_INLINE_ static BitField<m_enum> convert(const void *p_ptr) { \ + return BitField<m_enum>(*reinterpret_cast<const int64_t *>(p_ptr)); \ + } \ + typedef int64_t EncodeT; \ + _FORCE_INLINE_ static void encode(BitField<m_enum> p_val, const void *p_ptr) { \ + *(int64_t *)p_ptr = p_val; \ + } \ + }; \ + template <> \ + struct ZeroInitializer<BitField<m_enum>> { \ + static void initialize(BitField<m_enum> &value) { value = 0; } \ + }; + // Object enum casts must go here VARIANT_ENUM_CAST(Object::ConnectFlags); diff --git a/core/variant/type_info.h b/core/variant/type_info.h index bacd0d19ce..794274dd77 100644 --- a/core/variant/type_info.h +++ b/core/variant/type_info.h @@ -279,6 +279,51 @@ inline StringName __constant_get_enum_name(T param, const String &p_constant) { return GetTypeInfo<T>::get_class_info().class_name; } +template <class T> +class BitField { + uint32_t value = 0; + +public: + _FORCE_INLINE_ void set_flag(T p_flag) { value |= p_flag; } + _FORCE_INLINE_ bool has_flag(T p_flag) const { return value & p_flag; } + _FORCE_INLINE_ void clear_flag(T p_flag) { return value &= ~p_flag; } + _FORCE_INLINE_ BitField(uint32_t p_value) { value = p_value; } + _FORCE_INLINE_ operator uint32_t() const { return value; } +}; + +#define TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_impl) \ + template <> \ + struct GetTypeInfo<m_impl> { \ + static const Variant::Type VARIANT_TYPE = Variant::INT; \ + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \ + godot::details::enum_qualified_name_to_class_info_name(String(#m_enum))); \ + } \ + }; \ + template <> \ + struct GetTypeInfo<BitField<m_impl>> { \ + static const Variant::Type VARIANT_TYPE = Variant::INT; \ + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \ + static inline PropertyInfo get_class_info() { \ + return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \ + godot::details::enum_qualified_name_to_class_info_name(String(#m_enum))); \ + } \ + }; + +#define MAKE_BITFIELD_TYPE_INFO(m_enum) \ + TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum) \ + TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum const) \ + TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum &) \ + TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, const m_enum &) + +template <typename T> +inline StringName __constant_get_bitfield_name(T param, const String &p_constant) { + if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) { + ERR_PRINT("Missing VARIANT_ENUM_CAST for constant's bitfield: " + p_constant); + } + return GetTypeInfo<BitField<T>>::get_class_info().class_name; +} #define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info()) template <typename T> diff --git a/doc/class.xsd b/doc/class.xsd index 498c930d6f..4f085369ee 100644 --- a/doc/class.xsd +++ b/doc/class.xsd @@ -155,6 +155,7 @@ <xs:attribute type="xs:string" name="name" /> <xs:attribute type="xs:string" name="value" /> <xs:attribute type="xs:string" name="enum" use="optional" /> + <xs:attribute type="xs:boolean" name="is_bitfield" use="optional" /> </xs:extension> </xs:simpleContent> </xs:complexType> diff --git a/doc/classes/ResourceSaver.xml b/doc/classes/ResourceSaver.xml index 815c7e8813..213d8c585a 100644 --- a/doc/classes/ResourceSaver.xml +++ b/doc/classes/ResourceSaver.xml @@ -37,7 +37,7 @@ <return type="int" enum="Error" /> <argument index="0" name="path" type="String" /> <argument index="1" name="resource" type="Resource" /> - <argument index="2" name="flags" type="int" default="0" /> + <argument index="2" name="flags" type="int" enum="ResourceSaver.SaverFlags" default="0" /> <description> Saves a resource to disk to the given path, using a [ResourceFormatSaver] that recognizes the resource object. The [code]flags[/code] bitmask can be specified to customize the save behavior using [enum SaverFlags] flags. @@ -46,28 +46,28 @@ </method> </methods> <constants> - <constant name="FLAG_NONE" value="0" enum="SaverFlags"> + <constant name="FLAG_NONE" value="0" enum="SaverFlags" is_bitfield="true"> No resource saving option. </constant> - <constant name="FLAG_RELATIVE_PATHS" value="1" enum="SaverFlags"> + <constant name="FLAG_RELATIVE_PATHS" value="1" enum="SaverFlags" is_bitfield="true"> Save the resource with a path relative to the scene which uses it. </constant> - <constant name="FLAG_BUNDLE_RESOURCES" value="2" enum="SaverFlags"> + <constant name="FLAG_BUNDLE_RESOURCES" value="2" enum="SaverFlags" is_bitfield="true"> Bundles external resources. </constant> - <constant name="FLAG_CHANGE_PATH" value="4" enum="SaverFlags"> + <constant name="FLAG_CHANGE_PATH" value="4" enum="SaverFlags" is_bitfield="true"> Changes the [member Resource.resource_path] of the saved resource to match its new location. </constant> - <constant name="FLAG_OMIT_EDITOR_PROPERTIES" value="8" enum="SaverFlags"> + <constant name="FLAG_OMIT_EDITOR_PROPERTIES" value="8" enum="SaverFlags" is_bitfield="true"> Do not save editor-specific metadata (identified by their [code]__editor[/code] prefix). </constant> - <constant name="FLAG_SAVE_BIG_ENDIAN" value="16" enum="SaverFlags"> + <constant name="FLAG_SAVE_BIG_ENDIAN" value="16" enum="SaverFlags" is_bitfield="true"> Save as big endian (see [member File.big_endian]). </constant> - <constant name="FLAG_COMPRESS" value="32" enum="SaverFlags"> + <constant name="FLAG_COMPRESS" value="32" enum="SaverFlags" is_bitfield="true"> Compress the resource on save using [constant File.COMPRESSION_ZSTD]. Only available for binary resource types. </constant> - <constant name="FLAG_REPLACE_SUBRESOURCE_PATHS" value="64" enum="SaverFlags"> + <constant name="FLAG_REPLACE_SUBRESOURCE_PATHS" value="64" enum="SaverFlags" is_bitfield="true"> Take over the paths of the saved subresources (see [method Resource.take_over_path]). </constant> </constants> diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py index ce09361dfa..e9e9d097eb 100755 --- a/doc/tools/make_rst.py +++ b/doc/tools/make_rst.py @@ -122,16 +122,18 @@ class MethodDef: class ConstantDef: - def __init__(self, name, value, text): # type: (str, str, Optional[str]) -> None + def __init__(self, name, value, text, bitfield): # type: (str, str, Optional[str], Optional[bool]) -> None self.name = name self.value = value self.text = text + self.is_bitfield = bitfield class EnumDef: - def __init__(self, name): # type: (str) -> None + def __init__(self, name, bitfield): # type: (str, Optional[bool]) -> None self.name = name self.values = OrderedDict() # type: OrderedDict[str, ConstantDef] + self.is_bitfield = bitfield class ThemeItemDef: @@ -305,7 +307,8 @@ class State: constant_name = constant.attrib["name"] value = constant.attrib["value"] enum = constant.get("enum") - constant_def = ConstantDef(constant_name, value, constant.text) + is_bitfield = constant.get("is_bitfield") or False + constant_def = ConstantDef(constant_name, value, constant.text, is_bitfield) if enum is None: if constant_name in class_def.constants: print_error('{}.xml: Duplicate constant "{}".'.format(class_name, constant_name), self) @@ -318,7 +321,7 @@ class State: enum_def = class_def.enums[enum] else: - enum_def = EnumDef(enum) + enum_def = EnumDef(enum, is_bitfield) class_def.enums[enum] = enum_def enum_def.values[constant_name] = constant_def @@ -706,7 +709,11 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S for value in e.values.values(): f.write(".. _class_{}_constant_{}:\n\n".format(class_name, value.name)) - f.write("enum **{}**:\n\n".format(e.name)) + if e.is_bitfield: + f.write("flags **{}**:\n\n".format(e.name)) + else: + f.write("enum **{}**:\n\n".format(e.name)) + for value in e.values.values(): f.write("- **{}** = **{}**".format(value.name, value.value)) if value.text is not None and value.text.strip() != "": diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index e6cd1e0b48..88818bfca4 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -429,7 +429,7 @@ void DocTools::generate(bool p_basic_types) { PropertyInfo retinfo = mb->get_return_info(); found_type = true; - if (retinfo.type == Variant::INT && retinfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + if (retinfo.type == Variant::INT && retinfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { prop.enumeration = retinfo.class_name; prop.type = "int"; } else if (retinfo.class_name != StringName()) { @@ -575,6 +575,7 @@ void DocTools::generate(bool p_basic_types) { constant.value = itos(ClassDB::get_integer_constant(name, E)); constant.is_value_valid = true; constant.enumeration = ClassDB::get_integer_constant_enum(name, E); + constant.is_bitfield = ClassDB::is_enum_bitfield(name, constant.enumeration); c.constants.push_back(constant); } @@ -1244,6 +1245,9 @@ Error DocTools::_load(Ref<XMLParser> parser) { if (parser->has_attribute("enum")) { constant2.enumeration = parser->get_attribute_value("enum"); } + if (parser->has_attribute("is_bitfield")) { + constant2.is_bitfield = parser->get_attribute_value("is_bitfield").to_lower() == "true"; + } if (!parser->is_empty()) { parser->read(); if (parser->get_node_type() == XMLParser::NODE_TEXT) { @@ -1424,7 +1428,11 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String, const DocData::ConstantDoc &k = c.constants[i]; if (k.is_value_valid) { if (!k.enumeration.is_empty()) { - _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\">"); + if (k.is_bitfield) { + _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\" is_bitfield=\"true\">"); + } else { + _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\">"); + } } else { _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\">"); } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 36360954d9..7bf9eb2997 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -1105,7 +1105,11 @@ void EditorHelp::_update_doc() { class_desc->push_font(doc_code_font); class_desc->push_color(title_color); - class_desc->add_text("enum "); + if (E.value.size() && E.value[0].is_bitfield) { + class_desc->add_text("flags "); + } else { + class_desc->add_text("enum "); + } class_desc->pop(); String e = E.key; if ((e.get_slice_count(".") > 1) && (e.get_slice(".", 0) == edited_class)) { diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 474c8094f2..e419493324 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -569,7 +569,7 @@ static int _get_enum_constant_location(StringName p_class, StringName p_enum_con // END LOCATION METHODS static String _get_visual_datatype(const PropertyInfo &p_info, bool p_is_arg = true) { - if (p_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + if (p_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { String enum_name = p_info.class_name; if (!enum_name.contains(".")) { return enum_name; @@ -1292,7 +1292,7 @@ static GDScriptCompletionIdentifier _type_from_property(const PropertyInfo &p_pr return ci; } - if (p_property.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + if (p_property.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { ci.enumeration = p_property.class_name; } @@ -2407,7 +2407,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c if (p_argidx < method_args) { PropertyInfo arg_info = info.arguments[p_argidx]; - if (arg_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + if (arg_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { _find_enumeration_candidates(p_context, arg_info.class_name, r_result); } } diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 9d3d481068..4ee774c3bd 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -2865,7 +2865,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { " We only expected Object.free, but found '" + itype.name + "." + imethod.name + "'."); } - } else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + } else if (return_info.type == Variant::INT && return_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { imethod.return_type.cname = return_info.class_name; imethod.return_type.is_enum = true; } else if (return_info.class_name != StringName()) { @@ -2903,7 +2903,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { ArgumentInterface iarg; iarg.name = orig_arg_name; - if (arginfo.type == Variant::INT && arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + if (arginfo.type == Variant::INT && arginfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { iarg.type.cname = arginfo.class_name; iarg.type.is_enum = true; } else if (arginfo.class_name != StringName()) { @@ -3011,7 +3011,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { ArgumentInterface iarg; iarg.name = orig_arg_name; - if (arginfo.type == Variant::INT && arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + if (arginfo.type == Variant::INT && arginfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { iarg.type.cname = arginfo.class_name; iarg.type.is_enum = true; } else if (arginfo.class_name != StringName()) { @@ -3075,9 +3075,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() { List<String> constants; ClassDB::get_integer_constant_list(type_cname, &constants, true); - const HashMap<StringName, List<StringName>> &enum_map = class_info->enum_map; + const HashMap<StringName, ClassDB::ClassInfo::EnumInfo> &enum_map = class_info->enum_map; - for (const KeyValue<StringName, List<StringName>> &E : enum_map) { + for (const KeyValue<StringName, ClassDB::ClassInfo::EnumInfo> &E : enum_map) { StringName enum_proxy_cname = E.key; String enum_proxy_name = enum_proxy_cname.operator String(); if (itype.find_property_by_proxy_name(enum_proxy_cname)) { @@ -3087,7 +3087,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { enum_proxy_cname = StringName(enum_proxy_name); } EnumInterface ienum(enum_proxy_cname); - const List<StringName> &enum_constants = E.value; + const List<StringName> &enum_constants = E.value.constants; for (const StringName &constant_cname : enum_constants) { String constant_name = constant_cname.operator String(); int64_t *value = class_info->constant_map.getptr(constant_cname); diff --git a/tests/core/object/test_class_db.h b/tests/core/object/test_class_db.h index 7ea9e16ff1..c7535426df 100644 --- a/tests/core/object/test_class_db.h +++ b/tests/core/object/test_class_db.h @@ -597,7 +597,7 @@ void add_exposed_classes(Context &r_context) { (exposed_class.name != r_context.names_cache.object_class || String(method.name) != "free"), warn_msg.utf8().get_data()); - } else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + } else if (return_info.type == Variant::INT && return_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { method.return_type.name = return_info.class_name; method.return_type.is_enum = true; } else if (return_info.class_name != StringName()) { @@ -626,7 +626,7 @@ void add_exposed_classes(Context &r_context) { ArgumentData arg; arg.name = orig_arg_name; - if (arg_info.type == Variant::INT && arg_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + if (arg_info.type == Variant::INT && arg_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { arg.type.name = arg_info.class_name; arg.type.is_enum = true; } else if (arg_info.class_name != StringName()) { @@ -694,7 +694,7 @@ void add_exposed_classes(Context &r_context) { ArgumentData arg; arg.name = orig_arg_name; - if (arg_info.type == Variant::INT && arg_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + if (arg_info.type == Variant::INT && arg_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { arg.type.name = arg_info.class_name; arg.type.is_enum = true; } else if (arg_info.class_name != StringName()) { @@ -732,13 +732,13 @@ void add_exposed_classes(Context &r_context) { List<String> constants; ClassDB::get_integer_constant_list(class_name, &constants, true); - const HashMap<StringName, List<StringName>> &enum_map = class_info->enum_map; + const HashMap<StringName, ClassDB::ClassInfo::EnumInfo> &enum_map = class_info->enum_map; - for (const KeyValue<StringName, List<StringName>> &K : enum_map) { + for (const KeyValue<StringName, ClassDB::ClassInfo::EnumInfo> &K : enum_map) { EnumData enum_; enum_.name = K.key; - for (const StringName &E : K.value) { + for (const StringName &E : K.value.constants) { const StringName &constant_name = E; TEST_FAIL_COND(String(constant_name).find("::") != -1, "Enum constant contains '::', check bindings to remove the scope: '", |