From ee0a217be3114d9b4f50772720312df5f74997e1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 11 Apr 2010 09:13:37 +0000 Subject: [PATCH] python function to remove drivers. eg: bpy.context.object.driver_remove("location") ANIM_remove_driver now accepts -1 as an index for removing all drivers from one path. --- source/blender/blenkernel/BKE_fcurve.h | 2 + source/blender/blenkernel/intern/fcurve.c | 21 ++++ source/blender/editors/animation/drivers.c | 63 ++++++------ source/blender/python/intern/bpy_rna.c | 108 +++++++++++---------- 4 files changed, 113 insertions(+), 81 deletions(-) diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index c4d74f86284..835e2ed80c8 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -187,6 +187,8 @@ void copy_fcurves(ListBase *dst, ListBase *src); /* find matching F-Curve in the given list of F-Curves */ struct FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_index); +struct FCurve *iter_step_fcurve (struct FCurve *fcu_iter, const char rna_path[]); + /* high level function to get an fcurve from C without having the rna */ struct FCurve *id_data_find_fcurve(ID *id, void *data, struct StructRNA *type, char *prop_name, int index); diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 5bfef86b7c6..9bbb6e7b7b6 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -234,6 +234,27 @@ FCurve *list_find_fcurve (ListBase *list, const char rna_path[], const int array return NULL; } +/* quick way to loop over all fcurves of a given 'path' */ +FCurve *iter_step_fcurve (FCurve *fcu_iter, const char rna_path[]) +{ + FCurve *fcu; + + /* sanity checks */ + if (ELEM(NULL, fcu_iter, rna_path)) + return NULL; + + /* check paths of curves, then array indices... */ + for (fcu= fcu_iter; fcu; fcu= fcu->next) { + /* simple string-compare (this assumes that they have the same root...) */ + if (fcu->rna_path && !strcmp(fcu->rna_path, rna_path)) { + return fcu; + } + } + + /* return */ + return NULL; +} + /* Get list of LinkData's containing pointers to the F-Curves which control the types of data indicated * Lists... * - dst: list of LinkData's matching the criteria returned. diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 5024ca39970..3fc228e1c15 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -197,27 +197,42 @@ short ANIM_remove_driver (struct ID *id, const char rna_path[], int array_index, { AnimData *adt; FCurve *fcu; + int success= 0; /* get F-Curve * Note: here is one of the places where we don't want new F-Curve + Driver added! * so 'add' var must be 0 */ /* we don't check the validity of the path here yet, but it should be ok... */ - fcu= verify_driver_fcurve(id, rna_path, array_index, 0); adt= BKE_animdata_from_id(id); - /* only continue if we have an driver to remove */ - if (adt && fcu) { - /* remove F-Curve from driver stack, then free it */ - BLI_remlink(&adt->drivers, fcu); - free_fcurve(fcu); - - /* done successfully */ - return 1; + if(adt) { + if(array_index == -1) { + FCurve *fcu_iter= adt->drivers.first; + while((fcu= iter_step_fcurve(fcu_iter, rna_path))) { + /* store the next fcurve for looping */ + fcu_iter= fcu->next; + + /* remove F-Curve from driver stack, then free it */ + BLI_remlink(&adt->drivers, fcu); + free_fcurve(fcu); + + /* done successfully */ + success |= 1; + } + } + else { + fcu= verify_driver_fcurve(id, rna_path, array_index, 0); + if(fcu) { + BLI_remlink(&adt->drivers, fcu); + free_fcurve(fcu); + + success = 1; + } + } } - - /* failed */ - return 0; + + return success; } /* ************************************************** */ @@ -408,33 +423,21 @@ static int remove_driver_button_exec (bContext *C, wmOperator *op) PropertyRNA *prop= NULL; char *path; short success= 0; - int a, index, length, all= RNA_boolean_get(op->ptr, "all"); + int index, all= RNA_boolean_get(op->ptr, "all"); /* try to find driver using property retrieved from UI */ memset(&ptr, 0, sizeof(PointerRNA)); uiAnimContextProperty(C, &ptr, &prop, &index); + + if (all) + index= -1; if (ptr.data && prop) { path= RNA_path_from_ID_to_property(&ptr, prop); - - if (path) { - if (all) { - length= RNA_property_array_length(&ptr, prop); - - if(length) index= 0; - else length= 1; - } - else - length= 1; - - for (a=0; aptr.id.data, group); } -/* internal use for insert and delete */ -static int pyrna_struct_keyframe_parse(PointerRNA *ptr, PyObject *args, char *error_prefix, - char **path_full, int *index, float *cfra, char **group_name) /* return values */ +/* for keyframes and drivers */ +static int pyrna_struct_anim_args_parse(PointerRNA *ptr, char *error_prefix, char *path, + char **path_full, int *index) { - char *path; PropertyRNA *prop; - - if (!PyArg_ParseTuple(args, "s|ifs", &path, index, cfra, group_name)) { - PyErr_Format(PyExc_TypeError, "%.200s expected a string and optionally an int, float, and string arguments", error_prefix); - return -1; - } if (ptr->data==NULL) { PyErr_Format(PyExc_TypeError, "%.200s this struct has no data, can't be animated", error_prefix); return -1; } - + prop = RNA_struct_find_property(ptr, path); - + if (prop==NULL) { PyErr_Format( PyExc_TypeError, "%.200s property \"%s\" not found", error_prefix, path); return -1; @@ -1756,6 +1750,23 @@ static int pyrna_struct_keyframe_parse(PointerRNA *ptr, PyObject *args, char *er return -1; } + return 0; +} + +/* internal use for insert and delete */ +static int pyrna_struct_keyframe_parse(PointerRNA *ptr, PyObject *args, char *error_prefix, + char **path_full, int *index, float *cfra, char **group_name) /* return values */ +{ + char *path; + + if (!PyArg_ParseTuple(args, "s|ifs", &path, index, cfra, group_name)) { + PyErr_Format(PyExc_TypeError, "%.200s expected a string and optionally an int, float, and string arguments", error_prefix); + return -1; + } + + if(pyrna_struct_anim_args_parse(ptr, error_prefix, path, path_full, index) < 0) + return -1; + if(*cfra==FLT_MAX) *cfra= CTX_data_scene(BPy_GetContext())->r.cfra; @@ -1846,52 +1857,13 @@ static PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args) { char *path, *path_full; int index= -1; - PropertyRNA *prop; PyObject *ret; if (!PyArg_ParseTuple(args, "s|i:driver_add", &path, &index)) return NULL; - if (self->ptr.data==NULL) { - PyErr_Format( PyExc_TypeError, "bpy_struct.driver_add(): this struct has no data, cant be animated", path); + if(pyrna_struct_anim_args_parse(&self->ptr, "bpy_struct.driver_add():", path, &path_full, &index) < 0) return NULL; - } - - prop = RNA_struct_find_property(&self->ptr, path); - - if (prop==NULL) { - PyErr_Format( PyExc_TypeError, "bpy_struct.driver_add(): property \"%s\" not found", path); - return NULL; - } - - if (!RNA_property_animateable(&self->ptr, prop)) { - PyErr_Format( PyExc_TypeError, "bpy_struct.driver_add(): property \"%s\" not animatable", path); - return NULL; - } - - if(RNA_property_array_check(&self->ptr, prop) == 0) { - if(index == -1) { - index= 0; - } - else { - PyErr_Format( PyExc_TypeError, "bpy_struct.driver_add(): array index %d given while property \"%s\" is not an array", index, path); - return NULL; - } - } - else { - int array_len= RNA_property_array_length(&self->ptr, prop); - if(index < -1 || index >= array_len) { - PyErr_Format( PyExc_TypeError, "bpy_struct.driver_add(): index out of range \"%s\", given %d, array length is %d", path, index, array_len); - return NULL; - } - } - - path_full= RNA_path_from_ID_to_property(&self->ptr, prop); - - if (path_full==NULL) { - PyErr_Format( PyExc_TypeError, "bpy_struct.driver_add(): could not make path to \"%s\"", path); - return NULL; - } if(ANIM_add_driver((ID *)self->ptr.id.data, path_full, index, 0, DRIVER_TYPE_PYTHON)) { ID *id= self->ptr.id.data; @@ -1927,6 +1899,39 @@ static PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args) return ret; } + +static char pyrna_struct_driver_remove_doc[] = +".. method:: driver_remove(path, index=-1)\n" +"\n" +" Remove driver(s) from the given property\n" +"\n" +" :arg path: path to the property to drive, analogous to the fcurve's data path.\n" +" :type path: string\n" +" :arg index: array index of the property drive. Defaults to -1 for all indicies or a single channel if the property is not an array.\n" +" :type index: int\n" +" :return: Success of driver removal.\n" +" :rtype: boolean"; + +static PyObject *pyrna_struct_driver_remove(BPy_StructRNA *self, PyObject *args) +{ + char *path, *path_full; + int index= -1; + PyObject *ret; + + if (!PyArg_ParseTuple(args, "s|i:driver_remove", &path, &index)) + return NULL; + + if(pyrna_struct_anim_args_parse(&self->ptr, "bpy_struct.driver_remove():", path, &path_full, &index) < 0) + return NULL; + + ret= PyBool_FromLong(ANIM_remove_driver((ID *)self->ptr.id.data, path_full, index, 0)); + + MEM_freeN(path_full); + + return ret; +} + + static char pyrna_struct_is_property_set_doc[] = ".. method:: is_property_set(property)\n" "\n" @@ -2899,6 +2904,7 @@ static struct PyMethodDef pyrna_struct_methods[] = { {"keyframe_insert", (PyCFunction)pyrna_struct_keyframe_insert, METH_VARARGS, pyrna_struct_keyframe_insert_doc}, {"keyframe_delete", (PyCFunction)pyrna_struct_keyframe_delete, METH_VARARGS, pyrna_struct_keyframe_delete_doc}, {"driver_add", (PyCFunction)pyrna_struct_driver_add, METH_VARARGS, pyrna_struct_driver_add_doc}, + {"driver_remove", (PyCFunction)pyrna_struct_driver_remove, METH_VARARGS, pyrna_struct_driver_remove_doc}, {"is_property_set", (PyCFunction)pyrna_struct_is_property_set, METH_VARARGS, pyrna_struct_is_property_set_doc}, {"is_property_hidden", (PyCFunction)pyrna_struct_is_property_hidden, METH_VARARGS, pyrna_struct_is_property_hidden_doc}, {"path_resolve", (PyCFunction)pyrna_struct_path_resolve, METH_O, pyrna_struct_path_resolve_doc},