revert part of Tons commit r33884.
[blender.git] / source / blender / editors / animation / drivers.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Joshua Leung (full recode)
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29  
30 #include <string.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_blenlib.h"
35
36 #include "DNA_anim_types.h"
37
38 #include "BKE_animsys.h"
39 #include "BKE_depsgraph.h"
40 #include "BKE_fcurve.h"
41 #include "BKE_context.h"
42 #include "BKE_report.h"
43
44 #include "ED_keyframing.h"
45
46 #include "UI_interface.h"
47
48 #include "WM_api.h"
49 #include "WM_types.h"
50
51 #include "RNA_access.h"
52 #include "RNA_define.h"
53
54 /* ************************************************** */
55 /* Animation Data Validation */
56
57 /* Get (or add relevant data to be able to do so) F-Curve from the driver stack, 
58  * for the given Animation Data block. This assumes that all the destinations are valid.
59  *      
60  *      - add:  0 - don't add anything if not found, 
61  *                      1 - add new Driver FCurve, 
62  *                      -1 - add new Driver FCurve without driver stuff (for pasting)
63  */
64 FCurve *verify_driver_fcurve (ID *id, const char rna_path[], const int array_index, short add)
65 {
66         AnimData *adt;
67         FCurve *fcu;
68         
69         /* sanity checks */
70         if ELEM(NULL, id, rna_path)
71                 return NULL;
72         
73         /* init animdata if none available yet */
74         adt= BKE_animdata_from_id(id);
75         if ((adt == NULL) && (add))
76                 adt= BKE_id_add_animdata(id);
77         if (adt == NULL) { 
78                 /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
79                 return NULL;
80         }
81                 
82         /* try to find f-curve matching for this setting 
83          *      - add if not found and allowed to add one
84          *              TODO: add auto-grouping support? how this works will need to be resolved
85          */
86         fcu= list_find_fcurve(&adt->drivers, rna_path, array_index);
87         
88         if ((fcu == NULL) && (add)) {
89                 /* use default settings to make a F-Curve */
90                 fcu= MEM_callocN(sizeof(FCurve), "FCurve");
91                 
92                 fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
93                 
94                 /* store path - make copy, and store that */
95                 fcu->rna_path= BLI_strdupn(rna_path, strlen(rna_path));
96                 fcu->array_index= array_index;
97                 
98                 /* if add is negative, don't init this data yet, since it will be filled in by the pasted driver */
99                 if (add > 0) {
100                         /* add some new driver data */
101                         fcu->driver= MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
102                         
103                         /* add simple generator modifier for driver so that there is some visible representation */
104                         add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR);
105                 }
106                 
107                 /* just add F-Curve to end of driver list */
108                 BLI_addtail(&adt->drivers, fcu);
109         }
110         
111         /* return the F-Curve */
112         return fcu;
113 }
114
115 /* ************************************************** */
116 /* Driver Management API */
117
118 /* Main Driver Management API calls:
119  *      Add a new driver for the specified property on the given ID block
120  */
121 short ANIM_add_driver (ReportList *reports, ID *id, const char rna_path[], int array_index, short flag, int type)
122 {       
123         PointerRNA id_ptr, ptr;
124         PropertyRNA *prop;
125         FCurve *fcu;
126         int array_index_max;
127         int done = 0;
128         
129         /* validate pointer first - exit if failure */
130         RNA_id_pointer_create(id, &id_ptr);
131         if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
132                 BKE_reportf(reports, RPT_ERROR, 
133                         "Could not add Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)", 
134                         id->name, rna_path);
135                 return 0;
136         }
137         
138         /* key entire array convenience method */
139         if (array_index == -1) {
140                 array_index_max= RNA_property_array_length(&ptr, prop);
141                 array_index= 0;
142         }
143         else
144                 array_index_max= array_index;
145         
146         /* maximum index should be greater than the start index */
147         if (array_index == array_index_max)
148                 array_index_max += 1;
149         
150         /* will only loop once unless the array index was -1 */
151         for (; array_index < array_index_max; array_index++) {
152                 /* create F-Curve with Driver */
153                 fcu= verify_driver_fcurve(id, rna_path, array_index, 1);
154                 
155                 if (fcu && fcu->driver) {
156                         ChannelDriver *driver= fcu->driver;
157                         
158                         /* set the type of the driver */
159                         driver->type= type;
160                         
161                         /* creating drivers for buttons will create the driver(s) with type 
162                          * "scripted expression" so that their values won't be lost immediately,
163                          * so here we copy those values over to the driver's expression
164                          */
165                         if (type == DRIVER_TYPE_PYTHON) {
166                                 PropertyType proptype= RNA_property_type(prop);
167                                 int array= RNA_property_array_length(&ptr, prop);
168                                 char *expression= driver->expression;
169                                 int val, maxlen= sizeof(driver->expression);
170                                 float fval;
171                                 
172                                 if (proptype == PROP_BOOLEAN) {
173                                         if (!array) val= RNA_property_boolean_get(&ptr, prop);
174                                         else val= RNA_property_boolean_get_index(&ptr, prop, array_index);
175                                         
176                                         BLI_strncpy(expression, (val)? "True": "False", maxlen);
177                                 }
178                                 else if (proptype == PROP_INT) {
179                                         if (!array) val= RNA_property_int_get(&ptr, prop);
180                                         else val= RNA_property_int_get_index(&ptr, prop, array_index);
181                                         
182                                         BLI_snprintf(expression, maxlen, "%d", val);
183                                 }
184                                 else if (proptype == PROP_FLOAT) {
185                                         if (!array) fval= RNA_property_float_get(&ptr, prop);
186                                         else fval= RNA_property_float_get_index(&ptr, prop, array_index);
187                                         
188                                         BLI_snprintf(expression, maxlen, "%.3f", fval);
189                                 }
190                         }
191                         
192                         /* for easier setup of drivers from UI, a driver variable should be 
193                          * added if flag is set (UI calls only)
194                          */
195                         if (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) {
196                                 /* assume that users will mostly want this to be of type "Transform Channel" too,
197                                  * since this allows the easiest setting up of common rig components
198                                  */
199                                 DriverVar *dvar = driver_add_new_variable(driver);
200                                 driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN);
201                         }
202                 }
203                 
204                 /* set the done status */
205                 done += (fcu != NULL);
206         }
207         
208         /* done */
209         return done;
210 }
211
212 /* Main Driver Management API calls:
213  *      Remove the driver for the specified property on the given ID block (if available)
214  */
215 short ANIM_remove_driver (ReportList *UNUSED(reports), ID *id, const char rna_path[], int array_index, short UNUSED(flag))
216 {
217         AnimData *adt;
218         FCurve *fcu;
219         int success= 0;
220         
221         /* we don't check the validity of the path here yet, but it should be ok... */
222         adt= BKE_animdata_from_id(id);
223         
224         if (adt) {
225                 if (array_index == -1) {
226                         /* step through all drivers, removing all of those with the same base path */
227                         FCurve *fcu_iter= adt->drivers.first;
228                         
229                         while ((fcu = iter_step_fcurve(fcu_iter, rna_path)) != NULL) {
230                                 /* store the next fcurve for looping  */
231                                 fcu_iter= fcu->next;
232                                 
233                                 /* remove F-Curve from driver stack, then free it */
234                                 BLI_remlink(&adt->drivers, fcu);
235                                 free_fcurve(fcu);
236                                 
237                                 /* done successfully */
238                                 success |= 1;
239                         }
240                 }
241                 else {
242                         /* find the matching driver and remove it only 
243                          * Note: here is one of the places where we don't want new F-Curve + Driver added!
244                          *              so 'add' var must be 0
245                          */
246                         fcu= verify_driver_fcurve(id, rna_path, array_index, 0);
247                         if (fcu) {
248                                 BLI_remlink(&adt->drivers, fcu);
249                                 free_fcurve(fcu);
250                                 
251                                 success = 1;
252                         }
253                 }
254         }
255
256         return success;
257 }
258
259 /* ************************************************** */
260 /* Driver Management API - Copy/Paste Drivers */
261
262 /* Copy/Paste Buffer for Driver Data... */
263 static FCurve *channeldriver_copypaste_buf = NULL;
264
265 /* This function frees any MEM_calloc'ed copy/paste buffer data */
266 // XXX find some header to put this in!
267 void free_anim_drivers_copybuf (void)
268 {
269         /* free the buffer F-Curve if it exists, as if it were just another F-Curve */
270         if (channeldriver_copypaste_buf)
271                 free_fcurve(channeldriver_copypaste_buf);
272         channeldriver_copypaste_buf= NULL;
273 }
274
275 /* Checks if there is a driver in the copy/paste buffer */
276 short ANIM_driver_can_paste (void)
277 {
278         return (channeldriver_copypaste_buf != NULL);
279 }
280
281 /* ------------------- */
282
283 /* Main Driver Management API calls:
284  *      Make a copy of the driver for the specified property on the given ID block
285  */
286 short ANIM_copy_driver (ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag))
287 {
288         PointerRNA id_ptr, ptr;
289         PropertyRNA *prop;
290         FCurve *fcu;
291         
292         /* validate pointer first - exit if failure */
293         RNA_id_pointer_create(id, &id_ptr);
294         if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
295                 BKE_reportf(reports, RPT_ERROR,
296                         "Could not find Driver to copy, as RNA Path is invalid for the given ID (ID = %s, Path = %s)", 
297                         id->name, rna_path);
298                 return 0;
299         }
300         
301         /* try to get F-Curve with Driver */
302         fcu= verify_driver_fcurve(id, rna_path, array_index, 0);
303         
304         /* clear copy/paste buffer first (for consistency with other copy/paste buffers) */
305         free_anim_drivers_copybuf();
306         
307         /* copy this to the copy/paste buf if it exists */
308         if (fcu && fcu->driver) {
309                 /* make copies of some info such as the rna_path, then clear this info from the F-Curve temporarily
310                  * so that we don't end up wasting memory storing the path which won't get used ever...
311                  */
312                 char *tmp_path = fcu->rna_path;
313                 fcu->rna_path= NULL;
314                 
315                 /* make a copy of the F-Curve with */
316                 channeldriver_copypaste_buf= copy_fcurve(fcu);
317                 
318                 /* restore the path */
319                 fcu->rna_path= tmp_path;
320                 
321                 /* copied... */
322                 return 1;
323         }
324         
325         /* done */
326         return 0;
327 }
328
329 /* Main Driver Management API calls:
330  *      Add a new driver for the specified property on the given ID block or replace an existing one
331  *      with the driver + driver-curve data from the buffer 
332  */
333 short ANIM_paste_driver (ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag))
334 {       
335         PointerRNA id_ptr, ptr;
336         PropertyRNA *prop;
337         FCurve *fcu;
338         
339         /* validate pointer first - exit if failure */
340         RNA_id_pointer_create(id, &id_ptr);
341         if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
342                 BKE_reportf(reports, RPT_ERROR,
343                         "Could not paste Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)", 
344                         id->name, rna_path);
345                 return 0;
346         }
347         
348         /* if the buffer is empty, cannot paste... */
349         if (channeldriver_copypaste_buf == NULL) {
350                 BKE_report(reports, RPT_ERROR, "Paste Driver: No Driver to paste.");
351                 return 0;
352         }
353         
354         /* create Driver F-Curve, but without data which will be copied across... */
355         fcu= verify_driver_fcurve(id, rna_path, array_index, -1);
356
357         if (fcu) {
358                 /* copy across the curve data from the buffer curve 
359                  * NOTE: this step needs care to not miss new settings
360                  */
361                         /* keyframes/samples */
362                 fcu->bezt= MEM_dupallocN(channeldriver_copypaste_buf->bezt);
363                 fcu->fpt= MEM_dupallocN(channeldriver_copypaste_buf->fpt);
364                 fcu->totvert= channeldriver_copypaste_buf->totvert;
365                 
366                         /* modifiers */
367                 copy_fmodifiers(&fcu->modifiers, &channeldriver_copypaste_buf->modifiers);
368                 
369                         /* flags - on a per-relevant-flag basis */
370                 if (channeldriver_copypaste_buf->flag & FCURVE_AUTO_HANDLES)
371                         fcu->flag |= FCURVE_AUTO_HANDLES;
372                 else
373                         fcu->flag &= ~FCURVE_AUTO_HANDLES;
374                         /* extrapolation mode */
375                 fcu->extend= channeldriver_copypaste_buf->extend;
376                         
377                         /* the 'juicy' stuff - the driver */
378                 fcu->driver= fcurve_copy_driver(channeldriver_copypaste_buf->driver);
379         }
380         
381         /* done */
382         return (fcu != NULL);
383 }
384
385 /* ************************************************** */
386 /* UI-Button Interface */
387
388 /* Add Driver Button Operator ------------------------ */
389
390 static int add_driver_button_exec (bContext *C, wmOperator *op)
391 {
392         PointerRNA ptr= {{0}};
393         PropertyRNA *prop= NULL;
394         short success= 0;
395         int index, all= RNA_boolean_get(op->ptr, "all");
396         
397         /* try to create driver using property retrieved from UI */
398         uiContextActiveProperty(C, &ptr, &prop, &index);
399
400         if (all)
401                 index= -1;
402
403         if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
404                 char *path= RNA_path_from_ID_to_property(&ptr, prop);
405                 short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
406                 
407                 if (path) {                     
408                         success+= ANIM_add_driver(op->reports, ptr.id.data, path, index, flags, DRIVER_TYPE_PYTHON);
409                         
410                         MEM_freeN(path);
411                 }
412         }
413         
414         if (success) {
415                 /* send updates */
416                 uiContextAnimUpdate(C);
417                 
418                 DAG_ids_flush_update(CTX_data_main(C), 0);
419                 
420                 WM_event_add_notifier(C, NC_ANIMATION|ND_FCURVES_ORDER, NULL); // XXX
421         }
422         
423         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
424 }
425
426 void ANIM_OT_driver_button_add (wmOperatorType *ot)
427 {
428         /* identifiers */
429         ot->name= "Add Driver";
430         ot->idname= "ANIM_OT_driver_button_add";
431         ot->description= "Add driver(s) for the property(s) connected represented by the highlighted button";
432         
433         /* callbacks */
434         ot->exec= add_driver_button_exec; 
435         //op->poll= ??? // TODO: need to have some animateable property to do this
436         
437         /* flags */
438         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
439
440         /* properties */
441         RNA_def_boolean(ot->srna, "all", 1, "All", "Create drivers for all elements of the array.");
442 }
443
444 /* Remove Driver Button Operator ------------------------ */
445
446 static int remove_driver_button_exec (bContext *C, wmOperator *op)
447 {
448         PointerRNA ptr= {{0}};
449         PropertyRNA *prop= NULL;
450         short success= 0;
451         int index, all= RNA_boolean_get(op->ptr, "all");
452         
453         /* try to find driver using property retrieved from UI */
454         uiContextActiveProperty(C, &ptr, &prop, &index);
455         
456         if (all)
457                 index= -1;
458
459         if (ptr.id.data && ptr.data && prop) {
460                 char *path= RNA_path_from_ID_to_property(&ptr, prop);
461                 
462                 success= ANIM_remove_driver(op->reports, ptr.id.data, path, index, 0);
463                 MEM_freeN(path);
464         }
465         
466         if (success) {
467                 /* send updates */
468                 uiContextAnimUpdate(C);
469                 
470                 DAG_ids_flush_update(CTX_data_main(C), 0);
471                 
472                 WM_event_add_notifier(C, NC_ANIMATION|ND_FCURVES_ORDER, NULL);  // XXX
473         }
474         
475         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
476 }
477
478 void ANIM_OT_driver_button_remove (wmOperatorType *ot)
479 {
480         /* identifiers */
481         ot->name= "Remove Driver";
482         ot->idname= "ANIM_OT_driver_button_remove";
483         ot->description= "Remove the driver(s) for the property(s) connected represented by the highlighted button";
484         
485         /* callbacks */
486         ot->exec= remove_driver_button_exec; 
487         //op->poll= ??? // TODO: need to have some driver to be able to do this...
488         
489         /* flags */
490         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
491
492         /* properties */
493         RNA_def_boolean(ot->srna, "all", 1, "All", "Delete drivers for all elements of the array.");
494 }
495
496 /* Copy Driver Button Operator ------------------------ */
497
498 static int copy_driver_button_exec (bContext *C, wmOperator *op)
499 {
500         PointerRNA ptr= {{0}};
501         PropertyRNA *prop= NULL;
502         short success= 0;
503         int index;
504         
505         /* try to create driver using property retrieved from UI */
506         uiContextActiveProperty(C, &ptr, &prop, &index);
507         
508         if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
509                 char *path= RNA_path_from_ID_to_property(&ptr, prop);
510                 
511                 if (path) {
512                         /* only copy the driver for the button that this was involved for */
513                         success= ANIM_copy_driver(op->reports, ptr.id.data, path, index, 0);
514                         
515                         uiContextAnimUpdate(C);
516                         
517                         MEM_freeN(path);
518                 }
519         }
520         
521         /* since we're just copying, we don't really need to do anything else...*/
522         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
523 }
524
525 void ANIM_OT_copy_driver_button (wmOperatorType *ot)
526 {
527         /* identifiers */
528         ot->name= "Copy Driver";
529         ot->idname= "ANIM_OT_copy_driver_button";
530         ot->description= "Copy the driver for the highlighted button";
531         
532         /* callbacks */
533         ot->exec= copy_driver_button_exec; 
534         //op->poll= ??? // TODO: need to have some driver to be able to do this...
535         
536         /* flags */
537         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
538 }
539
540 /* Paste Driver Button Operator ------------------------ */
541
542 static int paste_driver_button_exec (bContext *C, wmOperator *op)
543 {
544         PointerRNA ptr= {{0}};
545         PropertyRNA *prop= NULL;
546         short success= 0;
547         int index;
548         
549         /* try to create driver using property retrieved from UI */
550         uiContextActiveProperty(C, &ptr, &prop, &index);
551         
552         if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
553                 char *path= RNA_path_from_ID_to_property(&ptr, prop);
554                 
555                 if (path) {
556                         /* only copy the driver for the button that this was involved for */
557                         success= ANIM_paste_driver(op->reports, ptr.id.data, path, index, 0);
558                         
559                         uiContextAnimUpdate(C);
560                         
561                         MEM_freeN(path);
562                 }
563         }
564         
565         /* since we're just copying, we don't really need to do anything else...*/
566         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
567 }
568
569 void ANIM_OT_paste_driver_button (wmOperatorType *ot)
570 {
571         /* identifiers */
572         ot->name= "Paste Driver";
573         ot->idname= "ANIM_OT_paste_driver_button";
574         ot->description= "Paste the driver in the copy/paste buffer for the highlighted button";
575         
576         /* callbacks */
577         ot->exec= paste_driver_button_exec; 
578         //op->poll= ??? // TODO: need to have some driver to be able to do this...
579         
580         /* flags */
581         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
582 }
583
584 /* ************************************************** */