Blender V2.61 - r43446

bpy_rna_anim.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * Contributor(s): Campbell Barton
00019  *
00020  * ***** END GPL LICENSE BLOCK *****
00021  */
00022 
00029 #include <Python.h>
00030 #include <float.h> /* FLT_MIN/MAX */
00031 
00032 #include "MEM_guardedalloc.h"
00033 
00034 #include "BLI_string.h"
00035 
00036 #include "DNA_scene_types.h"
00037 #include "DNA_anim_types.h"
00038 #include "ED_keyframing.h"
00039 
00040 #include "BKE_report.h"
00041 #include "BKE_context.h"
00042 #include "BKE_animsys.h"
00043 #include "BKE_fcurve.h"
00044 
00045 #include "RNA_access.h"
00046 
00047 #include "WM_api.h"
00048 #include "WM_types.h"
00049 
00050 #include "bpy_rna.h"
00051 #include "bpy_util.h"
00052 #include "bpy_rna_anim.h"
00053 
00054 #define TRUE 1
00055 #define FALSE 0
00056 
00057 /* for keyframes and drivers */
00058 static int pyrna_struct_anim_args_parse(
00059         PointerRNA *ptr, const char *error_prefix, const char *path,
00060         const char **path_full, int *index)
00061 {
00062     const int is_idbase = RNA_struct_is_ID(ptr->type);
00063     PropertyRNA *prop;
00064     PointerRNA r_ptr;
00065 
00066     if (ptr->data == NULL) {
00067         PyErr_Format(PyExc_TypeError,
00068                      "%.200s this struct has no data, can't be animated",
00069                      error_prefix);
00070         return -1;
00071     }
00072 
00073     /* full paths can only be given from ID base */
00074     if (is_idbase) {
00075         int r_index = -1;
00076         if (RNA_path_resolve_full(ptr, path, &r_ptr, &prop, &r_index) == 0) {
00077             prop = NULL;
00078         }
00079         else if (r_index != -1) {
00080             PyErr_Format(PyExc_ValueError,
00081                          "%.200s path includes index, must be a separate argument",
00082                          error_prefix, path);
00083             return -1;
00084         }
00085         else if (ptr->id.data != r_ptr.id.data) {
00086             PyErr_Format(PyExc_ValueError,
00087                          "%.200s path spans ID blocks",
00088                          error_prefix, path);
00089             return -1;
00090         }
00091     }
00092     else {
00093         prop = RNA_struct_find_property(ptr, path);
00094         r_ptr = *ptr;
00095     }
00096 
00097     if (prop == NULL) {
00098         PyErr_Format(PyExc_TypeError,
00099                      "%.200s property \"%s\" not found",
00100                      error_prefix, path);
00101         return -1;
00102     }
00103 
00104     if (!RNA_property_animateable(&r_ptr, prop)) {
00105         PyErr_Format(PyExc_TypeError,
00106                      "%.200s property \"%s\" not animatable",
00107                      error_prefix, path);
00108         return -1;
00109     }
00110 
00111     if (RNA_property_array_check(prop) == 0) {
00112         if ((*index) == -1) {
00113             *index = 0;
00114         }
00115         else {
00116             PyErr_Format(PyExc_TypeError,
00117                          "%.200s index %d was given while property \"%s\" is not an array",
00118                          error_prefix, *index, path);
00119             return -1;
00120         }
00121     }
00122     else {
00123         int array_len = RNA_property_array_length(&r_ptr, prop);
00124         if ((*index) < -1 || (*index) >= array_len) {
00125             PyErr_Format(PyExc_TypeError,
00126                          "%.200s index out of range \"%s\", given %d, array length is %d",
00127                          error_prefix, path, *index, array_len);
00128             return -1;
00129         }
00130     }
00131 
00132     if (is_idbase) {
00133         *path_full = BLI_strdup(path);
00134     }
00135     else {
00136         *path_full = RNA_path_from_ID_to_property(&r_ptr, prop);
00137 
00138         if (*path_full == NULL) {
00139             PyErr_Format(PyExc_TypeError,
00140                          "%.200s could not make path to \"%s\"",
00141                          error_prefix, path);
00142             return -1;
00143         }
00144     }
00145 
00146     return 0;
00147 }
00148 
00149 /* internal use for insert and delete */
00150 static int pyrna_struct_keyframe_parse(
00151         PointerRNA *ptr, PyObject *args, PyObject *kw, const char *parse_str, const char *error_prefix,
00152         const char **path_full, int *index, float *cfra, const char **group_name) /* return values */
00153 {
00154     static const char *kwlist[] = {"data_path", "index", "frame", "group", NULL};
00155     const char *path;
00156 
00157     /* note, parse_str MUST start with 's|ifs' */
00158     if (!PyArg_ParseTupleAndKeywords(args, kw, parse_str, (char **)kwlist, &path, index, cfra, group_name))
00159         return -1;
00160 
00161     if (pyrna_struct_anim_args_parse(ptr, error_prefix, path, path_full, index) < 0)
00162         return -1;
00163 
00164     if (*cfra == FLT_MAX)
00165         *cfra = CTX_data_scene(BPy_GetContext())->r.cfra;
00166 
00167     return 0; /* success */
00168 }
00169 
00170 char pyrna_struct_keyframe_insert_doc[] =
00171 ".. method:: keyframe_insert(data_path, index=-1, frame=bpy.context.scene.frame_current, group=\"\")\n"
00172 "\n"
00173 "   Insert a keyframe on the property given, adding fcurves and animation data when necessary.\n"
00174 "\n"
00175 "   :arg data_path: path to the property to key, analogous to the fcurve's data path.\n"
00176 "   :type data_path: string\n"
00177 "   :arg index: array index of the property to key. Defaults to -1 which will key all indices or a single channel if the property is not an array.\n"
00178 "   :type index: int\n"
00179 "   :arg frame: The frame on which the keyframe is inserted, defaulting to the current frame.\n"
00180 "   :type frame: float\n"
00181 "   :arg group: The name of the group the F-Curve should be added to if it doesn't exist yet.\n"
00182 "   :type group: str\n"
00183 "   :return: Success of keyframe insertion.\n"
00184 "   :rtype: boolean\n"
00185 ;
00186 PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyObject *kw)
00187 {
00188     /* args, pyrna_struct_keyframe_parse handles these */
00189     const char *path_full = NULL;
00190     int index = -1;
00191     float cfra = FLT_MAX;
00192     const char *group_name = NULL;
00193 
00194     PYRNA_STRUCT_CHECK_OBJ(self);
00195 
00196     if (pyrna_struct_keyframe_parse(&self->ptr, args, kw,
00197                                    "s|ifs:bpy_struct.keyframe_insert()", "bpy_struct.keyframe_insert()",
00198                                    &path_full, &index, &cfra, &group_name) == -1)
00199     {
00200         return NULL;
00201     }
00202     else {
00203         short result;
00204         ReportList reports;
00205 
00206         BKE_reports_init(&reports, RPT_STORE);
00207 
00208         result = insert_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0);
00209         MEM_freeN((void *)path_full);
00210 
00211         if (BPy_reports_to_error(&reports, PyExc_RuntimeError, TRUE) == -1)
00212             return NULL;
00213 
00214         return PyBool_FromLong(result);
00215     }
00216 }
00217 
00218 char pyrna_struct_keyframe_delete_doc[] =
00219 ".. method:: keyframe_delete(data_path, index=-1, frame=bpy.context.scene.frame_current, group=\"\")\n"
00220 "\n"
00221 "   Remove a keyframe from this properties fcurve.\n"
00222 "\n"
00223 "   :arg data_path: path to the property to remove a key, analogous to the fcurve's data path.\n"
00224 "   :type data_path: string\n"
00225 "   :arg index: array index of the property to remove a key. Defaults to -1 removing all indices or a single channel if the property is not an array.\n"
00226 "   :type index: int\n"
00227 "   :arg frame: The frame on which the keyframe is deleted, defaulting to the current frame.\n"
00228 "   :type frame: float\n"
00229 "   :arg group: The name of the group the F-Curve should be added to if it doesn't exist yet.\n"
00230 "   :type group: str\n"
00231 "   :return: Success of keyframe deleation.\n"
00232 "   :rtype: boolean\n"
00233 ;
00234 PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyObject *kw)
00235 {
00236     /* args, pyrna_struct_keyframe_parse handles these */
00237     const char *path_full = NULL;
00238     int index = -1;
00239     float cfra = FLT_MAX;
00240     const char *group_name = NULL;
00241 
00242     PYRNA_STRUCT_CHECK_OBJ(self);
00243 
00244     if (pyrna_struct_keyframe_parse(&self->ptr, args, kw,
00245                                    "s|ifs:bpy_struct.keyframe_delete()",
00246                                    "bpy_struct.keyframe_insert()",
00247                                    &path_full, &index, &cfra, &group_name) == -1)
00248     {
00249         return NULL;
00250     }
00251     else {
00252         short result;
00253         ReportList reports;
00254 
00255         BKE_reports_init(&reports, RPT_STORE);
00256 
00257         result = delete_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0);
00258         MEM_freeN((void *)path_full);
00259 
00260         if (BPy_reports_to_error(&reports, PyExc_RuntimeError, TRUE) == -1)
00261             return NULL;
00262 
00263         return PyBool_FromLong(result);
00264     }
00265 
00266 }
00267 
00268 char pyrna_struct_driver_add_doc[] =
00269 ".. method:: driver_add(path, index=-1)\n"
00270 "\n"
00271 "   Adds driver(s) to the given property\n"
00272 "\n"
00273 "   :arg path: path to the property to drive, analogous to the fcurve's data path.\n"
00274 "   :type path: string\n"
00275 "   :arg index: array index of the property drive. Defaults to -1 for all indices or a single channel if the property is not an array.\n"
00276 "   :type index: int\n"
00277 "   :return: The driver(s) added.\n"
00278 "   :rtype: :class:`bpy.types.FCurve` or list if index is -1 with an array property.\n"
00279 ;
00280 PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args)
00281 {
00282     const char *path, *path_full;
00283     int index = -1;
00284 
00285     PYRNA_STRUCT_CHECK_OBJ(self);
00286 
00287     if (!PyArg_ParseTuple(args, "s|i:driver_add", &path, &index))
00288         return NULL;
00289 
00290     if (pyrna_struct_anim_args_parse(&self->ptr, "bpy_struct.driver_add():", path, &path_full, &index) < 0) {
00291         return NULL;
00292     }
00293     else {
00294         PyObject *ret = NULL;
00295         ReportList reports;
00296         int result;
00297 
00298         BKE_reports_init(&reports, RPT_STORE);
00299 
00300         result = ANIM_add_driver(&reports, (ID *)self->ptr.id.data, path_full, index, 0, DRIVER_TYPE_PYTHON);
00301 
00302         if (BPy_reports_to_error(&reports, PyExc_RuntimeError, TRUE) == -1)
00303             return NULL;
00304 
00305         if (result) {
00306             ID *id = self->ptr.id.data;
00307             AnimData *adt = BKE_animdata_from_id(id);
00308             FCurve *fcu;
00309 
00310             PointerRNA tptr;
00311             PyObject *item;
00312 
00313             if (index == -1) { /* all, use a list */
00314                 int i = 0;
00315                 ret = PyList_New(0);
00316                 while ((fcu = list_find_fcurve(&adt->drivers, path_full, i++))) {
00317                     RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr);
00318                     item = pyrna_struct_CreatePyObject(&tptr);
00319                     PyList_Append(ret, item);
00320                     Py_DECREF(item);
00321                 }
00322             }
00323             else {
00324                 fcu = list_find_fcurve(&adt->drivers, path_full, index);
00325                 RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr);
00326                 ret = pyrna_struct_CreatePyObject(&tptr);
00327             }
00328             
00329             WM_event_add_notifier(BPy_GetContext(), NC_ANIMATION|ND_FCURVES_ORDER, NULL);
00330         }
00331         else {
00332             /* XXX, should be handled by reports, */
00333             PyErr_SetString(PyExc_TypeError, "bpy_struct.driver_add(): failed because of an internal error");
00334             return NULL;
00335         }
00336 
00337         MEM_freeN((void *)path_full);
00338 
00339         return ret;
00340     }
00341 }
00342 
00343 
00344 char pyrna_struct_driver_remove_doc[] =
00345 ".. method:: driver_remove(path, index=-1)\n"
00346 "\n"
00347 "   Remove driver(s) from the given property\n"
00348 "\n"
00349 "   :arg path: path to the property to drive, analogous to the fcurve's data path.\n"
00350 "   :type path: string\n"
00351 "   :arg index: array index of the property drive. Defaults to -1 for all indices or a single channel if the property is not an array.\n"
00352 "   :type index: int\n"
00353 "   :return: Success of driver removal.\n"
00354 "   :rtype: boolean\n"
00355 ;
00356 PyObject *pyrna_struct_driver_remove(BPy_StructRNA *self, PyObject *args)
00357 {
00358     const char *path, *path_full;
00359     int index = -1;
00360 
00361     PYRNA_STRUCT_CHECK_OBJ(self);
00362 
00363     if (!PyArg_ParseTuple(args, "s|i:driver_remove", &path, &index))
00364         return NULL;
00365 
00366     if (pyrna_struct_anim_args_parse(&self->ptr, "bpy_struct.driver_remove():", path, &path_full, &index) < 0) {
00367         return NULL;
00368     }
00369     else {
00370         short result;
00371         ReportList reports;
00372 
00373         BKE_reports_init(&reports, RPT_STORE);
00374 
00375         result = ANIM_remove_driver(&reports, (ID *)self->ptr.id.data, path_full, index, 0);
00376 
00377         MEM_freeN((void *)path_full);
00378 
00379         if (BPy_reports_to_error(&reports, PyExc_RuntimeError, TRUE) == -1)
00380             return NULL;
00381         
00382         WM_event_add_notifier(BPy_GetContext(), NC_ANIMATION|ND_FCURVES_ORDER, NULL);
00383 
00384         return PyBool_FromLong(result);
00385     }
00386 }