[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [33631] trunk/blender/source/blender: Expose access to PROP_ENUM_FLAG from bpy.props.EnumProperty(), this is exposed as a python set().
Campbell Barton
ideasman42 at gmail.com
Mon Dec 13 10:10:16 CET 2010
Revision: 33631
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=33631
Author: campbellbarton
Date: 2010-12-13 10:10:16 +0100 (Mon, 13 Dec 2010)
Log Message:
-----------
Expose access to PROP_ENUM_FLAG from bpy.props.EnumProperty(), this is exposed as a python set(). The default value is also a python set() so multiple booleans can be used in the 1 property.
Also added PROP_ENUM_FLAG support to operator printouts.
Modified Paths:
--------------
trunk/blender/source/blender/makesrna/intern/rna_access.c
trunk/blender/source/blender/python/intern/bpy_props.c
Modified: trunk/blender/source/blender/makesrna/intern/rna_access.c
===================================================================
--- trunk/blender/source/blender/makesrna/intern/rna_access.c 2010-12-13 09:04:04 UTC (rev 33630)
+++ trunk/blender/source/blender/makesrna/intern/rna_access.c 2010-12-13 09:10:16 UTC (rev 33631)
@@ -3807,7 +3807,31 @@
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 {
Modified: trunk/blender/source/blender/python/intern/bpy_props.c
===================================================================
--- trunk/blender/source/blender/python/intern/bpy_props.c 2010-12-13 09:04:04 UTC (rev 33630)
+++ trunk/blender/source/blender/python/intern/bpy_props.c 2010-12-13 09:10:16 UTC (rev 33631)
@@ -40,6 +40,12 @@
{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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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<seq_len; i++) {
EnumPropertyItem tmp= {0, "", 0, "", ""};
item= PySequence_GetItem(value, i);
if(item==NULL || PyTuple_Check(item)==0) {
- 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");
if(items) MEM_freeN(items);
Py_XDECREF(item);
return NULL;
}
if(!PyArg_ParseTuple(item, "sss", &tmp.identifier, &tmp.name, &tmp.description)) {
- PyErr_SetString(PyExc_TypeError, "expected an identifier, name and description in the tuple");
+ PyErr_SetString(PyExc_TypeError, "EnumProperty(...): expected an identifier, name and description in the tuple");
Py_DECREF(item);
return NULL;
}
- tmp.value= i;
+ if(is_enum_flag) {
+ tmp.value= 1<<i;
+
+ if(def && PySet_Contains(def, PyTuple_GET_ITEM(item, 0))) {
+ *defvalue |= tmp.value;
+ def_used++;
+ }
+ }
+ else {
+ tmp.value= i;
+
+ if(def && def_used == 0 && strcmp(def_cmp, tmp.identifier)==0) {
+ *defvalue= tmp.value;
+ def_used++; /* only ever 1 */
+ }
+ }
+
RNA_enum_item_add(&items, &totitem, &tmp);
- if(def[0] && strcmp(def, tmp.identifier) == 0)
- *defvalue= tmp.value;
-
Py_DECREF(item);
}
- if(!def[0])
- *defvalue= 0;
-
RNA_enum_item_end(&items, &totitem);
+ if(is_enum_flag) {
+ /* strict check that all set members were used */
+ if(def && def_used != PySet_GET_SIZE(def)) {
+ MEM_freeN(items);
+
+ PyErr_Format(PyExc_TypeError, "EnumProperty(..., default={...}): set has %d unused member(s)", PySet_GET_SIZE(def) - def_used);
+ return NULL;
+ }
+ }
+ else {
+ if(def && def_used == 0) {
+ MEM_freeN(items);
+
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list