A few fixes:
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 <stdio.h>
31 #include <stddef.h>
32 #include <string.h>
33 #include <math.h>
34 #include <float.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_arithb.h"
40 #include "BLI_dynstr.h"
41
42 #include "DNA_anim_types.h"
43 #include "DNA_action_types.h"
44 #include "DNA_armature_types.h"
45 #include "DNA_constraint_types.h"
46 #include "DNA_key_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_material_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_userdef_types.h"
51 #include "DNA_windowmanager_types.h"
52
53 #include "BKE_animsys.h"
54 #include "BKE_action.h"
55 #include "BKE_constraint.h"
56 #include "BKE_fcurve.h"
57 #include "BKE_utildefines.h"
58 #include "BKE_context.h"
59 #include "BKE_report.h"
60 #include "BKE_key.h"
61 #include "BKE_material.h"
62
63 #include "ED_anim_api.h"
64 #include "ED_keyframing.h"
65 #include "ED_keyframes_edit.h"
66 #include "ED_screen.h"
67 #include "ED_util.h"
68
69 #include "UI_interface.h"
70
71 #include "WM_api.h"
72 #include "WM_types.h"
73
74 #include "RNA_access.h"
75 #include "RNA_define.h"
76 #include "RNA_types.h"
77
78 /* ************************************************** */
79 /* Animation Data Validation */
80
81 /* Get (or add relevant data to be able to do so) F-Curve from the driver stack, 
82  * for the given Animation Data block. This assumes that all the destinations are valid.
83  *      
84  *      - add:  0 - don't add anything if not found, 
85  *                      1 - add new Driver FCurve, 
86  *                      -1 - add new Driver FCurve without driver stuff (for pasting)
87  */
88 FCurve *verify_driver_fcurve (ID *id, const char rna_path[], const int array_index, short add)
89 {
90         AnimData *adt;
91         FCurve *fcu;
92         
93         /* sanity checks */
94         if ELEM(NULL, id, rna_path)
95                 return NULL;
96         
97         /* init animdata if none available yet */
98         adt= BKE_animdata_from_id(id);
99         if ((adt == NULL) && (add))
100                 adt= BKE_id_add_animdata(id);
101         if (adt == NULL) { 
102                 /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
103                 return NULL;
104         }
105                 
106         /* try to find f-curve matching for this setting 
107          *      - add if not found and allowed to add one
108          *              TODO: add auto-grouping support? how this works will need to be resolved
109          */
110         fcu= list_find_fcurve(&adt->drivers, rna_path, array_index);
111         
112         if ((fcu == NULL) && (add)) {
113                 /* use default settings to make a F-Curve */
114                 fcu= MEM_callocN(sizeof(FCurve), "FCurve");
115                 
116                 fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
117                 
118                 /* store path - make copy, and store that */
119                 fcu->rna_path= BLI_strdupn(rna_path, strlen(rna_path));
120                 fcu->array_index= array_index;
121                 
122                 /* if add is negative, don't init this data yet, since it will be filled in by the pasted driver */
123                 if (add > 0) {
124                         /* add some new driver data */
125                         fcu->driver= MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
126                         
127                         /* add simple generator modifier for driver so that there is some visible representation */
128                         add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR);
129                 }
130                 
131                 /* just add F-Curve to end of driver list */
132                 BLI_addtail(&adt->drivers, fcu);
133         }
134         
135         /* return the F-Curve */
136         return fcu;
137 }
138
139 /* ************************************************** */
140 /* Driver Management API */
141
142 /* Main Driver Management API calls:
143  *      Add a new driver for the specified property on the given ID block
144  */
145 short ANIM_add_driver (ID *id, const char rna_path[], int array_index, short flag, int type)
146 {       
147         PointerRNA id_ptr, ptr;
148         PropertyRNA *prop;
149         FCurve *fcu;
150         
151         /* validate pointer first - exit if failure */
152         RNA_id_pointer_create(id, &id_ptr);
153         if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
154                 printf("Add Driver: Could not add Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path);
155                 return 0;
156         }
157         
158         /* create F-Curve with Driver */
159         fcu= verify_driver_fcurve(id, rna_path, array_index, 1);
160
161         if (fcu && fcu->driver) {
162                 fcu->driver->type= type;
163                 
164                 /* fill in current value for python */
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= fcu->driver->expression;
169                         int val, maxlen= sizeof(fcu->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         
193         /* done */
194         return (fcu != NULL);
195 }
196
197 /* Main Driver Management API calls:
198  *      Remove the driver for the specified property on the given ID block (if available)
199  */
200 short ANIM_remove_driver (struct ID *id, const char rna_path[], int array_index, short flag)
201 {
202         AnimData *adt;
203         FCurve *fcu;
204         
205         /* get F-Curve
206          * Note: here is one of the places where we don't want new F-Curve + Driver added!
207          *              so 'add' var must be 0
208          */
209         /* we don't check the validity of the path here yet, but it should be ok... */
210         fcu= verify_driver_fcurve(id, rna_path, array_index, 0);
211         adt= BKE_animdata_from_id(id);
212         
213         /* only continue if we have an driver to remove */
214         if (adt && fcu) {
215                 /* remove F-Curve from driver stack, then free it */
216                 BLI_remlink(&adt->drivers, fcu);
217                 free_fcurve(fcu);
218                 
219                 /* done successfully */
220                 return 1;
221         }
222         
223         /* failed */
224         return 0;
225 }
226
227 /* ************************************************** */
228 /* Driver Management API - Copy/Paste Drivers */
229
230 /* Copy/Paste Buffer for Driver Data... */
231 static FCurve *channeldriver_copypaste_buf = NULL;
232
233 /* This function frees any MEM_calloc'ed copy/paste buffer data */
234 // XXX find some header to put this in!
235 void free_anim_drivers_copybuf (void)
236 {
237         /* free the buffer F-Curve if it exists, as if it were just another F-Curve */
238         if (channeldriver_copypaste_buf)
239                 free_fcurve(channeldriver_copypaste_buf);
240         channeldriver_copypaste_buf= NULL;
241 }
242
243 /* Checks if there is a driver in the copy/paste buffer */
244 short ANIM_driver_can_paste (void)
245 {
246         return (channeldriver_copypaste_buf != NULL);
247 }
248
249 /* ------------------- */
250
251 /* Main Driver Management API calls:
252  *      Make a copy of the driver for the specified property on the given ID block
253  */
254 short ANIM_copy_driver (ID *id, const char rna_path[], int array_index, short flag)
255 {
256         PointerRNA id_ptr, ptr;
257         PropertyRNA *prop;
258         FCurve *fcu;
259         
260         /* validate pointer first - exit if failure */
261         RNA_id_pointer_create(id, &id_ptr);
262         if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
263                 printf("Copy Driver: Could not find Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path);
264                 return 0;
265         }
266         
267         /* try to get F-Curve with Driver */
268         fcu= verify_driver_fcurve(id, rna_path, array_index, 0);
269         
270         /* clear copy/paste buffer first (for consistency with other copy/paste buffers) */
271         free_anim_drivers_copybuf();
272         
273         /* copy this to the copy/paste buf if it exists */
274         if (fcu && fcu->driver) {
275                 /* make copies of some info such as the rna_path, then clear this info from the F-Curve temporarily
276                  * so that we don't end up wasting memory storing the path which won't get used ever...
277                  */
278                 char *tmp_path = fcu->rna_path;
279                 fcu->rna_path= NULL;
280                 
281                 /* make a copy of the F-Curve with */
282                 channeldriver_copypaste_buf= copy_fcurve(fcu);
283                 
284                 /* restore the path */
285                 fcu->rna_path= tmp_path;
286                 
287                 /* copied... */
288                 return 1;
289         }
290         
291         /* done */
292         return 0;
293 }
294
295 /* Main Driver Management API calls:
296  *      Add a new driver for the specified property on the given ID block or replace an existing one
297  *      with the driver + driver-curve data from the buffer 
298  */
299 short ANIM_paste_driver (ID *id, const char rna_path[], int array_index, short flag)
300 {       
301         PointerRNA id_ptr, ptr;
302         PropertyRNA *prop;
303         FCurve *fcu;
304         
305         /* validate pointer first - exit if failure */
306         RNA_id_pointer_create(id, &id_ptr);
307         if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
308                 printf("Paste Driver: Could not add Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path);
309                 return 0;
310         }
311         
312         /* if the buffer is empty, cannot paste... */
313         if (channeldriver_copypaste_buf == NULL) {
314                 printf("Paste Driver: No Driver to paste. \n");
315                 return 0;
316         }
317         
318         /* create Driver F-Curve, but without data which will be copied across... */
319         fcu= verify_driver_fcurve(id, rna_path, array_index, -1);
320
321         if (fcu) {
322                 /* copy across the curve data from the buffer curve 
323                  * NOTE: this step needs care to not miss new settings
324                  */
325                         /* keyframes/samples */
326                 fcu->bezt= MEM_dupallocN(channeldriver_copypaste_buf->bezt);
327                 fcu->fpt= MEM_dupallocN(channeldriver_copypaste_buf->fpt);
328                 fcu->totvert= channeldriver_copypaste_buf->totvert;
329                 
330                         /* modifiers */
331                 copy_fmodifiers(&fcu->modifiers, &channeldriver_copypaste_buf->modifiers);
332                 
333                         /* flags - on a per-relevant-flag basis */
334                 if (channeldriver_copypaste_buf->flag & FCURVE_AUTO_HANDLES)
335                         fcu->flag |= FCURVE_AUTO_HANDLES;
336                 else
337                         fcu->flag &= ~FCURVE_AUTO_HANDLES;
338                         /* extrapolation mode */
339                 fcu->extend= channeldriver_copypaste_buf->extend;
340                         
341                         /* the 'juicy' stuff - the driver */
342                 fcu->driver= fcurve_copy_driver(channeldriver_copypaste_buf->driver);
343         }
344         
345         /* done */
346         return (fcu != NULL);
347 }
348
349 /* ************************************************** */
350 /* UI-Button Interface */
351
352 /* Add Driver Button Operator ------------------------ */
353
354 static int add_driver_button_exec (bContext *C, wmOperator *op)
355 {
356         PointerRNA ptr;
357         PropertyRNA *prop= NULL;
358         char *path;
359         short success= 0;
360         int a, index, length, all= RNA_boolean_get(op->ptr, "all");
361         
362         /* try to create driver using property retrieved from UI */
363         memset(&ptr, 0, sizeof(PointerRNA));
364         uiAnimContextProperty(C, &ptr, &prop, &index);
365         
366         if (ptr.data && prop && RNA_property_animateable(ptr.data, prop)) {
367                 path= RNA_path_from_ID_to_property(&ptr, prop);
368                 
369                 if (path) {
370                         if (all) {
371                                 length= RNA_property_array_length(&ptr, prop);
372                                 
373                                 if (length) index= 0;
374                                 else length= 1;
375                         }
376                         else
377                                 length= 1;
378                         
379                         for (a=0; a<length; a++)
380                                 success+= ANIM_add_driver(ptr.id.data, path, index+a, 0, DRIVER_TYPE_PYTHON);
381                         
382                         MEM_freeN(path);
383                 }
384         }
385         
386         if (success) {
387                 /* send updates */
388                 ED_anim_dag_flush_update(C);    
389                 
390                 /* for now, only send ND_KEYS for KeyingSets */
391                 WM_event_add_notifier(C, ND_KEYS, NULL); // XXX
392         }
393         
394         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
395 }
396
397 void ANIM_OT_add_driver_button (wmOperatorType *ot)
398 {
399         /* identifiers */
400         ot->name= "Add Driver";
401         ot->idname= "ANIM_OT_add_driver_button";
402         ot->description= "Add driver(s) for the property(s) connected represented by the highlighted button.";
403         
404         /* callbacks */
405         ot->exec= add_driver_button_exec; 
406         //op->poll= ??? // TODO: need to have some animateable property to do this
407         
408         /* flags */
409         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
410
411         /* properties */
412         RNA_def_boolean(ot->srna, "all", 1, "All", "Create drivers for all elements of the array.");
413 }
414
415 /* Remove Driver Button Operator ------------------------ */
416
417 static int remove_driver_button_exec (bContext *C, wmOperator *op)
418 {
419         PointerRNA ptr;
420         PropertyRNA *prop= NULL;
421         char *path;
422         short success= 0;
423         int a, index, length, all= RNA_boolean_get(op->ptr, "all");
424         
425         /* try to find driver using property retrieved from UI */
426         memset(&ptr, 0, sizeof(PointerRNA));
427         uiAnimContextProperty(C, &ptr, &prop, &index);
428
429         if (ptr.data && prop) {
430                 path= RNA_path_from_ID_to_property(&ptr, prop);
431                 
432                 if (path) {
433                         if (all) {
434                                 length= RNA_property_array_length(&ptr, prop);
435                                 
436                                 if(length) index= 0;
437                                 else length= 1;
438                         }
439                         else
440                                 length= 1;
441                         
442                         for (a=0; a<length; a++)
443                                 success+= ANIM_remove_driver(ptr.id.data, path, index+a, 0);
444                         
445                         MEM_freeN(path);
446                 }
447         }
448         
449         
450         if (success) {
451                 /* send updates */
452                 ED_anim_dag_flush_update(C);    
453                 
454                 /* for now, only send ND_KEYS for KeyingSets */
455                 WM_event_add_notifier(C, ND_KEYS, NULL);  // XXX
456         }
457         
458         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
459 }
460
461 void ANIM_OT_remove_driver_button (wmOperatorType *ot)
462 {
463         /* identifiers */
464         ot->name= "Remove Driver";
465         ot->idname= "ANIM_OT_remove_driver_button";
466         ot->description= "Remove the driver(s) for the property(s) connected represented by the highlighted button.";
467         
468         /* callbacks */
469         ot->exec= remove_driver_button_exec; 
470         //op->poll= ??? // TODO: need to have some driver to be able to do this...
471         
472         /* flags */
473         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
474
475         /* properties */
476         RNA_def_boolean(ot->srna, "all", 1, "All", "Delete drivers for all elements of the array.");
477 }
478
479 /* Copy Driver Button Operator ------------------------ */
480
481 static int copy_driver_button_exec (bContext *C, wmOperator *op)
482 {
483         PointerRNA ptr;
484         PropertyRNA *prop= NULL;
485         char *path;
486         short success= 0;
487         int index;
488         
489         /* try to create driver using property retrieved from UI */
490         memset(&ptr, 0, sizeof(PointerRNA));
491         uiAnimContextProperty(C, &ptr, &prop, &index);
492         
493         if (ptr.data && prop && RNA_property_animateable(ptr.data, prop)) {
494                 path= RNA_path_from_ID_to_property(&ptr, prop);
495                 
496                 if (path) {
497                         /* only copy the driver for the button that this was involved for */
498                         success= ANIM_copy_driver(ptr.id.data, path, index, 0);
499                         
500                         MEM_freeN(path);
501                 }
502         }
503         
504         /* since we're just copying, we don't really need to do anything else...*/
505         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
506 }
507
508 void ANIM_OT_copy_driver_button (wmOperatorType *ot)
509 {
510         /* identifiers */
511         ot->name= "Copy Driver";
512         ot->idname= "ANIM_OT_copy_driver_button";
513         ot->description= "Copy the driver for the highlighted button.";
514         
515         /* callbacks */
516         ot->exec= copy_driver_button_exec; 
517         //op->poll= ??? // TODO: need to have some driver to be able to do this...
518         
519         /* flags */
520         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
521 }
522
523 /* Paste Driver Button Operator ------------------------ */
524
525 static int paste_driver_button_exec (bContext *C, wmOperator *op)
526 {
527         PointerRNA ptr;
528         PropertyRNA *prop= NULL;
529         char *path;
530         short success= 0;
531         int index;
532         
533         /* try to create driver using property retrieved from UI */
534         memset(&ptr, 0, sizeof(PointerRNA));
535         uiAnimContextProperty(C, &ptr, &prop, &index);
536         
537         if (ptr.data && prop && RNA_property_animateable(ptr.data, prop)) {
538                 path= RNA_path_from_ID_to_property(&ptr, prop);
539                 
540                 if (path) {
541                         /* only copy the driver for the button that this was involved for */
542                         success= ANIM_paste_driver(ptr.id.data, path, index, 0);
543                         
544                         MEM_freeN(path);
545                 }
546         }
547         
548         /* since we're just copying, we don't really need to do anything else...*/
549         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
550 }
551
552 void ANIM_OT_paste_driver_button (wmOperatorType *ot)
553 {
554         /* identifiers */
555         ot->name= "Paste Driver";
556         ot->idname= "ANIM_OT_paste_driver_button";
557         ot->description= "Paste the driver in the copy/paste buffer for the highlighted button.";
558         
559         /* callbacks */
560         ot->exec= paste_driver_button_exec; 
561         //op->poll= ??? // TODO: need to have some driver to be able to do this...
562         
563         /* flags */
564         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
565 }
566
567
568 /* Copy to Clipboard Button Operator ------------------------ */
569
570 static int copy_clipboard_button_exec(bContext *C, wmOperator *op)
571 {
572         PointerRNA ptr;
573         PropertyRNA *prop= NULL;
574         char *path;
575         short success= 0;
576         int index;
577
578         /* try to create driver using property retrieved from UI */
579         memset(&ptr, 0, sizeof(PointerRNA));
580         uiAnimContextProperty(C, &ptr, &prop, &index);
581
582         if (ptr.data && prop) {
583                 path= RNA_path_from_ID_to_property(&ptr, prop);
584                 
585                 if (path) {
586                         WM_clipboard_text_set(path, FALSE);
587                         MEM_freeN(path);
588                 }
589         }
590
591         /* since we're just copying, we don't really need to do anything else...*/
592         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
593 }
594
595 void ANIM_OT_copy_clipboard_button(wmOperatorType *ot)
596 {
597         /* identifiers */
598         ot->name= "Copy Data Path";
599         ot->idname= "ANIM_OT_copy_clipboard_button";
600         ot->description= "Copy the RNA data path for this property to the clipboard.";
601
602         /* callbacks */
603         ot->exec= copy_clipboard_button_exec;
604         //op->poll= ??? // TODO: need to have some valid property before this can be done
605
606         /* flags */
607         ot->flag= OPTYPE_REGISTER;
608 }
609
610 /* ************************************************** */