4ebb407f4d67ee3f3be23a3d5c503a98d5bd1b2f
[blender.git] / source / blender / python / intern / bpy_rna_anim.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Campbell Barton
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/python/intern/bpy_rna_anim.c
24  *  \ingroup pythonintern
25  */
26
27 #include <Python.h>
28 #include <float.h> /* FLT_MIN/MAX */
29
30 #include "MEM_guardedalloc.h"
31
32 #include "BLI_string.h"
33
34 #include "DNA_scene_types.h"
35 #include "DNA_anim_types.h"
36 #include "ED_keyframing.h"
37
38 #include "BKE_report.h"
39 #include "BKE_context.h"
40 #include "BKE_animsys.h"
41 #include "BKE_fcurve.h"
42
43 #include "RNA_access.h"
44
45 #include "WM_api.h"
46 #include "WM_types.h"
47
48 #include "bpy_rna.h"
49 #include "bpy_util.h"
50 #include "bpy_rna_anim.h"
51
52 #define TRUE 1
53 #define FALSE 0
54
55 /* for keyframes and drivers */
56 static int pyrna_struct_anim_args_parse(PointerRNA *ptr, const char *error_prefix, const char *path,
57                                         const char **path_full, int *index)
58 {
59         const int is_idbase= RNA_struct_is_ID(ptr->type);
60         PropertyRNA *prop;
61         PointerRNA r_ptr;
62
63         if (ptr->data==NULL) {
64                 PyErr_Format(PyExc_TypeError,
65                              "%.200s this struct has no data, can't be animated",
66                              error_prefix);
67                 return -1;
68         }
69
70         /* full paths can only be given from ID base */
71         if (is_idbase) {
72                 int r_index= -1;
73                 if (RNA_path_resolve_full(ptr, path, &r_ptr, &prop, &r_index)==0) {
74                         prop= NULL;
75                 }
76                 else if (r_index != -1) {
77                         PyErr_Format(PyExc_ValueError,
78                                      "%.200s path includes index, must be a separate argument",
79                                      error_prefix, path);
80                         return -1;
81                 }
82                 else if (ptr->id.data != r_ptr.id.data) {
83                         PyErr_Format(PyExc_ValueError,
84                                      "%.200s path spans ID blocks",
85                                      error_prefix, path);
86                         return -1;
87                 }
88         }
89         else {
90                 prop= RNA_struct_find_property(ptr, path);
91                 r_ptr= *ptr;
92         }
93
94         if (prop==NULL) {
95                 PyErr_Format(PyExc_TypeError,
96                              "%.200s property \"%s\" not found",
97                              error_prefix, path);
98                 return -1;
99         }
100
101         if (!RNA_property_animateable(&r_ptr, prop)) {
102                 PyErr_Format(PyExc_TypeError,
103                              "%.200s property \"%s\" not animatable",
104                              error_prefix, path);
105                 return -1;
106         }
107
108         if (RNA_property_array_check(prop) == 0) {
109                 if ((*index) == -1) {
110                         *index= 0;
111                 }
112                 else {
113                         PyErr_Format(PyExc_TypeError,
114                                      "%.200s index %d was given while property \"%s\" is not an array",
115                                      error_prefix, *index, path);
116                         return -1;
117                 }
118         }
119         else {
120                 int array_len= RNA_property_array_length(&r_ptr, prop);
121                 if ((*index) < -1 || (*index) >= array_len) {
122                         PyErr_Format(PyExc_TypeError,
123                                      "%.200s index out of range \"%s\", given %d, array length is %d",
124                                      error_prefix, path, *index, array_len);
125                         return -1;
126                 }
127         }
128
129         if (is_idbase) {
130                 *path_full= BLI_strdup(path);
131         }
132         else {
133                 *path_full= RNA_path_from_ID_to_property(&r_ptr, prop);
134
135                 if (*path_full==NULL) {
136                         PyErr_Format(PyExc_TypeError,
137                                      "%.200s could not make path to \"%s\"",
138                                      error_prefix, path);
139                         return -1;
140                 }
141         }
142
143         return 0;
144 }
145
146 /* internal use for insert and delete */
147 static int pyrna_struct_keyframe_parse(PointerRNA *ptr, PyObject *args, PyObject *kw, const char *parse_str, const char *error_prefix,
148                                        const char **path_full, int *index, float *cfra, const char **group_name) /* return values */
149 {
150         static const char *kwlist[]= {"data_path", "index", "frame", "group", NULL};
151         const char *path;
152
153         /* note, parse_str MUST start with 's|ifs' */
154         if (!PyArg_ParseTupleAndKeywords(args, kw, parse_str, (char **)kwlist, &path, index, cfra, group_name))
155                 return -1;
156
157         if (pyrna_struct_anim_args_parse(ptr, error_prefix, path, path_full, index) < 0)
158                 return -1;
159
160         if (*cfra==FLT_MAX)
161                 *cfra= CTX_data_scene(BPy_GetContext())->r.cfra;
162
163         return 0; /* success */
164 }
165
166 char pyrna_struct_keyframe_insert_doc[] =
167 ".. method:: keyframe_insert(data_path, index=-1, frame=bpy.context.scene.frame_current, group=\"\")\n"
168 "\n"
169 "   Insert a keyframe on the property given, adding fcurves and animation data when necessary.\n"
170 "\n"
171 "   :arg data_path: path to the property to key, analogous to the fcurve's data path.\n"
172 "   :type data_path: string\n"
173 "   :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"
174 "   :type index: int\n"
175 "   :arg frame: The frame on which the keyframe is inserted, defaulting to the current frame.\n"
176 "   :type frame: float\n"
177 "   :arg group: The name of the group the F-Curve should be added to if it doesn't exist yet.\n"
178 "   :type group: str\n"
179 "   :return: Success of keyframe insertion.\n"
180 "   :rtype: boolean\n"
181 ;
182 PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyObject *kw)
183 {
184         /* args, pyrna_struct_keyframe_parse handles these */
185         const char *path_full= NULL;
186         int index= -1;
187         float cfra= FLT_MAX;
188         const char *group_name= NULL;
189
190         PYRNA_STRUCT_CHECK_OBJ(self);
191
192         if (pyrna_struct_keyframe_parse(&self->ptr, args, kw,
193                                        "s|ifs:bpy_struct.keyframe_insert()", "bpy_struct.keyframe_insert()",
194                                        &path_full, &index, &cfra, &group_name) == -1)
195         {
196                 return NULL;
197         }
198         else {
199                 short result;
200                 ReportList reports;
201
202                 BKE_reports_init(&reports, RPT_STORE);
203
204                 result= insert_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0);
205                 MEM_freeN((void *)path_full);
206
207                 if (BPy_reports_to_error(&reports, PyExc_RuntimeError, TRUE) == -1)
208                         return NULL;
209
210                 return PyBool_FromLong(result);
211         }
212 }
213
214 char pyrna_struct_keyframe_delete_doc[] =
215 ".. method:: keyframe_delete(data_path, index=-1, frame=bpy.context.scene.frame_current, group=\"\")\n"
216 "\n"
217 "   Remove a keyframe from this properties fcurve.\n"
218 "\n"
219 "   :arg data_path: path to the property to remove a key, analogous to the fcurve's data path.\n"
220 "   :type data_path: string\n"
221 "   :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"
222 "   :type index: int\n"
223 "   :arg frame: The frame on which the keyframe is deleted, defaulting to the current frame.\n"
224 "   :type frame: float\n"
225 "   :arg group: The name of the group the F-Curve should be added to if it doesn't exist yet.\n"
226 "   :type group: str\n"
227 "   :return: Success of keyframe deleation.\n"
228 "   :rtype: boolean\n"
229 ;
230 PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyObject *kw)
231 {
232         /* args, pyrna_struct_keyframe_parse handles these */
233         const char *path_full= NULL;
234         int index= -1;
235         float cfra= FLT_MAX;
236         const char *group_name= NULL;
237
238         PYRNA_STRUCT_CHECK_OBJ(self);
239
240         if (pyrna_struct_keyframe_parse(&self->ptr, args, kw,
241                                        "s|ifs:bpy_struct.keyframe_delete()",
242                                        "bpy_struct.keyframe_insert()",
243                                        &path_full, &index, &cfra, &group_name) == -1)
244         {
245                 return NULL;
246         }
247         else {
248                 short result;
249                 ReportList reports;
250
251                 BKE_reports_init(&reports, RPT_STORE);
252
253                 result= delete_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0);
254                 MEM_freeN((void *)path_full);
255
256                 if (BPy_reports_to_error(&reports, PyExc_RuntimeError, TRUE) == -1)
257                         return NULL;
258
259                 return PyBool_FromLong(result);
260         }
261
262 }
263
264 char pyrna_struct_driver_add_doc[] =
265 ".. method:: driver_add(path, index=-1)\n"
266 "\n"
267 "   Adds driver(s) to the given property\n"
268 "\n"
269 "   :arg path: path to the property to drive, analogous to the fcurve's data path.\n"
270 "   :type path: string\n"
271 "   :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"
272 "   :type index: int\n"
273 "   :return: The driver(s) added.\n"
274 "   :rtype: :class:`bpy.types.FCurve` or list if index is -1 with an array property.\n"
275 ;
276 PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args)
277 {
278         const char *path, *path_full;
279         int index= -1;
280
281         PYRNA_STRUCT_CHECK_OBJ(self);
282
283         if (!PyArg_ParseTuple(args, "s|i:driver_add", &path, &index))
284                 return NULL;
285
286         if (pyrna_struct_anim_args_parse(&self->ptr, "bpy_struct.driver_add():", path, &path_full, &index) < 0) {
287                 return NULL;
288         }
289         else {
290                 PyObject *ret= NULL;
291                 ReportList reports;
292                 int result;
293
294                 BKE_reports_init(&reports, RPT_STORE);
295
296                 result= ANIM_add_driver(&reports, (ID *)self->ptr.id.data, path_full, index, 0, DRIVER_TYPE_PYTHON);
297
298                 if (BPy_reports_to_error(&reports, PyExc_RuntimeError, TRUE) == -1)
299                         return NULL;
300
301                 if (result) {
302                         ID *id= self->ptr.id.data;
303                         AnimData *adt= BKE_animdata_from_id(id);
304                         FCurve *fcu;
305
306                         PointerRNA tptr;
307                         PyObject *item;
308
309                         if (index == -1) { /* all, use a list */
310                                 int i= 0;
311                                 ret= PyList_New(0);
312                                 while ((fcu= list_find_fcurve(&adt->drivers, path_full, i++))) {
313                                         RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr);
314                                         item= pyrna_struct_CreatePyObject(&tptr);
315                                         PyList_Append(ret, item);
316                                         Py_DECREF(item);
317                                 }
318                         }
319                         else {
320                                 fcu= list_find_fcurve(&adt->drivers, path_full, index);
321                                 RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr);
322                                 ret= pyrna_struct_CreatePyObject(&tptr);
323                         }
324                         
325                         WM_event_add_notifier(BPy_GetContext(), NC_ANIMATION|ND_FCURVES_ORDER, NULL);
326                 }
327                 else {
328                         /* XXX, should be handled by reports, */
329                         PyErr_SetString(PyExc_TypeError, "bpy_struct.driver_add(): failed because of an internal error");
330                         return NULL;
331                 }
332
333                 MEM_freeN((void *)path_full);
334
335                 return ret;
336         }
337 }
338
339
340 char pyrna_struct_driver_remove_doc[] =
341 ".. method:: driver_remove(path, index=-1)\n"
342 "\n"
343 "   Remove driver(s) from the given property\n"
344 "\n"
345 "   :arg path: path to the property to drive, analogous to the fcurve's data path.\n"
346 "   :type path: string\n"
347 "   :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"
348 "   :type index: int\n"
349 "   :return: Success of driver removal.\n"
350 "   :rtype: boolean\n"
351 ;
352 PyObject *pyrna_struct_driver_remove(BPy_StructRNA *self, PyObject *args)
353 {
354         const char *path, *path_full;
355         int index= -1;
356
357         PYRNA_STRUCT_CHECK_OBJ(self);
358
359         if (!PyArg_ParseTuple(args, "s|i:driver_remove", &path, &index))
360                 return NULL;
361
362         if (pyrna_struct_anim_args_parse(&self->ptr, "bpy_struct.driver_remove():", path, &path_full, &index) < 0) {
363                 return NULL;
364         }
365         else {
366                 short result;
367                 ReportList reports;
368
369                 BKE_reports_init(&reports, RPT_STORE);
370
371                 result= ANIM_remove_driver(&reports, (ID *)self->ptr.id.data, path_full, index, 0);
372
373                 MEM_freeN((void *)path_full);
374
375                 if (BPy_reports_to_error(&reports, PyExc_RuntimeError, TRUE) == -1)
376                         return NULL;
377                 
378                 WM_event_add_notifier(BPy_GetContext(), NC_ANIMATION|ND_FCURVES_ORDER, NULL);
379
380                 return PyBool_FromLong(result);
381         }
382 }