Implement a BitField hint

Allows to specify the binder that an enum must be treated as a bitfield.
This commit is contained in:
reduz 2022-06-24 11:16:37 +02:00 committed by Rémi Verschelde
parent 9de5698ee2
commit 5ac42cf576
18 changed files with 184 additions and 58 deletions

View File

@ -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 //////

View File

@ -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);

View File

@ -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());

View File

@ -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;
};

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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() != "":

View File

@ -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 + "\">");
}

View File

@ -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)) {

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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: '",