diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 4dc696e32dc..f95e18f3722 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -3807,7 +3807,31 @@ char *RNA_property_as_string(bContext *C, PointerRNA *ptr, PropertyRNA *prop) const char *identifier; int val = RNA_property_enum_get(ptr, prop); - if(RNA_property_enum_identifier(C, ptr, prop, val, &identifier)) { + if(RNA_property_flag(prop) & PROP_ENUM_FLAG) { + /* represent as a python set */ + EnumPropertyItem *item= NULL; + int free; + + BLI_dynstr_append(dynstr, "{"); + + RNA_property_enum_items(C, ptr, prop, &item, NULL, &free); + if(item) { + short is_first= TRUE; + for (; item->identifier; item++) { + if(item->identifier[0] && item->value & val) { + BLI_dynstr_appendf(dynstr, is_first ? "'%s'" : ", '%s'", item->identifier); + is_first= FALSE; + } + } + + if(free) { + MEM_freeN(item); + } + } + + BLI_dynstr_append(dynstr, "}"); + } + else if(RNA_property_enum_identifier(C, ptr, prop, val, &identifier)) { BLI_dynstr_appendf(dynstr, "'%s'", identifier); } else { diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index b7192f7395b..1148b9e5e2b 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -40,6 +40,12 @@ EnumPropertyItem property_flag_items[] = { {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animateable", ""}, {0, NULL, 0, NULL, NULL}}; +EnumPropertyItem property_flag_enum_items[] = { + {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""}, + {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animateable", ""}, + {PROP_ENUM_FLAG, "ENUM_FLAG", 0, "Enum Flag", ""}, + {0, NULL, 0, NULL, NULL}}; + /* subtypes */ EnumPropertyItem property_subtype_string_items[] = { {PROP_FILEPATH, "FILE_PATH", 0, "File Path", ""}, @@ -134,7 +140,7 @@ static PyObject *bpy_prop_deferred_return(PyObject *func, PyObject *kw) /* terse macros for error checks shared between all funcs cant use function * calls because of static strins passed to pyrna_set_to_enum_bitfield */ -#define BPY_PROPDEF_CHECK(_func) \ +#define BPY_PROPDEF_CHECK(_func, _property_flag_items) \ if(id_len >= MAX_IDPROP_NAME) { \ PyErr_Format(PyExc_TypeError, #_func"(): '%.200s' too long, max length is %d", id, MAX_IDPROP_NAME-1); \ return NULL; \ @@ -143,11 +149,11 @@ static PyObject *bpy_prop_deferred_return(PyObject *func, PyObject *kw) PyErr_Format(PyExc_TypeError, #_func"(): '%s' is defined as a non-dynamic type", id); \ return NULL; \ } \ - if(pyopts && pyrna_set_to_enum_bitfield(property_flag_items, pyopts, &opts, #_func"(options={...}):")) \ + if(pyopts && pyrna_set_to_enum_bitfield(_property_flag_items, pyopts, &opts, #_func"(options={...}):")) \ return NULL; \ -#define BPY_PROPDEF_SUBTYPE_CHECK(_func, _subtype) \ - BPY_PROPDEF_CHECK(_func) \ +#define BPY_PROPDEF_SUBTYPE_CHECK(_func, _property_flag_items, _subtype) \ + BPY_PROPDEF_CHECK(_func, _property_flag_items) \ if(pysubtype && RNA_enum_value_from_id(_subtype, pysubtype, &subtype)==0) { \ PyErr_Format(PyExc_TypeError, #_func"(subtype='%s'): invalid subtype", pysubtype); \ return NULL; \ @@ -196,7 +202,7 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) if (!PyArg_ParseTupleAndKeywords(args, kw, "s#|ssiO!s:BoolProperty", (char **)kwlist, &id, &id_len, &name, &description, &def, &PySet_Type, &pyopts, &pysubtype)) return NULL; - BPY_PROPDEF_SUBTYPE_CHECK(BoolProperty, property_subtype_number_items) + BPY_PROPDEF_SUBTYPE_CHECK(BoolProperty, property_flag_items, property_subtype_number_items) prop= RNA_def_property(srna, id, PROP_BOOLEAN, subtype); RNA_def_property_boolean_default(prop, def); @@ -243,7 +249,7 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject if (!PyArg_ParseTupleAndKeywords(args, kw, "s#|ssOO!si:BoolVectorProperty", (char **)kwlist, &id, &id_len, &name, &description, &pydef, &PySet_Type, &pyopts, &pysubtype, &size)) return NULL; - BPY_PROPDEF_SUBTYPE_CHECK(BoolVectorProperty, property_subtype_array_items) + BPY_PROPDEF_SUBTYPE_CHECK(BoolVectorProperty, property_flag_items, property_subtype_array_items) if(size < 1 || size > PYRNA_STACK_ARRAY) { PyErr_Format(PyExc_TypeError, "BoolVectorProperty(size=%d): size must be between 0 and " STRINGIFY(PYRNA_STACK_ARRAY), size); @@ -298,7 +304,7 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) if (!PyArg_ParseTupleAndKeywords(args, kw, "s#|ssiiiiiiO!s:IntProperty", (char **)kwlist, &id, &id_len, &name, &description, &def, &min, &max, &soft_min, &soft_max, &step, &PySet_Type, &pyopts, &pysubtype)) return NULL; - BPY_PROPDEF_SUBTYPE_CHECK(IntProperty, property_subtype_number_items) + BPY_PROPDEF_SUBTYPE_CHECK(IntProperty, property_flag_items, property_subtype_number_items) prop= RNA_def_property(srna, id, PROP_INT, subtype); RNA_def_property_int_default(prop, def); @@ -346,7 +352,7 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject if (!PyArg_ParseTupleAndKeywords(args, kw, "s#|ssOiiiiiO!si:IntVectorProperty", (char **)kwlist, &id, &id_len, &name, &description, &pydef, &min, &max, &soft_min, &soft_max, &step, &PySet_Type, &pyopts, &pysubtype, &size)) return NULL; - BPY_PROPDEF_SUBTYPE_CHECK(IntVectorProperty, property_subtype_array_items) + BPY_PROPDEF_SUBTYPE_CHECK(IntVectorProperty, property_flag_items, property_subtype_array_items) if(size < 1 || size > PYRNA_STACK_ARRAY) { PyErr_Format(PyExc_TypeError, "IntVectorProperty(size=%d): size must be between 0 and " STRINGIFY(PYRNA_STACK_ARRAY), size); @@ -407,7 +413,7 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) if (!PyArg_ParseTupleAndKeywords(args, kw, "s#|ssffffffiO!ss:FloatProperty", (char **)kwlist, &id, &id_len, &name, &description, &def, &min, &max, &soft_min, &soft_max, &step, &precision, &PySet_Type, &pyopts, &pysubtype, &pyunit)) return NULL; - BPY_PROPDEF_SUBTYPE_CHECK(FloatProperty, property_subtype_number_items) + BPY_PROPDEF_SUBTYPE_CHECK(FloatProperty, property_flag_items, property_subtype_number_items) if(pyunit && RNA_enum_value_from_id(property_unit_items, pyunit, &unit)==0) { PyErr_Format(PyExc_TypeError, "FloatProperty(unit='%s'): invalid unit"); @@ -460,7 +466,7 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec if (!PyArg_ParseTupleAndKeywords(args, kw, "s#|ssOfffffiO!si:FloatVectorProperty", (char **)kwlist, &id, &id_len, &name, &description, &pydef, &min, &max, &soft_min, &soft_max, &step, &precision, &PySet_Type, &pyopts, &pysubtype, &size)) return NULL; - BPY_PROPDEF_SUBTYPE_CHECK(FloatVectorProperty, property_subtype_array_items) + BPY_PROPDEF_SUBTYPE_CHECK(FloatVectorProperty, property_flag_items, property_subtype_array_items) if(size < 1 || size > PYRNA_STACK_ARRAY) { PyErr_Format(PyExc_TypeError, "FloatVectorProperty(size=%d): size must be between 0 and " STRINGIFY(PYRNA_STACK_ARRAY), size); @@ -515,7 +521,7 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw if (!PyArg_ParseTupleAndKeywords(args, kw, "s#|sssiO!s:StringProperty", (char **)kwlist, &id, &id_len, &name, &description, &def, &maxlen, &PySet_Type, &pyopts, &pysubtype)) return NULL; - BPY_PROPDEF_SUBTYPE_CHECK(StringProperty, property_subtype_string_items) + BPY_PROPDEF_SUBTYPE_CHECK(StringProperty, property_flag_items, property_subtype_string_items) prop= RNA_def_property(srna, id, PROP_STRING, subtype); if(maxlen != 0) RNA_def_property_string_maxlength(prop, maxlen + 1); /* +1 since it includes null terminator */ @@ -531,49 +537,102 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw Py_RETURN_NONE; } -static EnumPropertyItem *enum_items_from_py(PyObject *value, const char *def, int *defvalue) +static EnumPropertyItem *enum_items_from_py(PyObject *value, PyObject *def, int *defvalue, const short is_enum_flag) { EnumPropertyItem *items= NULL; PyObject *item; int seq_len, i, totitem= 0; + short def_used= 0; + const char *def_cmp= NULL; if(!PySequence_Check(value)) { - PyErr_SetString(PyExc_TypeError, "expected a sequence of tuples for the enum items"); + PyErr_SetString(PyExc_TypeError, "EnumProperty(...): expected a sequence of tuples for the enum items"); return NULL; } - seq_len = PySequence_Length(value); + seq_len= PySequence_Length(value); + + if(is_enum_flag) { + if(seq_len > RNA_ENUM_BITFLAG_SIZE) { + PyErr_SetString(PyExc_TypeError, "EnumProperty(...): maximum " STRINGIFY(RNA_ENUM_BITFLAG_SIZE) " members for a ENUM_FLAG type property"); + return NULL; + } + if(def && !PySet_Check(def)) { + PyErr_Format(PyExc_TypeError, "EnumProperty(...): default option must be a 'set' type when ENUM_FLAG is enabled, not a '%.200s'", Py_TYPE(def)->tp_name); + return NULL; + } + } + else { + if(def) { + def_cmp= _PyUnicode_AsString(def); + if(def_cmp==NULL) { + PyErr_Format(PyExc_TypeError, "EnumProperty(...): default option must be a 'str' type when ENUM_FLAG is disabled, not a '%.200s'", Py_TYPE(def)->tp_name); + return NULL; + } + } + } + + /* blank value */ + *defvalue= 0; + for(i=0; i