diff options
Diffstat (limited to 'source/blender/python/intern/bpy_props.c')
-rw-r--r-- | source/blender/python/intern/bpy_props.c | 750 |
1 files changed, 389 insertions, 361 deletions
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index 9ae7507a72a..c8af0d63e3b 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -22,11 +22,13 @@ * ***** END GPL LICENSE BLOCK ***** */ +#include <Python.h> + #include "bpy_props.h" #include "bpy_rna.h" #include "bpy_util.h" -#include "BKE_utildefines.h" +#include "BLI_utildefines.h" #include "RNA_define.h" /* for defining our own rna */ #include "RNA_enum_types.h" @@ -35,13 +37,19 @@ #include "../generic/py_capi_utils.h" -EnumPropertyItem property_flag_items[] = { +static EnumPropertyItem property_flag_items[] = { + {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""}, + {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animateable", ""}, + {0, NULL, 0, NULL, NULL}}; + +static 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[] = { +static EnumPropertyItem property_subtype_string_items[] = { {PROP_FILEPATH, "FILE_PATH", 0, "File Path", ""}, {PROP_DIRPATH, "DIR_PATH", 0, "Directory Path", ""}, {PROP_FILENAME, "FILENAME", 0, "Filename", ""}, @@ -49,7 +57,7 @@ EnumPropertyItem property_subtype_string_items[] = { {PROP_NONE, "NONE", 0, "None", ""}, {0, NULL, 0, NULL, NULL}}; -EnumPropertyItem property_subtype_number_items[] = { +static EnumPropertyItem property_subtype_number_items[] = { {PROP_UNSIGNED, "UNSIGNED", 0, "Unsigned", ""}, {PROP_PERCENTAGE, "PERCENTAGE", 0, "Percentage", ""}, {PROP_FACTOR, "FACTOR", 0, "Factor", ""}, @@ -60,7 +68,7 @@ EnumPropertyItem property_subtype_number_items[] = { {PROP_NONE, "NONE", 0, "None", ""}, {0, NULL, 0, NULL, NULL}}; -EnumPropertyItem property_subtype_array_items[] = { +static EnumPropertyItem property_subtype_array_items[] = { {PROP_COLOR, "COLOR", 0, "Color", ""}, {PROP_TRANSLATION, "TRANSLATION", 0, "Translation", ""}, {PROP_DIRECTION, "DIRECTION", 0, "Direction", ""}, @@ -77,19 +85,93 @@ EnumPropertyItem property_subtype_array_items[] = { {PROP_NONE, "NONE", 0, "None", ""}, {0, NULL, 0, NULL, NULL}}; -/* operators use this so it can store the args given but defer running - * it until the operator runs where these values are used to setup the - * default args for that operator instance */ -static PyObject *bpy_prop_deferred_return(void *func, PyObject *kw) +/* PyObject's */ +static PyObject *pymeth_BoolProperty = NULL; +static PyObject *pymeth_BoolVectorProperty = NULL; +static PyObject *pymeth_IntProperty = NULL; +static PyObject *pymeth_IntVectorProperty = NULL; +static PyObject *pymeth_FloatProperty = NULL; +static PyObject *pymeth_FloatVectorProperty = NULL; +static PyObject *pymeth_StringProperty = NULL; +static PyObject *pymeth_EnumProperty = NULL; +static PyObject *pymeth_PointerProperty = NULL; +static PyObject *pymeth_CollectionProperty = NULL; +static PyObject *pymeth_RemoveProperty = NULL; + + +/* operators and classes use this so it can store the args given but defer + * running it until the operator runs where these values are used to setup + * the default args for that operator instance */ +static PyObject *bpy_prop_deferred_return(PyObject *func, PyObject *kw) { PyObject *ret = PyTuple_New(2); - PyTuple_SET_ITEM(ret, 0, PyCapsule_New(func, NULL, NULL)); - if(kw==NULL) kw= PyDict_New(); - else Py_INCREF(kw); + PyTuple_SET_ITEM(ret, 0, func); + Py_INCREF(func); + + if(kw==NULL) + kw= PyDict_New(); + else + Py_INCREF(kw); + PyTuple_SET_ITEM(ret, 1, kw); + return ret; } +/* this define runs at the start of each function and deals with + * returning a deferred property (to be registed later) */ +#define BPY_PROPDEF_HEAD(_func) \ + if (PyTuple_GET_SIZE(args) == 1) { \ + PyObject *ret; \ + self= PyTuple_GET_ITEM(args, 0); \ + args= PyTuple_New(0); \ + ret= BPy_##_func(self, args, kw); \ + Py_DECREF(args); \ + return ret; \ + } \ + else if (PyTuple_GET_SIZE(args) > 1) { \ + PyErr_SetString(PyExc_ValueError, "all args must be keywords"); \ + return NULL; \ + } \ + srna= srna_from_self(self, #_func"(...):"); \ + if(srna==NULL) { \ + if(PyErr_Occurred()) \ + return NULL; \ + return bpy_prop_deferred_return((void *)pymeth_##_func, 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, _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; \ + } \ + if(RNA_def_property_free_identifier(srna, id) == -1) { \ + 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={...}):")) \ + return NULL; \ + +#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; \ + } \ + + +#define BPY_PROPDEF_NAME_DOC \ +" :arg name: Name used in the user interface.\n" \ +" :type name: string\n" \ + + +#define BPY_PROPDEF_DESC_DOC \ +" :arg description: Text used for the tooltip and api documentation.\n" \ +" :type description: string\n" \ + + #if 0 static int bpy_struct_id_used(StructRNA *srna, char *identifier) { @@ -102,32 +184,28 @@ static int bpy_struct_id_used(StructRNA *srna, char *identifier) /* Function that sets RNA, NOTE - self is NULL when called from python, but being abused from C so we can pass the srna allong * This isnt incorrect since its a python object - but be careful */ -char BPy_BoolProperty_doc[] = +static char BPy_BoolProperty_doc[] = ".. function:: BoolProperty(name=\"\", description=\"\", default=False, options={'ANIMATABLE'}, subtype='NONE')\n" "\n" " Returns a new boolean property definition.\n" "\n" +BPY_PROPDEF_NAME_DOC +BPY_PROPDEF_DESC_DOC " :arg options: Enumerator in ['HIDDEN', 'ANIMATABLE'].\n" " :type options: set\n" " :arg subtype: Enumerator in ['UNSIGNED', 'PERCENTAGE', 'FACTOR', 'ANGLE', 'TIME', 'DISTANCE', 'NONE'].\n" -" :type subtype: string"; - -PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) +" :type subtype: string\n" +; +static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - if (PyTuple_GET_SIZE(args) > 0) { - PyErr_SetString(PyExc_ValueError, "all args must be keywords"); - return NULL; - } + BPY_PROPDEF_HEAD(BoolProperty) - srna= srna_from_self(self, "BoolProperty(...):"); - if(srna==NULL && PyErr_Occurred()) { - return NULL; /* self's type was compatible but error getting the srna */ - } - else if(srna) { - static char *kwlist[] = {"attr", "name", "description", "default", "options", "subtype", NULL}; - char *id=NULL, *name="", *description=""; + if(srna) { + static const char *kwlist[] = {"attr", "name", "description", "default", "options", "subtype", NULL}; + const char *id=NULL, *name="", *description=""; + int id_len; int def=0; PropertyRNA *prop; PyObject *pyopts= NULL; @@ -135,23 +213,11 @@ PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) char *pysubtype= NULL; int subtype= PROP_NONE; - if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssiO!s:BoolProperty", (char **)kwlist, &id, &name, &description, &def, &PySet_Type, &pyopts, &pysubtype)) + if (!PyArg_ParseTupleAndKeywords(args, kw, "s#|ssiO!s:BoolProperty", (char **)kwlist, &id, &id_len, &name, &description, &def, &PySet_Type, &pyopts, &pysubtype)) return NULL; - if(RNA_def_property_free_identifier(srna, id) == -1) { - PyErr_Format(PyExc_TypeError, "BoolProperty(): '%s' is defined as a non-dynamic type.", id); - return NULL; - } - - if(pyopts && pyrna_set_to_enum_bitfield(property_flag_items, pyopts, &opts, "BoolProperty(options={...}):")) - return NULL; + BPY_PROPDEF_SUBTYPE_CHECK(BoolProperty, property_flag_items, property_subtype_number_items) - if(pysubtype && RNA_enum_value_from_id(property_subtype_number_items, pysubtype, &subtype)==0) { - PyErr_Format(PyExc_TypeError, "BoolProperty(subtype='%s'): invalid subtype.", pysubtype); - return NULL; - } - - // prop= RNA_def_boolean(srna, id, def, name, description); prop= RNA_def_property(srna, id, PROP_BOOLEAN, subtype); RNA_def_property_boolean_default(prop, def); RNA_def_property_ui_text(prop, name, description); @@ -160,39 +226,38 @@ PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) if(opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN); if((opts & PROP_ANIMATABLE)==0) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); } - RNA_def_property_duplicate_pointers(prop); - Py_RETURN_NONE; - } - else { /* operators defer running this function */ - return bpy_prop_deferred_return((void *)BPy_BoolProperty, kw); + RNA_def_property_duplicate_pointers(srna, prop); } + + Py_RETURN_NONE; } -char BPy_BoolVectorProperty_doc[] = +static char BPy_BoolVectorProperty_doc[] = ".. function:: BoolVectorProperty(name=\"\", description=\"\", default=(False, False, False), options={'ANIMATABLE'}, subtype='NONE', size=3)\n" "\n" " Returns a new vector boolean property definition.\n" "\n" +BPY_PROPDEF_NAME_DOC +BPY_PROPDEF_DESC_DOC +" :arg default: sequence of booleans the length of *size*.\n" +" :type default: sequence\n" " :arg options: Enumerator in ['HIDDEN', 'ANIMATABLE'].\n" " :type options: set\n" " :arg subtype: Enumerator in ['COLOR', 'TRANSLATION', 'DIRECTION', 'VELOCITY', 'ACCELERATION', 'MATRIX', 'EULER', 'QUATERNION', 'AXISANGLE', 'XYZ', 'COLOR_GAMMA', 'LAYER', 'NONE'].\n" -" :type subtype: string"; -PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw) +" :type subtype: string\n" +" :arg size: Vector dimensions in [1, and " STRINGIFY(PYRNA_STACK_ARRAY) "].\n" +" :type size: int\n" +; +static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - if (PyTuple_GET_SIZE(args) > 0) { - PyErr_SetString(PyExc_ValueError, "all args must be keywords"); - return NULL; - } + BPY_PROPDEF_HEAD(BoolVectorProperty) - srna= srna_from_self(self, "BoolVectorProperty(...):"); - if(srna==NULL && PyErr_Occurred()) { - return NULL; /* self's type was compatible but error getting the srna */ - } - else if(srna) { + if(srna) { static const char *kwlist[] = {"attr", "name", "description", "default", "options", "subtype", "size", NULL}; - char *id=NULL, *name="", *description=""; + const char *id=NULL, *name="", *description=""; + int id_len; int def[PYRNA_STACK_ARRAY]={0}; int size=3; PropertyRNA *prop; @@ -202,24 +267,13 @@ PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw) char *pysubtype= NULL; int subtype= PROP_NONE; - if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssOO!si:BoolVectorProperty", (char **)kwlist, &id, &name, &description, &pydef, &PySet_Type, &pyopts, &pysubtype, &size)) - return NULL; - - if(RNA_def_property_free_identifier(srna, id) == -1) { - PyErr_Format(PyExc_TypeError, "BoolVectorProperty(): '%s' is defined as a non-dynamic type.", id); - return NULL; - } - - if(pyopts && pyrna_set_to_enum_bitfield(property_flag_items, pyopts, &opts, "BoolVectorProperty(options={...}):")) + if (!PyArg_ParseTupleAndKeywords(args, kw, "s#|ssOO!si:BoolVectorProperty", (char **)kwlist, &id, &id_len, &name, &description, &pydef, &PySet_Type, &pyopts, &pysubtype, &size)) return NULL; - if(pysubtype && RNA_enum_value_from_id(property_subtype_array_items, pysubtype, &subtype)==0) { - PyErr_Format(PyExc_TypeError, "BoolVectorProperty(subtype='%s'): invalid subtype.", pysubtype); - return NULL; - } + 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 %d.", size, PYRNA_STACK_ARRAY); + PyErr_Format(PyExc_TypeError, "BoolVectorProperty(size=%d): size must be between 0 and " STRINGIFY(PYRNA_STACK_ARRAY), size); return NULL; } @@ -236,39 +290,34 @@ PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw) if(opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN); if((opts & PROP_ANIMATABLE)==0) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); } - RNA_def_property_duplicate_pointers(prop); - Py_RETURN_NONE; - } - else { /* operators defer running this function */ - return bpy_prop_deferred_return((void *)BPy_BoolVectorProperty, kw); + RNA_def_property_duplicate_pointers(srna, prop); } + + Py_RETURN_NONE; } -char BPy_IntProperty_doc[] = +static char BPy_IntProperty_doc[] = ".. function:: IntProperty(name=\"\", description=\"\", default=0, min=-sys.maxint, max=sys.maxint, soft_min=-sys.maxint, soft_max=sys.maxint, step=1, options={'ANIMATABLE'}, subtype='NONE')\n" "\n" " Returns a new int property definition.\n" "\n" +BPY_PROPDEF_NAME_DOC +BPY_PROPDEF_DESC_DOC " :arg options: Enumerator in ['HIDDEN', 'ANIMATABLE'].\n" " :type options: set\n" " :arg subtype: Enumerator in ['UNSIGNED', 'PERCENTAGE', 'FACTOR', 'ANGLE', 'TIME', 'DISTANCE', 'NONE'].\n" -" :type subtype: string"; -PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) +" :type subtype: string\n" +; +static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - if (PyTuple_GET_SIZE(args) > 0) { - PyErr_SetString(PyExc_ValueError, "all args must be keywords"); - return NULL; - } + BPY_PROPDEF_HEAD(IntProperty) - srna= srna_from_self(self, "IntProperty(...):"); - if(srna==NULL && PyErr_Occurred()) { - return NULL; /* self's type was compatible but error getting the srna */ - } - else if(srna) { + if(srna) { static const char *kwlist[] = {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "options", "subtype", NULL}; - char *id=NULL, *name="", *description=""; + const char *id=NULL, *name="", *description=""; + int id_len; int min=INT_MIN, max=INT_MAX, soft_min=INT_MIN, soft_max=INT_MAX, step=1, def=0; PropertyRNA *prop; PyObject *pyopts= NULL; @@ -276,21 +325,10 @@ PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) char *pysubtype= NULL; int subtype= PROP_NONE; - if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssiiiiiiO!s:IntProperty", (char **)kwlist, &id, &name, &description, &def, &min, &max, &soft_min, &soft_max, &step, &PySet_Type, &pyopts, &pysubtype)) - return NULL; - - if(RNA_def_property_free_identifier(srna, id) == -1) { - PyErr_Format(PyExc_TypeError, "IntProperty(): '%s' is defined as a non-dynamic type.", id); + 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; - } - if(pyopts && pyrna_set_to_enum_bitfield(property_flag_items, pyopts, &opts, "IntProperty(options={...}):")) - return NULL; - - if(pysubtype && RNA_enum_value_from_id(property_subtype_number_items, pysubtype, &subtype)==0) { - PyErr_Format(PyExc_TypeError, "IntProperty(subtype='%s'): invalid subtype.", pysubtype); - return NULL; - } + 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); @@ -302,39 +340,37 @@ PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) if(opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN); if((opts & PROP_ANIMATABLE)==0) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); } - RNA_def_property_duplicate_pointers(prop); - Py_RETURN_NONE; - } - else { /* operators defer running this function */ - return bpy_prop_deferred_return((void *)BPy_IntProperty, kw); + RNA_def_property_duplicate_pointers(srna, prop); } + Py_RETURN_NONE; } -char BPy_IntVectorProperty_doc[] = +static char BPy_IntVectorProperty_doc[] = ".. function:: IntVectorProperty(name=\"\", description=\"\", default=(0, 0, 0), min=-sys.maxint, max=sys.maxint, soft_min=-sys.maxint, soft_max=sys.maxint, options={'ANIMATABLE'}, subtype='NONE', size=3)\n" "\n" " Returns a new vector int property definition.\n" "\n" +BPY_PROPDEF_NAME_DOC +BPY_PROPDEF_DESC_DOC +" :arg default: sequence of ints the length of *size*.\n" +" :type default: sequence\n" " :arg options: Enumerator in ['HIDDEN', 'ANIMATABLE'].\n" " :type options: set\n" " :arg subtype: Enumerator in ['COLOR', 'TRANSLATION', 'DIRECTION', 'VELOCITY', 'ACCELERATION', 'MATRIX', 'EULER', 'QUATERNION', 'AXISANGLE', 'XYZ', 'COLOR_GAMMA', 'LAYER', 'NONE'].\n" -" :type subtype: string"; -PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw) +" :type subtype: string\n" +" :arg size: Vector dimensions in [1, and " STRINGIFY(PYRNA_STACK_ARRAY) "].\n" +" :type size: int\n" +; +static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - if (PyTuple_GET_SIZE(args) > 0) { - PyErr_SetString(PyExc_ValueError, "all args must be keywords"); - return NULL; - } + BPY_PROPDEF_HEAD(IntVectorProperty) - srna= srna_from_self(self, "IntVectorProperty(...):"); - if(srna==NULL && PyErr_Occurred()) { - return NULL; /* self's type was compatible but error getting the srna */ - } - else if(srna) { + if(srna) { static const char *kwlist[] = {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "options", "subtype", "size", NULL}; - char *id=NULL, *name="", *description=""; + const char *id=NULL, *name="", *description=""; + int id_len; int min=INT_MIN, max=INT_MAX, soft_min=INT_MIN, soft_max=INT_MAX, step=1, def[PYRNA_STACK_ARRAY]={0}; int size=3; PropertyRNA *prop; @@ -344,24 +380,13 @@ PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw) char *pysubtype= NULL; int subtype= PROP_NONE; - if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssOiiiiO!si:IntVectorProperty", (char **)kwlist, &id, &name, &description, &pydef, &min, &max, &soft_min, &soft_max, &PySet_Type, &pyopts, &pysubtype, &size)) + 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; - if(RNA_def_property_free_identifier(srna, id) == -1) { - PyErr_Format(PyExc_TypeError, "IntVectorProperty(): '%s' is defined as a non-dynamic type.", id); - return NULL; - } - - if(pyopts && pyrna_set_to_enum_bitfield(property_flag_items, pyopts, &opts, "IntVectorProperty(options={...}):")) - return NULL; - - if(pysubtype && RNA_enum_value_from_id(property_subtype_array_items, pysubtype, &subtype)==0) { - PyErr_Format(PyExc_TypeError, "IntVectorProperty(subtype='%s'): invalid subtype.", pysubtype); - return NULL; - } + 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 %d.", size, PYRNA_STACK_ARRAY); + PyErr_Format(PyExc_TypeError, "IntVectorProperty(size=%d): size must be between 0 and " STRINGIFY(PYRNA_STACK_ARRAY), size); return NULL; } @@ -379,42 +404,36 @@ PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw) if(opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN); if((opts & PROP_ANIMATABLE)==0) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); } - RNA_def_property_duplicate_pointers(prop); - Py_RETURN_NONE; - } - else { /* operators defer running this function */ - return bpy_prop_deferred_return((void *)BPy_IntVectorProperty, kw); + RNA_def_property_duplicate_pointers(srna, prop); } + Py_RETURN_NONE; } -char BPy_FloatProperty_doc[] = +static char BPy_FloatProperty_doc[] = ".. function:: FloatProperty(name=\"\", description=\"\", default=0.0, min=sys.float_info.min, max=sys.float_info.max, soft_min=sys.float_info.min, soft_max=sys.float_info.max, step=3, precision=2, options={'ANIMATABLE'}, subtype='NONE', unit='NONE')\n" "\n" " Returns a new float property definition.\n" "\n" +BPY_PROPDEF_NAME_DOC +BPY_PROPDEF_DESC_DOC " :arg options: Enumerator in ['HIDDEN', 'ANIMATABLE'].\n" " :type options: set\n" " :arg subtype: Enumerator in ['UNSIGNED', 'PERCENTAGE', 'FACTOR', 'ANGLE', 'TIME', 'DISTANCE', 'NONE'].\n" " :type subtype: string\n" " :arg unit: Enumerator in ['NONE', 'LENGTH', 'AREA', 'VOLUME', 'ROTATION', 'TIME', 'VELOCITY', 'ACCELERATION'].\n" -" :type unit: string\n"; -PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) +" :type unit: string\n" +; +static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - if (PyTuple_GET_SIZE(args) > 0) { - PyErr_SetString(PyExc_ValueError, "all args must be keywords"); - return NULL; - } + BPY_PROPDEF_HEAD(FloatProperty) - srna= srna_from_self(self, "FloatProperty(...):"); - if(srna==NULL && PyErr_Occurred()) { - return NULL; /* self's type was compatible but error getting the srna */ - } - else if(srna) { + if(srna) { static const char *kwlist[] = {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "precision", "options", "subtype", "unit", NULL}; - char *id=NULL, *name="", *description=""; + const char *id=NULL, *name="", *description=""; + int id_len; float min=-FLT_MAX, max=FLT_MAX, soft_min=-FLT_MAX, soft_max=FLT_MAX, step=3, def=0.0f; int precision= 2; PropertyRNA *prop; @@ -425,24 +444,13 @@ PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) char *pyunit= NULL; int unit= PROP_UNIT_NONE; - if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssffffffiO!ss:FloatProperty", (char **)kwlist, &id, &name, &description, &def, &min, &max, &soft_min, &soft_max, &step, &precision, &PySet_Type, &pyopts, &pysubtype, &pyunit)) - return NULL; - - if(RNA_def_property_free_identifier(srna, id) == -1) { - PyErr_Format(PyExc_TypeError, "FloatProperty(): '%s' is defined as a non-dynamic type.", id); - return NULL; - } - - if(pyopts && pyrna_set_to_enum_bitfield(property_flag_items, pyopts, &opts, "FloatProperty(options={...}):")) + 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; - if(pysubtype && RNA_enum_value_from_id(property_subtype_number_items, pysubtype, &subtype)==0) { - PyErr_Format(PyExc_TypeError, "FloatProperty(subtype='%s'): invalid subtype.", pysubtype); - return NULL; - } + 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."); + PyErr_Format(PyExc_TypeError, "FloatProperty(unit='%s'): invalid unit"); return NULL; } @@ -456,39 +464,37 @@ PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) if(opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN); if((opts & PROP_ANIMATABLE)==0) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); } - RNA_def_property_duplicate_pointers(prop); - Py_RETURN_NONE; - } - else { /* operators defer running this function */ - return bpy_prop_deferred_return((void *)BPy_FloatProperty, kw); + RNA_def_property_duplicate_pointers(srna, prop); } + Py_RETURN_NONE; } -char BPy_FloatVectorProperty_doc[] = +static char BPy_FloatVectorProperty_doc[] = ".. function:: FloatVectorProperty(name=\"\", description=\"\", default=(0.0, 0.0, 0.0), min=sys.float_info.min, max=sys.float_info.max, soft_min=sys.float_info.min, soft_max=sys.float_info.max, step=3, precision=2, options={'ANIMATABLE'}, subtype='NONE', size=3)\n" "\n" " Returns a new vector float property definition.\n" "\n" +BPY_PROPDEF_NAME_DOC +BPY_PROPDEF_DESC_DOC +" :arg default: sequence of floats the length of *size*.\n" +" :type default: sequence\n" " :arg options: Enumerator in ['HIDDEN', 'ANIMATABLE'].\n" " :type options: set\n" " :arg subtype: Enumerator in ['COLOR', 'TRANSLATION', 'DIRECTION', 'VELOCITY', 'ACCELERATION', 'MATRIX', 'EULER', 'QUATERNION', 'AXISANGLE', 'XYZ', 'COLOR_GAMMA', 'LAYER', 'NONE'].\n" -" :type subtype: string"; -PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw) +" :type subtype: string\n" +" :arg size: Vector dimensions in [1, and " STRINGIFY(PYRNA_STACK_ARRAY) "].\n" +" :type size: int\n" +; +static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - if (PyTuple_GET_SIZE(args) > 0) { - PyErr_SetString(PyExc_ValueError, "all args must be keywords"); - return NULL; - } + BPY_PROPDEF_HEAD(FloatVectorProperty) - srna= srna_from_self(self, "FloatVectorProperty(...):"); - if(srna==NULL && PyErr_Occurred()) { - return NULL; /* self's type was compatible but error getting the srna */ - } - else if(srna) { + if(srna) { static const char *kwlist[] = {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "precision", "options", "subtype", "size", NULL}; - char *id=NULL, *name="", *description=""; + const char *id=NULL, *name="", *description=""; + int id_len; float min=-FLT_MAX, max=FLT_MAX, soft_min=-FLT_MAX, soft_max=FLT_MAX, step=3, def[PYRNA_STACK_ARRAY]={0.0f}; int precision= 2, size=3; PropertyRNA *prop; @@ -498,24 +504,13 @@ PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw) char *pysubtype= NULL; int subtype= PROP_NONE; - if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssOfffffiO!si:FloatVectorProperty", (char **)kwlist, &id, &name, &description, &pydef, &min, &max, &soft_min, &soft_max, &step, &precision, &PySet_Type, &pyopts, &pysubtype, &size)) + 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; - if(RNA_def_property_free_identifier(srna, id) == -1) { - PyErr_Format(PyExc_TypeError, "FloatVectorProperty(): '%s' is defined as a non-dynamic type.", id); - return NULL; - } - - if(pyopts && pyrna_set_to_enum_bitfield(property_flag_items, pyopts, &opts, "FloatVectorProperty(options={...}):")) - return NULL; - - if(pysubtype && RNA_enum_value_from_id(property_subtype_array_items, pysubtype, &subtype)==0) { - PyErr_Format(PyExc_TypeError, "FloatVectorProperty(subtype='%s'): invalid subtype.", pysubtype); - return NULL; - } + 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 %d.", size, PYRNA_STACK_ARRAY); + PyErr_Format(PyExc_TypeError, "FloatVectorProperty(size=%d): size must be between 0 and " STRINGIFY(PYRNA_STACK_ARRAY), size); return NULL; } @@ -533,39 +528,33 @@ PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw) if(opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN); if((opts & PROP_ANIMATABLE)==0) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); } - RNA_def_property_duplicate_pointers(prop); - Py_RETURN_NONE; - } - else { /* operators defer running this function */ - return bpy_prop_deferred_return((void *)BPy_FloatVectorProperty, kw); + RNA_def_property_duplicate_pointers(srna, prop); } + Py_RETURN_NONE; } -char BPy_StringProperty_doc[] = +static char BPy_StringProperty_doc[] = ".. function:: StringProperty(name=\"\", description=\"\", default=\"\", maxlen=0, options={'ANIMATABLE'}, subtype='NONE')\n" "\n" " Returns a new string property definition.\n" "\n" +BPY_PROPDEF_NAME_DOC +BPY_PROPDEF_DESC_DOC " :arg options: Enumerator in ['HIDDEN', 'ANIMATABLE'].\n" " :type options: set\n" " :arg subtype: Enumerator in ['FILE_PATH', 'DIR_PATH', 'FILENAME', 'NONE'].\n" -" :type subtype: string"; -PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw) +" :type subtype: string\n" +; +static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - if (PyTuple_GET_SIZE(args) > 0) { - PyErr_SetString(PyExc_ValueError, "all args must be keywords"); - return NULL; - } + BPY_PROPDEF_HEAD(StringProperty) - srna= srna_from_self(self, "StringProperty(...):"); - if(srna==NULL && PyErr_Occurred()) { - return NULL; /* self's type was compatible but error getting the srna */ - } - else if(srna) { + if(srna) { static const char *kwlist[] = {"attr", "name", "description", "default", "maxlen", "options", "subtype", NULL}; - char *id=NULL, *name="", *description="", *def=""; + const char *id=NULL, *name="", *description="", *def=""; + int id_len; int maxlen=0; PropertyRNA *prop; PyObject *pyopts= NULL; @@ -573,21 +562,10 @@ PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw) char *pysubtype= NULL; int subtype= PROP_NONE; - if (!PyArg_ParseTupleAndKeywords(args, kw, "s|sssiO!s:StringProperty", (char **)kwlist, &id, &name, &description, &def, &maxlen, &PySet_Type, &pyopts, &pysubtype)) - return NULL; - - if(RNA_def_property_free_identifier(srna, id) == -1) { - PyErr_Format(PyExc_TypeError, "StringProperty(): '%s' is defined as a non-dynamic type.", id); + if (!PyArg_ParseTupleAndKeywords(args, kw, "s#|sssiO!s:StringProperty", (char **)kwlist, &id, &id_len, &name, &description, &def, &maxlen, &PySet_Type, &pyopts, &pysubtype)) return NULL; - } - if(pyopts && pyrna_set_to_enum_bitfield(property_flag_items, pyopts, &opts, "StringProperty(options={...}):")) - return NULL; - - if(pysubtype && RNA_enum_value_from_id(property_subtype_string_items, pysubtype, &subtype)==0) { - PyErr_Format(PyExc_TypeError, "StringProperty(subtype='%s'): invalid subtype.", pysubtype); - return NULL; - } + 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 */ @@ -598,185 +576,221 @@ PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw) if(opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN); if((opts & PROP_ANIMATABLE)==0) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); } - RNA_def_property_duplicate_pointers(prop); - Py_RETURN_NONE; - } - else { /* operators defer running this function */ - return bpy_prop_deferred_return((void *)BPy_StringProperty, kw); + RNA_def_property_duplicate_pointers(srna, prop); } + Py_RETURN_NONE; } -static EnumPropertyItem *enum_items_from_py(PyObject *value, const char *def, int *defvalue) +static EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, 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"); - return NULL; + seq_len= PySequence_Fast_GET_SIZE(seq_fast); + + 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; - seq_len = PySequence_Length(value); 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"); + item= PySequence_Fast_GET_ITEM(seq_fast, i); + if(PyTuple_Check(item)==0) { + 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"); - Py_DECREF(item); + PyErr_SetString(PyExc_TypeError, "EnumProperty(...): expected an identifier, name and description in the tuple"); return NULL; } - tmp.value= i; - RNA_enum_item_add(&items, &totitem, &tmp); + if(is_enum_flag) { + tmp.value= 1<<i; - if(def[0] && strcmp(def, tmp.identifier) == 0) - *defvalue= tmp.value; + if(def && PySet_Contains(def, PyTuple_GET_ITEM(item, 0))) { + *defvalue |= tmp.value; + def_used++; + } + } + else { + tmp.value= i; - Py_DECREF(item); - } + if(def && def_used == 0 && strcmp(def_cmp, tmp.identifier)==0) { + *defvalue= tmp.value; + def_used++; /* only ever 1 */ + } + } - if(!def[0]) - *defvalue= 0; + RNA_enum_item_add(&items, &totitem, &tmp); + } 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); + + PyErr_Format(PyExc_TypeError, "EnumProperty(..., default=\'%s\'): not found in enum members", def); + return NULL; + } + } + return items; } -char BPy_EnumProperty_doc[] = +static char BPy_EnumProperty_doc[] = ".. function:: EnumProperty(items, name=\"\", description=\"\", default=\"\", options={'ANIMATABLE'})\n" "\n" " Returns a new enumerator property definition.\n" "\n" -" :arg options: Enumerator in ['HIDDEN', 'ANIMATABLE'].\n" +BPY_PROPDEF_NAME_DOC +BPY_PROPDEF_DESC_DOC +" :arg default: The default value for this enum, A string when *ENUM_FLAG* is disabled otherwise a set which may only contain string identifiers used in *items*.\n" +" :type default: string or set\n" +" :arg options: Enumerator in ['HIDDEN', 'ANIMATABLE', 'ENUM_FLAG'].\n" " :type options: set\n" -" :arg items: The items that make up this enumerator.\n" -" :type items: sequence of string triplets"; -PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw) +" :arg items: sequence of enum items formatted: [(identifier, name, description), ...] where the identifier is used for python access and other values are used for the interface.\n" +" :type items: sequence of string triplets\n" +; +static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - if (PyTuple_GET_SIZE(args) > 0) { - PyErr_SetString(PyExc_ValueError, "all args must be keywords"); - return NULL; - } - - srna= srna_from_self(self, "EnumProperty(...):"); - if(srna==NULL && PyErr_Occurred()) { - return NULL; /* self's type was compatible but error getting the srna */ - } - else if(srna) { + BPY_PROPDEF_HEAD(EnumProperty) + + if(srna) { static const char *kwlist[] = {"attr", "items", "name", "description", "default", "options", NULL}; - char *id=NULL, *name="", *description="", *def=""; + const char *id=NULL, *name="", *description=""; + PyObject *def= NULL; + int id_len; int defvalue=0; - PyObject *items= Py_None; + PyObject *items, *items_fast; EnumPropertyItem *eitems; PropertyRNA *prop; PyObject *pyopts= NULL; int opts=0; - if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|sssO!:EnumProperty", (char **)kwlist, &id, &items, &name, &description, &def, &PySet_Type, &pyopts)) + if (!PyArg_ParseTupleAndKeywords(args, kw, "s#O|ssOO!:EnumProperty", (char **)kwlist, &id, &id_len, &items, &name, &description, &def, &PySet_Type, &pyopts)) return NULL; - if(RNA_def_property_free_identifier(srna, id) == -1) { - PyErr_Format(PyExc_TypeError, "EnumProperty(): '%s' is defined as a non-dynamic type.", id); + BPY_PROPDEF_CHECK(EnumProperty, property_flag_enum_items) + + if(!(items_fast= PySequence_Fast(items, "EnumProperty(...): expected a sequence of tuples for the enum items"))) { return NULL; } - if(pyopts && pyrna_set_to_enum_bitfield(property_flag_items, pyopts, &opts, "EnumProperty(options={...}):")) - return NULL; + eitems= enum_items_from_py(items_fast, def, &defvalue, (opts & PROP_ENUM_FLAG)!=0); + + Py_DECREF(items_fast); - eitems= enum_items_from_py(items, def, &defvalue); if(!eitems) return NULL; - prop= RNA_def_enum(srna, id, eitems, defvalue, name, description); + if(opts & PROP_ENUM_FLAG) prop= RNA_def_enum_flag(srna, id, eitems, defvalue, name, description); + else prop= RNA_def_enum(srna, id, eitems, defvalue, name, description); + if(pyopts) { if(opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN); if((opts & PROP_ANIMATABLE)==0) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); } - RNA_def_property_duplicate_pointers(prop); + RNA_def_property_duplicate_pointers(srna, prop); MEM_freeN(eitems); - - Py_RETURN_NONE; - } - else { /* operators defer running this function */ - return bpy_prop_deferred_return((void *)BPy_EnumProperty, kw); } + Py_RETURN_NONE; } static StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix) { StructRNA *srna; - srna= srna_from_self(value, "BoolProperty(...):"); + srna= srna_from_self(value, ""); if(!srna) { - - PyObject *msg= PyC_ExceptionBuffer(); - char *msg_char= _PyUnicode_AsString(msg); - PyErr_Format(PyExc_TypeError, "%.200s expected an RNA type derived from IDPropertyGroup, failed with: %s", error_prefix, msg_char); - Py_DECREF(msg); + if(PyErr_Occurred()) { + PyObject *msg= PyC_ExceptionBuffer(); + char *msg_char= _PyUnicode_AsString(msg); + PyErr_Format(PyExc_TypeError, "%.200s expected an RNA type derived from PropertyGroup, failed with: %s", error_prefix, msg_char); + Py_DECREF(msg); + } + else { + PyErr_Format(PyExc_TypeError, "%.200s expected an RNA type derived from PropertyGroup, failed with type '%s'", error_prefix, Py_TYPE(value)->tp_name); + } return NULL; } - if(!RNA_struct_is_a(srna, &RNA_IDPropertyGroup)) { - PyErr_Format(PyExc_SystemError, "%.200s expected an RNA type derived from IDPropertyGroup", error_prefix); + if(!RNA_struct_is_a(srna, &RNA_PropertyGroup)) { + PyErr_Format(PyExc_TypeError, "%.200s expected an RNA type derived from PropertyGroup", error_prefix); return NULL; } return srna; } -char BPy_PointerProperty_doc[] = -".. function:: PointerProperty(items, type=\"\", description=\"\", default=\"\", options={'ANIMATABLE'})\n" +static char BPy_PointerProperty_doc[] = +".. function:: PointerProperty(type=\"\", description=\"\", options={'ANIMATABLE'})\n" "\n" " Returns a new pointer property definition.\n" "\n" +" :arg type: A subclass of :class:`bpy.types.PropertyGroup`.\n" +" :type type: class\n" +BPY_PROPDEF_NAME_DOC +BPY_PROPDEF_DESC_DOC " :arg options: Enumerator in ['HIDDEN', 'ANIMATABLE'].\n" " :type options: set\n" -" :arg type: Dynamic type from :mod:`bpy.types`.\n" -" :type type: class"; -PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) +; +static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - if (PyTuple_GET_SIZE(args) > 0) { - PyErr_SetString(PyExc_ValueError, "all args must be keywords"); - return NULL; - } + BPY_PROPDEF_HEAD(PointerProperty) - srna= srna_from_self(self, "PointerProperty(...):"); - if(srna==NULL && PyErr_Occurred()) { - return NULL; /* self's type was compatible but error getting the srna */ - } - else if(srna) { + if(srna) { static const char *kwlist[] = {"attr", "type", "name", "description", "options", NULL}; - char *id=NULL, *name="", *description=""; + const char *id=NULL, *name="", *description=""; + int id_len; PropertyRNA *prop; StructRNA *ptype; PyObject *type= Py_None; PyObject *pyopts= NULL; int opts=0; - if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|ssO!:PointerProperty", (char **)kwlist, &id, &type, &name, &description, &PySet_Type, &pyopts)) - return NULL; - - if(RNA_def_property_free_identifier(srna, id) == -1) { - PyErr_Format(PyExc_TypeError, "PointerProperty(): '%s' is defined as a non-dynamic type.", id); + if (!PyArg_ParseTupleAndKeywords(args, kw, "s#O|ssO!:PointerProperty", (char **)kwlist, &id, &id_len, &type, &name, &description, &PySet_Type, &pyopts)) return NULL; - } - if(pyopts && pyrna_set_to_enum_bitfield(property_flag_items, pyopts, &opts, "PointerProperty(options={...}):")) - return NULL; + BPY_PROPDEF_CHECK(PointerProperty, property_flag_items) ptype= pointer_type_from_py(type, "PointerProperty(...):"); if(!ptype) @@ -787,56 +801,43 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) if(opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN); if((opts & PROP_ANIMATABLE)==0) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); } - RNA_def_property_duplicate_pointers(prop); - Py_RETURN_NONE; - } - else { /* operators defer running this function */ - return bpy_prop_deferred_return((void *)BPy_PointerProperty, kw); + RNA_def_property_duplicate_pointers(srna, prop); } - return NULL; + Py_RETURN_NONE; } -char BPy_CollectionProperty_doc[] = +static char BPy_CollectionProperty_doc[] = ".. function:: CollectionProperty(items, type=\"\", description=\"\", default=\"\", options={'ANIMATABLE'})\n" "\n" " Returns a new collection property definition.\n" "\n" +" :arg type: A subclass of :class:`bpy.types.PropertyGroup`.\n" +" :type type: class\n" +BPY_PROPDEF_NAME_DOC +BPY_PROPDEF_DESC_DOC " :arg options: Enumerator in ['HIDDEN', 'ANIMATABLE'].\n" " :type options: set\n" -" :arg type: Dynamic type from :mod:`bpy.types`.\n" -" :type type: class"; -PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) +; +static PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - if (PyTuple_GET_SIZE(args) > 0) { - PyErr_SetString(PyExc_ValueError, "all args must be keywords"); - return NULL; - } + BPY_PROPDEF_HEAD(CollectionProperty) - srna= srna_from_self(self, "CollectionProperty(...):"); - if(srna==NULL && PyErr_Occurred()) { - return NULL; /* self's type was compatible but error getting the srna */ - } - else if(srna) { + if(srna) { static const char *kwlist[] = {"attr", "type", "name", "description", "options", NULL}; - char *id=NULL, *name="", *description=""; + const char *id=NULL, *name="", *description=""; + int id_len; PropertyRNA *prop; StructRNA *ptype; PyObject *type= Py_None; PyObject *pyopts= NULL; int opts=0; - if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|ssO!:CollectionProperty", (char **)kwlist, &id, &type, &name, &description, &PySet_Type, &pyopts)) + if (!PyArg_ParseTupleAndKeywords(args, kw, "s#O|ssO!:CollectionProperty", (char **)kwlist, &id, &id_len, &type, &name, &description, &PySet_Type, &pyopts)) return NULL; - if(RNA_def_property_free_identifier(srna, id) == -1) { - PyErr_Format(PyExc_TypeError, "CollectionProperty(): '%s' is defined as a non-dynamic type.", id); - return NULL; - } - - if(pyopts && pyrna_set_to_enum_bitfield(property_flag_items, pyopts, &opts, "CollectionProperty(options={...}):")) - return NULL; + BPY_PROPDEF_CHECK(CollectionProperty, property_flag_items) ptype= pointer_type_from_py(type, "CollectionProperty(...):"); if(!ptype) @@ -847,32 +848,42 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) if(opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN); if((opts & PROP_ANIMATABLE)==0) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); } - RNA_def_property_duplicate_pointers(prop); - Py_RETURN_NONE; - } - else { /* operators defer running this function */ - return bpy_prop_deferred_return((void *)BPy_CollectionProperty, kw); + RNA_def_property_duplicate_pointers(srna, prop); } - return NULL; + Py_RETURN_NONE; } -char BPy_RemoveProperty_doc[] = +static char BPy_RemoveProperty_doc[] = ".. function:: RemoveProperty(attr)\n" "\n" " Removes a dynamically defined property.\n" "\n" " :arg attr: Property name.\n" -" :type attr: string"; -PyObject *BPy_RemoveProperty(PyObject *self, PyObject *args, PyObject *kw) +" :type attr: string\n" +; +static PyObject *BPy_RemoveProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; + if(PyTuple_GET_SIZE(args) == 1) { + PyObject *ret; + self= PyTuple_GET_ITEM(args, 0); + args= PyTuple_New(0); + ret= BPy_RemoveProperty(self, args, kw); + Py_DECREF(args); + return ret; + } + else if (PyTuple_GET_SIZE(args) > 1) { + PyErr_SetString(PyExc_ValueError, "all args must be keywords"); \ + return NULL; + } + srna= srna_from_self(self, "RemoveProperty(...):"); if(srna==NULL && PyErr_Occurred()) { return NULL; /* self's type was compatible but error getting the srna */ } else if(srna==NULL) { - PyErr_SetString(PyExc_TypeError, "RemoveProperty(): struct rna not available for this type."); + PyErr_SetString(PyExc_TypeError, "RemoveProperty(): struct rna not available for this type"); return NULL; } else { @@ -884,12 +895,11 @@ PyObject *BPy_RemoveProperty(PyObject *self, PyObject *args, PyObject *kw) return NULL; if(RNA_def_property_free_identifier(srna, id) != 1) { - PyErr_Format(PyExc_TypeError, "RemoveProperty(): '%s' not a defined dynamic property.", id); + PyErr_Format(PyExc_TypeError, "RemoveProperty(): '%s' not a defined dynamic property", id); return NULL; } - - Py_RETURN_NONE; } + Py_RETURN_NONE; } static struct PyMethodDef props_methods[] = { @@ -904,8 +914,7 @@ static struct PyMethodDef props_methods[] = { {"PointerProperty", (PyCFunction)BPy_PointerProperty, METH_VARARGS|METH_KEYWORDS, BPy_PointerProperty_doc}, {"CollectionProperty", (PyCFunction)BPy_CollectionProperty, METH_VARARGS|METH_KEYWORDS, BPy_CollectionProperty_doc}, - /* only useful as a bpy_struct method */ - /* {"RemoveProperty", (PyCFunction)BPy_RemoveProperty, METH_VARARGS|METH_KEYWORDS, BPy_RemoveProperty_doc}, */ + {"RemoveProperty", (PyCFunction)BPy_RemoveProperty, METH_VARARGS|METH_KEYWORDS, BPy_RemoveProperty_doc}, {NULL, NULL, 0, NULL} }; @@ -922,6 +931,8 @@ static struct PyModuleDef props_module = { PyObject *BPY_rna_props( void ) { PyObject *submodule; + PyObject *submodule_dict; + submodule= PyModule_Create(&props_module); PyDict_SetItemString(PyImport_GetModuleDict(), props_module.m_name, submodule); @@ -929,6 +940,23 @@ PyObject *BPY_rna_props( void ) * module with a new ref like PyDict_New, since they are passed to * PyModule_AddObject which steals a ref */ Py_INCREF(submodule); - + + /* api needs the PyObjects internally */ + submodule_dict= PyModule_GetDict(submodule); + +#define ASSIGN_STATIC(_name) pymeth_##_name = PyDict_GetItemString(submodule_dict, #_name) + + ASSIGN_STATIC(BoolProperty); + ASSIGN_STATIC(BoolVectorProperty); + ASSIGN_STATIC(IntProperty); + ASSIGN_STATIC(IntVectorProperty); + ASSIGN_STATIC(FloatProperty); + ASSIGN_STATIC(FloatVectorProperty); + ASSIGN_STATIC(StringProperty); + ASSIGN_STATIC(EnumProperty); + ASSIGN_STATIC(PointerProperty); + ASSIGN_STATIC(CollectionProperty); + ASSIGN_STATIC(RemoveProperty); + return submodule; } |