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