Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2011-06-06 21:50:20 +0400
committerCampbell Barton <ideasman42@gmail.com>2011-06-06 21:50:20 +0400
commit8cee3285460b82a5f64901a8610b07b63bd95701 (patch)
tree755e2eb20837a6a015168ddd5b6df77e64885137 /source/blender/python/intern
parent0c1298f9727a2de61dd0d28944f4af5873a65668 (diff)
Support for update callbacks in python defined RNA properties as discussed last meeting.
This means script authors can perform actions using these callbacks rather then on drawing which puts blender in a readonly state. Simple example: import bpy def up_func(self, context): print("test") bpy.types.Scene.testprop = bpy.props.FloatProperty(update=up_func) bpy.context.scene.testprop = 11 # prints -> test
Diffstat (limited to 'source/blender/python/intern')
-rw-r--r--source/blender/python/intern/bpy_props.c304
1 files changed, 240 insertions, 64 deletions
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 4fef084f093..c6576fe2319 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -47,6 +47,11 @@
#include "../generic/py_capi_utils.h"
+/* initial definition of callback slots we'll probably have more then 1 */
+#define BPY_DATA_CB_SLOT_SIZE 1
+
+#define BPY_DATA_CB_SLOT_UPDATE 0
+
extern BPy_StructRNA *bpy_context_module;
static EnumPropertyItem property_flag_items[]= {
@@ -110,6 +115,45 @@ static PyObject *pymeth_PointerProperty= NULL;
static PyObject *pymeth_CollectionProperty= NULL;
static PyObject *pymeth_RemoveProperty= NULL;
+PyObject *pyrna_struct_as_instance(PointerRNA *ptr)
+{
+ PyObject *self= NULL;
+ /* first get self */
+ /* operators can store their own instance for later use */
+ if(ptr->data) {
+ void **instance= RNA_struct_instance(ptr);
+
+ if(instance) {
+ if(*instance) {
+ self= *instance;
+ Py_INCREF(self);
+ }
+ }
+ }
+
+ /* in most cases this will run */
+ if(self == NULL) {
+ self= pyrna_struct_CreatePyObject(ptr);
+ }
+
+ return self;
+}
+
+/* could be moved into bpy_utils */
+static void printf_func_error(PyObject *py_func)
+{
+ /* since we return to C code we can't leave the error */
+ PyCodeObject *f_code= (PyCodeObject *)PyFunction_GET_CODE(py_func);
+ PyErr_Print();
+ PyErr_Clear();
+
+ /* use py style error */
+ fprintf(stderr, "File \"%s\", line %d, in %s\n",
+ _PyUnicode_AsString(f_code->co_filename),
+ f_code->co_firstlineno,
+ _PyUnicode_AsString(((PyFunctionObject *)py_func)->func_name)
+ );
+}
/* 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
@@ -130,6 +174,87 @@ static PyObject *bpy_prop_deferred_return(PyObject *func, PyObject *kw)
return ret;
}
+/* callbacks */
+void bpy_prop_update_cb(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop)
+{
+ PyGILState_STATE gilstate;
+ PyObject **py_data= (PyObject **)RNA_property_py_data_get(prop);
+ PyObject *py_func;
+ PyObject *args;
+ PyObject *self;
+ PyObject *ret;
+
+ BLI_assert(py_data != NULL);
+
+ bpy_context_set(C, &gilstate);
+
+ py_func= py_data[BPY_DATA_CB_SLOT_UPDATE];
+
+ args= PyTuple_New(2);
+ self= pyrna_struct_as_instance(ptr);
+ PyTuple_SET_ITEM(args, 0, self);
+
+ PyTuple_SET_ITEM(args, 1, (PyObject *)bpy_context_module);
+ Py_INCREF(bpy_context_module);
+
+ ret= PyObject_CallObject(py_func, args);
+
+ Py_DECREF(args);
+
+ if(ret == NULL) {
+ printf_func_error(py_func);
+ }
+ else {
+ if(ret != Py_None) {
+ PyErr_SetString(PyExc_ValueError, "the return value must be None");
+ printf_func_error(py_func);
+ }
+
+ Py_DECREF(ret);
+ }
+
+ bpy_context_clear(C, &gilstate);
+}
+
+static int bpy_prop_callback_check(PyObject *py_func, int argcount)
+{
+ if(py_func) {
+ if(!PyFunction_Check(py_func)) {
+ PyErr_Format(PyExc_TypeError,
+ "update keyword: expected a function type, not a %.200s",
+ Py_TYPE(py_func)->tp_name);
+ return -1;
+ }
+ else {
+ PyCodeObject *f_code= (PyCodeObject *)PyFunction_GET_CODE(py_func);
+ if (f_code->co_argcount != argcount) {
+ PyErr_Format(PyExc_TypeError,
+ "update keyword: expected a function taking %d arguments, not %d",
+ argcount, f_code->co_argcount);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static int bpy_prop_callback_assign(struct PropertyRNA *prop, PyObject *update_cb)
+{
+ /* assume this is already checked for type and arg length */
+ if(update_cb) {
+ PyObject **py_data= MEM_callocN(sizeof(PyObject *) * BPY_DATA_CB_SLOT_SIZE, "bpy_prop_callback_assign");
+ RNA_def_property_update_runtime(prop, (void *)bpy_prop_update_cb);
+ py_data[BPY_DATA_CB_SLOT_UPDATE]= update_cb;
+ RNA_def_py_data(prop, py_data);
+
+ RNA_def_property_flag(prop, PROP_CONTEXT_PROPERTY_UPDATE);
+ }
+
+ return 0;
+}
+
/* this define runs at the start of each function and deals with
* returning a deferred property (to be registered later) */
#define BPY_PROPDEF_HEAD(_func) \
@@ -184,6 +309,11 @@ static PyObject *bpy_prop_deferred_return(PyObject *func, PyObject *kw)
" :type description: string\n" \
+#define BPY_PROPDEF_UPDATE_DOC \
+" :arg update: function to be called when this value is modified,\n" \
+" This function must take 2 values (self, context) and return None.\n" \
+" :type update: function\n" \
+
#if 0
static int bpy_struct_id_used(StructRNA *srna, char *identifier)
{
@@ -197,7 +327,7 @@ 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 */
PyDoc_STRVAR(BPy_BoolProperty_doc,
-".. function:: BoolProperty(name=\"\", description=\"\", default=False, options={'ANIMATABLE'}, subtype='NONE')\n"
+".. function:: BoolProperty(name=\"\", description=\"\", default=False, options={'ANIMATABLE'}, subtype='NONE', update=None)\n"
"\n"
" Returns a new boolean property definition.\n"
"\n"
@@ -207,6 +337,7 @@ BPY_PROPDEF_DESC_DOC
" :type options: set\n"
" :arg subtype: Enumerator in ['UNSIGNED', 'PERCENTAGE', 'FACTOR', 'ANGLE', 'TIME', 'DISTANCE', 'NONE'].\n"
" :type subtype: string\n"
+BPY_PROPDEF_UPDATE_DOC
);
static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -215,7 +346,7 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
BPY_PROPDEF_HEAD(BoolProperty)
if(srna) {
- static const char *kwlist[]= {"attr", "name", "description", "default", "options", "subtype", NULL};
+ static const char *kwlist[]= {"attr", "name", "description", "default", "options", "subtype", "update", NULL};
const char *id=NULL, *name="", *description="";
int id_len;
int def=0;
@@ -224,18 +355,24 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
int opts=0;
char *pysubtype= NULL;
int subtype= PROP_NONE;
+ PyObject *update_cb= NULL;
if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#|ssiO!s:BoolProperty",
+ "s#|ssiO!sO:BoolProperty",
(char **)kwlist, &id, &id_len,
&name, &description, &def,
- &PySet_Type, &pyopts, &pysubtype))
+ &PySet_Type, &pyopts, &pysubtype,
+ &update_cb))
{
return NULL;
}
BPY_PROPDEF_SUBTYPE_CHECK(BoolProperty, property_flag_items, property_subtype_number_items)
+ if (bpy_prop_callback_check(update_cb, 2) == -1) {
+ return NULL;
+ }
+
prop= RNA_def_property(srna, id, PROP_BOOLEAN, subtype);
RNA_def_property_boolean_default(prop, def);
RNA_def_property_ui_text(prop, name, description);
@@ -244,6 +381,7 @@ static 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);
}
+ bpy_prop_callback_assign(prop, update_cb);
RNA_def_property_duplicate_pointers(srna, prop);
}
@@ -251,7 +389,7 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
}
PyDoc_STRVAR(BPy_BoolVectorProperty_doc,
-".. function:: BoolVectorProperty(name=\"\", description=\"\", default=(False, False, False), options={'ANIMATABLE'}, subtype='NONE', size=3)\n"
+".. function:: BoolVectorProperty(name=\"\", description=\"\", default=(False, False, False), options={'ANIMATABLE'}, subtype='NONE', size=3, update=None)\n"
"\n"
" Returns a new vector boolean property definition.\n"
"\n"
@@ -265,6 +403,7 @@ BPY_PROPDEF_DESC_DOC
" :type subtype: string\n"
" :arg size: Vector dimensions in [1, and " STRINGIFY(PYRNA_STACK_ARRAY) "].\n"
" :type size: int\n"
+BPY_PROPDEF_UPDATE_DOC
);
static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -273,7 +412,7 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
BPY_PROPDEF_HEAD(BoolVectorProperty)
if(srna) {
- static const char *kwlist[]= {"attr", "name", "description", "default", "options", "subtype", "size", NULL};
+ static const char *kwlist[]= {"attr", "name", "description", "default", "options", "subtype", "size", "update", NULL};
const char *id=NULL, *name="", *description="";
int id_len;
int def[PYRNA_STACK_ARRAY]={0};
@@ -284,12 +423,14 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
int opts=0;
char *pysubtype= NULL;
int subtype= PROP_NONE;
+ PyObject *update_cb= NULL;
if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#|ssOO!si:BoolVectorProperty",
+ "s#|ssOO!siO:BoolVectorProperty",
(char **)kwlist, &id, &id_len,
&name, &description, &pydef,
- &PySet_Type, &pyopts, &pysubtype,&size))
+ &PySet_Type, &pyopts, &pysubtype, &size,
+ &update_cb))
{
return NULL;
}
@@ -304,6 +445,10 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
if(pydef && PyC_AsArray(def, pydef, size, &PyBool_Type, "BoolVectorProperty(default=sequence)") < 0)
return NULL;
+ if (bpy_prop_callback_check(update_cb, 2) == -1) {
+ return NULL;
+ }
+
// prop= RNA_def_boolean_array(srna, id, size, pydef ? def:NULL, name, description);
prop= RNA_def_property(srna, id, PROP_BOOLEAN, subtype);
RNA_def_property_array(prop, size);
@@ -314,6 +459,7 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
if(opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN);
if((opts & PROP_ANIMATABLE)==0) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
}
+ bpy_prop_callback_assign(prop, update_cb);
RNA_def_property_duplicate_pointers(srna, prop);
}
@@ -321,7 +467,7 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
}
PyDoc_STRVAR(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"
+".. 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', update=None)\n"
"\n"
" Returns a new int property definition.\n"
"\n"
@@ -331,6 +477,7 @@ BPY_PROPDEF_DESC_DOC
" :type options: set\n"
" :arg subtype: Enumerator in ['UNSIGNED', 'PERCENTAGE', 'FACTOR', 'ANGLE', 'TIME', 'DISTANCE', 'NONE'].\n"
" :type subtype: string\n"
+BPY_PROPDEF_UPDATE_DOC
);
static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -339,7 +486,7 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
BPY_PROPDEF_HEAD(IntProperty)
if(srna) {
- static const char *kwlist[]= {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "options", "subtype", NULL};
+ static const char *kwlist[]= {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "options", "subtype", "update", NULL};
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;
@@ -348,19 +495,25 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
int opts=0;
char *pysubtype= NULL;
int subtype= PROP_NONE;
+ PyObject *update_cb= NULL;
if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#|ssiiiiiiO!s:IntProperty",
+ "s#|ssiiiiiiO!sO:IntProperty",
(char **)kwlist, &id, &id_len,
&name, &description, &def,
&min, &max, &soft_min, &soft_max,
- &step, &PySet_Type, &pyopts, &pysubtype))
+ &step, &PySet_Type, &pyopts, &pysubtype,
+ &update_cb))
{
return NULL;
}
BPY_PROPDEF_SUBTYPE_CHECK(IntProperty, property_flag_items, property_subtype_number_items)
+ if (bpy_prop_callback_check(update_cb, 2) == -1) {
+ return NULL;
+ }
+
prop= RNA_def_property(srna, id, PROP_INT, subtype);
RNA_def_property_int_default(prop, def);
RNA_def_property_range(prop, min, max);
@@ -371,13 +524,14 @@ static 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);
}
+ bpy_prop_callback_assign(prop, update_cb);
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
}
PyDoc_STRVAR(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"
+".. 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, update=None)\n"
"\n"
" Returns a new vector int property definition.\n"
"\n"
@@ -391,6 +545,7 @@ BPY_PROPDEF_DESC_DOC
" :type subtype: string\n"
" :arg size: Vector dimensions in [1, and " STRINGIFY(PYRNA_STACK_ARRAY) "].\n"
" :type size: int\n"
+BPY_PROPDEF_UPDATE_DOC
);
static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -399,7 +554,7 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
BPY_PROPDEF_HEAD(IntVectorProperty)
if(srna) {
- static const char *kwlist[]= {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "options", "subtype", "size", NULL};
+ static const char *kwlist[]= {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "options", "subtype", "size", "update", NULL};
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};
@@ -410,14 +565,16 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
int opts=0;
char *pysubtype= NULL;
int subtype= PROP_NONE;
+ PyObject *update_cb= NULL;
if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#|ssOiiiiiO!si:IntVectorProperty",
+ "s#|ssOiiiiiO!siO:IntVectorProperty",
(char **)kwlist, &id, &id_len,
&name, &description, &pydef,
&min, &max, &soft_min, &soft_max,
&step, &PySet_Type, &pyopts,
- &pysubtype, &size))
+ &pysubtype, &size,
+ &update_cb))
{
return NULL;
}
@@ -432,6 +589,10 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
if(pydef && PyC_AsArray(def, pydef, size, &PyLong_Type, "IntVectorProperty(default=sequence)") < 0)
return NULL;
+ if (bpy_prop_callback_check(update_cb, 2) == -1) {
+ return NULL;
+ }
+
prop= RNA_def_property(srna, id, PROP_INT, subtype);
RNA_def_property_array(prop, size);
if(pydef) RNA_def_property_int_array_default(prop, def);
@@ -443,6 +604,7 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
if(opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN);
if((opts & PROP_ANIMATABLE)==0) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
}
+ bpy_prop_callback_assign(prop, update_cb);
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
@@ -450,7 +612,7 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
PyDoc_STRVAR(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"
+".. 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', update=None)\n"
"\n"
" Returns a new float property definition.\n"
"\n"
@@ -462,6 +624,7 @@ BPY_PROPDEF_DESC_DOC
" :type subtype: string\n"
" :arg unit: Enumerator in ['NONE', 'LENGTH', 'AREA', 'VOLUME', 'ROTATION', 'TIME', 'VELOCITY', 'ACCELERATION'].\n"
" :type unit: string\n"
+BPY_PROPDEF_UPDATE_DOC
);
static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -470,7 +633,7 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
BPY_PROPDEF_HEAD(FloatProperty)
if(srna) {
- static const char *kwlist[]= {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "precision", "options", "subtype", "unit", NULL};
+ static const char *kwlist[]= {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "precision", "options", "subtype", "unit", "update", NULL};
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;
@@ -482,14 +645,16 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
int subtype= PROP_NONE;
char *pyunit= NULL;
int unit= PROP_UNIT_NONE;
+ PyObject *update_cb= NULL;
if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#|ssffffffiO!ss:FloatProperty",
+ "s#|ssffffffiO!ssO:FloatProperty",
(char **)kwlist, &id, &id_len,
&name, &description, &def,
&min, &max, &soft_min, &soft_max,
&step, &precision, &PySet_Type,
- &pyopts, &pysubtype, &pyunit))
+ &pyopts, &pysubtype, &pyunit,
+ &update_cb))
{
return NULL;
}
@@ -501,6 +666,10 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
return NULL;
}
+ if (bpy_prop_callback_check(update_cb, 2) == -1) {
+ return NULL;
+ }
+
prop= RNA_def_property(srna, id, PROP_FLOAT, subtype | unit);
RNA_def_property_float_default(prop, def);
RNA_def_property_range(prop, min, max);
@@ -511,13 +680,14 @@ static 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);
}
+ bpy_prop_callback_assign(prop, update_cb);
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
}
PyDoc_STRVAR(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"
+".. 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, update=None)\n"
"\n"
" Returns a new vector float property definition.\n"
"\n"
@@ -531,6 +701,7 @@ BPY_PROPDEF_DESC_DOC
" :type subtype: string\n"
" :arg size: Vector dimensions in [1, and " STRINGIFY(PYRNA_STACK_ARRAY) "].\n"
" :type size: int\n"
+BPY_PROPDEF_UPDATE_DOC
);
static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -539,7 +710,7 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
BPY_PROPDEF_HEAD(FloatVectorProperty)
if(srna) {
- static const char *kwlist[]= {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "precision", "options", "subtype", "size", NULL};
+ static const char *kwlist[]= {"attr", "name", "description", "default", "min", "max", "soft_min", "soft_max", "step", "precision", "options", "subtype", "size", "update", NULL};
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};
@@ -550,14 +721,16 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
int opts=0;
char *pysubtype= NULL;
int subtype= PROP_NONE;
+ PyObject *update_cb= NULL;
if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#|ssOfffffiO!si:FloatVectorProperty",
+ "s#|ssOfffffiO!siO:FloatVectorProperty",
(char **)kwlist, &id, &id_len,
&name, &description, &pydef,
&min, &max, &soft_min, &soft_max,
&step, &precision, &PySet_Type,
- &pyopts, &pysubtype, &size))
+ &pyopts, &pysubtype, &size,
+ &update_cb))
{
return NULL;
}
@@ -572,6 +745,10 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
if(pydef && PyC_AsArray(def, pydef, size, &PyFloat_Type, "FloatVectorProperty(default=sequence)") < 0)
return NULL;
+ if (bpy_prop_callback_check(update_cb, 2) == -1) {
+ return NULL;
+ }
+
prop= RNA_def_property(srna, id, PROP_FLOAT, subtype);
RNA_def_property_array(prop, size);
if(pydef) RNA_def_property_float_array_default(prop, def);
@@ -583,13 +760,14 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
if(opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN);
if((opts & PROP_ANIMATABLE)==0) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
}
+ bpy_prop_callback_assign(prop, update_cb);
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
}
PyDoc_STRVAR(BPy_StringProperty_doc,
-".. function:: StringProperty(name=\"\", description=\"\", default=\"\", maxlen=0, options={'ANIMATABLE'}, subtype='NONE')\n"
+".. function:: StringProperty(name=\"\", description=\"\", default=\"\", maxlen=0, options={'ANIMATABLE'}, subtype='NONE', update=None)\n"
"\n"
" Returns a new string property definition.\n"
"\n"
@@ -599,6 +777,7 @@ BPY_PROPDEF_DESC_DOC
" :type options: set\n"
" :arg subtype: Enumerator in ['FILE_PATH', 'DIR_PATH', 'FILENAME', 'NONE'].\n"
" :type subtype: string\n"
+BPY_PROPDEF_UPDATE_DOC
);
static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -607,7 +786,7 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
BPY_PROPDEF_HEAD(StringProperty)
if(srna) {
- static const char *kwlist[]= {"attr", "name", "description", "default", "maxlen", "options", "subtype", NULL};
+ static const char *kwlist[]= {"attr", "name", "description", "default", "maxlen", "options", "subtype", "update", NULL};
const char *id=NULL, *name="", *description="", *def="";
int id_len;
int maxlen=0;
@@ -616,18 +795,24 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
int opts=0;
char *pysubtype= NULL;
int subtype= PROP_NONE;
+ PyObject *update_cb= NULL;
if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#|sssiO!s:StringProperty",
+ "s#|sssiO!sO:StringProperty",
(char **)kwlist, &id, &id_len,
&name, &description, &def,
- &maxlen, &PySet_Type, &pyopts, &pysubtype))
+ &maxlen, &PySet_Type, &pyopts, &pysubtype,
+ &update_cb))
{
return NULL;
}
BPY_PROPDEF_SUBTYPE_CHECK(StringProperty, property_flag_items, property_subtype_string_items)
+ if (bpy_prop_callback_check(update_cb, 2) == -1) {
+ return NULL;
+ }
+
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 */
if(def) RNA_def_property_string_default(prop, def);
@@ -637,6 +822,7 @@ static 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);
}
+ bpy_prop_callback_assign(prop, update_cb);
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;
@@ -803,23 +989,7 @@ static EnumPropertyItem *bpy_props_enum_itemf(struct bContext *C, PointerRNA *pt
bpy_context_set(C, &gilstate);
args= PyTuple_New(2);
-
- /* first get self */
- /* operators can store their own instance for later use */
- if(ptr->data) {
- void **instance = RNA_struct_instance(ptr);
-
- if(instance) {
- if(*instance) {
- self= *instance;
- Py_INCREF(self);
- }
- }
- }
- if(self == NULL) {
- self= pyrna_struct_CreatePyObject(ptr);
- }
-
+ self= pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEM(args, 0, self);
/* now get the context */
@@ -857,17 +1027,7 @@ static EnumPropertyItem *bpy_props_enum_itemf(struct bContext *C, PointerRNA *pt
*free= 1;
}
else {
- /* since we return to C code we can't leave the error */
- PyCodeObject *f_code= (PyCodeObject *)PyFunction_GET_CODE(py_func);
- PyErr_Print();
- PyErr_Clear();
-
- /* use py style error */
- fprintf(stderr, "File \"%s\", line %d, in %s\n",
- _PyUnicode_AsString(f_code->co_filename),
- f_code->co_firstlineno,
- _PyUnicode_AsString(((PyFunctionObject *)py_func)->func_name)
- );
+ printf_func_error(py_func);
eitems= DummyRNA_NULL_items;
}
@@ -878,7 +1038,7 @@ static EnumPropertyItem *bpy_props_enum_itemf(struct bContext *C, PointerRNA *pt
}
PyDoc_STRVAR(BPy_EnumProperty_doc,
-".. function:: EnumProperty(items, name=\"\", description=\"\", default=\"\", options={'ANIMATABLE'})\n"
+".. function:: EnumProperty(items, name=\"\", description=\"\", default=\"\", options={'ANIMATABLE'}, update=None)\n"
"\n"
" Returns a new enumerator property definition.\n"
"\n"
@@ -897,6 +1057,7 @@ BPY_PROPDEF_DESC_DOC
" the same format as the static list.\n"
" This function must take 2 arguments (self, context)\n"
" :type items: sequence of string triplets or a function\n"
+BPY_PROPDEF_UPDATE_DOC
);
static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -905,7 +1066,7 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
BPY_PROPDEF_HEAD(EnumProperty)
if(srna) {
- static const char *kwlist[]= {"attr", "items", "name", "description", "default", "options", NULL};
+ static const char *kwlist[]= {"attr", "items", "name", "description", "default", "options", "update", NULL};
const char *id=NULL, *name="", *description="";
PyObject *def= NULL;
int id_len;
@@ -916,18 +1077,24 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
PyObject *pyopts= NULL;
int opts=0;
short is_itemf= FALSE;
+ PyObject *update_cb= NULL;
if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#O|ssOO!:EnumProperty",
+ "s#O|ssOO!O:EnumProperty",
(char **)kwlist, &id, &id_len,
&items, &name, &description,
- &def, &PySet_Type, &pyopts))
+ &def, &PySet_Type, &pyopts,
+ &update_cb))
{
return NULL;
}
BPY_PROPDEF_CHECK(EnumProperty, property_flag_enum_items)
+ if (bpy_prop_callback_check(update_cb, 2) == -1) {
+ return NULL;
+ }
+
/* items can be a list or a callable */
if(PyFunction_Check(items)) { /* dont use PyCallable_Check because we need the function code for errors */
PyCodeObject *f_code= (PyCodeObject *)PyFunction_GET_CODE(items);
@@ -975,6 +1142,7 @@ static PyObject *BPy_EnumProperty(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);
}
+ bpy_prop_callback_assign(prop, update_cb);
RNA_def_property_duplicate_pointers(srna, prop);
if(is_itemf == FALSE) {
@@ -1017,7 +1185,7 @@ static StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix
}
PyDoc_STRVAR(BPy_PointerProperty_doc,
-".. function:: PointerProperty(type=\"\", description=\"\", options={'ANIMATABLE'})\n"
+".. function:: PointerProperty(type=\"\", description=\"\", options={'ANIMATABLE'}, update=None)\n"
"\n"
" Returns a new pointer property definition.\n"
"\n"
@@ -1027,6 +1195,7 @@ BPY_PROPDEF_NAME_DOC
BPY_PROPDEF_DESC_DOC
" :arg options: Enumerator in ['HIDDEN', 'ANIMATABLE'].\n"
" :type options: set\n"
+BPY_PROPDEF_UPDATE_DOC
);
static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -1035,7 +1204,7 @@ static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *k
BPY_PROPDEF_HEAD(PointerProperty)
if(srna) {
- static const char *kwlist[]= {"attr", "type", "name", "description", "options", NULL};
+ static const char *kwlist[]= {"attr", "type", "name", "description", "options", "update", NULL};
const char *id=NULL, *name="", *description="";
int id_len;
PropertyRNA *prop;
@@ -1043,12 +1212,14 @@ static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *k
PyObject *type= Py_None;
PyObject *pyopts= NULL;
int opts=0;
+ PyObject *update_cb= NULL;
if (!PyArg_ParseTupleAndKeywords(args, kw,
- "s#O|ssO!:PointerProperty",
+ "s#O|ssO!O:PointerProperty",
(char **)kwlist, &id, &id_len,
&type, &name, &description,
- &PySet_Type, &pyopts))
+ &PySet_Type, &pyopts,
+ &update_cb))
{
return NULL;
}
@@ -1059,11 +1230,16 @@ static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *k
if(!ptype)
return NULL;
+ if (bpy_prop_callback_check(update_cb, 2) == -1) {
+ return NULL;
+ }
+
prop= RNA_def_pointer_runtime(srna, id, ptype, 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);
}
+ bpy_prop_callback_assign(prop, update_cb);
RNA_def_property_duplicate_pointers(srna, prop);
}
Py_RETURN_NONE;