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