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

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to