- modal keymap for border select
[blender-staging.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         int array_index_max = array_index+1;
151         
152         /* validate pointer first - exit if failure */
153         RNA_id_pointer_create(id, &id_ptr);
154         if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
155                 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);
156                 return 0;
157         }
158         
159         /* key entire array convenience method */
160         if (array_index == -1) {
161                 array_index= 0;
162                 array_index_max= RNA_property_array_length(&ptr, prop) + 1;
163         }
164         
165         /* will only loop once unless the array index was -1 */
166         for (; array_index < array_index_max; array_index++) {
167                 /* create F-Curve with Driver */
168                 fcu= verify_driver_fcurve(id, rna_path, array_index, 1);
169                 
170                 if (fcu && fcu->driver) {
171                         fcu->driver->type= type;
172                         
173                         /* fill in current value for python */
174                         if (type == DRIVER_TYPE_PYTHON) {
175                                 PropertyType proptype= RNA_property_type(prop);
176                                 int array= RNA_property_array_length(&ptr, prop);
177                                 char *expression= fcu->driver->expression;
178                                 int val, maxlen= sizeof(fcu->driver->expression);
179                                 float fval;
180                                 
181                                 if (proptype == PROP_BOOLEAN) {
182                                         if (!array) val= RNA_property_boolean_get(&ptr, prop);
183                                         else val= RNA_property_boolean_get_index(&ptr, prop, array_index);
184                                         
185                                         BLI_strncpy(expression, (val)? "True": "False", maxlen);
186                                 }
187                                 else if (proptype == PROP_INT) {
188                                         if (!array) val= RNA_property_int_get(&ptr, prop);
189                                         else val= RNA_property_int_get_index(&ptr, prop, array_index);
190                                         
191                                         BLI_snprintf(expression, maxlen, "%d", val);
192                                 }
193                                 else if (proptype == PROP_FLOAT) {
194                                         if (!array) fval= RNA_property_float_get(&ptr, prop);
195                                         else fval= RNA_property_float_get_index(&ptr, prop, array_index);
196                                         
197                                         BLI_snprintf(expression, maxlen, "%.3f", fval);
198                                 }
199                         }
200                 }
201         }
202         
203         /* done */
204         return (fcu != NULL);
205 }
206
207 /* Main Driver Management API calls:
208  *      Remove the driver for the specified property on the given ID block (if available)
209  */
210 short ANIM_remove_driver (struct ID *id, const char rna_path[], int array_index, short flag)
211 {
212         AnimData *adt;
213         FCurve *fcu;
214         
215         /* get F-Curve
216          * Note: here is one of the places where we don't want new F-Curve + Driver added!
217          *              so 'add' var must be 0
218          */
219         /* we don't check the validity of the path here yet, but it should be ok... */
220         fcu= verify_driver_fcurve(id, rna_path, array_index, 0);
221         adt= BKE_animdata_from_id(id);
222         
223         /* only continue if we have an driver to remove */
224         if (adt && fcu) {
225                 /* remove F-Curve from driver stack, then free it */
226                 BLI_remlink(&adt->drivers, fcu);
227                 free_fcurve(fcu);
228                 
229                 /* done successfully */
230                 return 1;
231         }
232         
233         /* failed */
234         return 0;
235 }
236
237 /* ************************************************** */
238 /* Driver Management API - Copy/Paste Drivers */
239
240 /* Copy/Paste Buffer for Driver Data... */
241 static FCurve *channeldriver_copypaste_buf = NULL;
242
243 /* This function frees any MEM_calloc'ed copy/paste buffer data */
244 // XXX find some header to put this in!
245 void free_anim_drivers_copybuf (void)
246 {
247         /* free the buffer F-Curve if it exists, as if it were just another F-Curve */
248         if (channeldriver_copypaste_buf)
249                 free_fcurve(channeldriver_copypaste_buf);
250         channeldriver_copypaste_buf= NULL;
251 }
252
253 /* Checks if there is a driver in the copy/paste buffer */
254 short ANIM_driver_can_paste (void)
255 {
256         return (channeldriver_copypaste_buf != NULL);
257 }
258
259 /* ------------------- */
260
261 /* Main Driver Management API calls:
262  *      Make a copy of the driver for the specified property on the given ID block
263  */
264 short ANIM_copy_driver (ID *id, const char rna_path[], int array_index, short flag)
265 {
266         PointerRNA id_ptr, ptr;
267         PropertyRNA *prop;
268         FCurve *fcu;
269         
270         /* validate pointer first - exit if failure */
271         RNA_id_pointer_create(id, &id_ptr);
272         if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
273                 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);
274                 return 0;
275         }
276         
277         /* try to get F-Curve with Driver */
278         fcu= verify_driver_fcurve(id, rna_path, array_index, 0);
279         
280         /* clear copy/paste buffer first (for consistency with other copy/paste buffers) */
281         free_anim_drivers_copybuf();
282         
283         /* copy this to the copy/paste buf if it exists */
284         if (fcu && fcu->driver) {
285                 /* make copies of some info such as the rna_path, then clear this info from the F-Curve temporarily
286                  * so that we don't end up wasting memory storing the path which won't get used ever...
287                  */
288                 char *tmp_path = fcu->rna_path;
289                 fcu->rna_path= NULL;
290                 
291                 /* make a copy of the F-Curve with */
292                 channeldriver_copypaste_buf= copy_fcurve(fcu);
293                 
294                 /* restore the path */
295                 fcu->rna_path= tmp_path;
296                 
297                 /* copied... */
298                 return 1;
299         }
300         
301         /* done */
302         return 0;
303 }
304
305 /* Main Driver Management API calls:
306  *      Add a new driver for the specified property on the given ID block or replace an existing one
307  *      with the driver + driver-curve data from the buffer 
308  */
309 short ANIM_paste_driver (ID *id, const char rna_path[], int array_index, short flag)
310 {       
311         PointerRNA id_ptr, ptr;
312         PropertyRNA *prop;
313         FCurve *fcu;
314         
315         /* validate pointer first - exit if failure */
316         RNA_id_pointer_create(id, &id_ptr);
317         if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
318                 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);
319                 return 0;
320         }
321         
322         /* if the buffer is empty, cannot paste... */
323         if (channeldriver_copypaste_buf == NULL) {
324                 printf("Paste Driver: No Driver to paste. \n");
325                 return 0;
326         }
327         
328         /* create Driver F-Curve, but without data which will be copied across... */
329         fcu= verify_driver_fcurve(id, rna_path, array_index, -1);
330
331         if (fcu) {
332                 /* copy across the curve data from the buffer curve 
333                  * NOTE: this step needs care to not miss new settings
334                  */
335                         /* keyframes/samples */
336                 fcu->bezt= MEM_dupallocN(channeldriver_copypaste_buf->bezt);
337                 fcu->fpt= MEM_dupallocN(channeldriver_copypaste_buf->fpt);
338                 fcu->totvert= channeldriver_copypaste_buf->totvert;
339                 
340                         /* modifiers */
341                 copy_fmodifiers(&fcu->modifiers, &channeldriver_copypaste_buf->modifiers);
342                 
343                         /* flags - on a per-relevant-flag basis */
344                 if (channeldriver_copypaste_buf->flag & FCURVE_AUTO_HANDLES)
345                         fcu->flag |= FCURVE_AUTO_HANDLES;
346                 else
347                         fcu->flag &= ~FCURVE_AUTO_HANDLES;
348                         /* extrapolation mode */
349                 fcu->extend= channeldriver_copypaste_buf->extend;
350                         
351                         /* the 'juicy' stuff - the driver */
352                 fcu->driver= fcurve_copy_driver(channeldriver_copypaste_buf->driver);
353         }
354         
355         /* done */
356         return (fcu != NULL);
357 }
358
359 /* ************************************************** */
360 /* UI-Button Interface */
361
362 /* Add Driver Button Operator ------------------------ */
363
364 static int add_driver_button_exec (bContext *C, wmOperator *op)
365 {
366         PointerRNA ptr;
367         PropertyRNA *prop= NULL;
368         char *path;
369         short success= 0;
370         int index, all= RNA_boolean_get(op->ptr, "all");
371         
372         /* try to create driver using property retrieved from UI */
373         memset(&ptr, 0, sizeof(PointerRNA));
374         uiAnimContextProperty(C, &ptr, &prop, &index);
375
376         if (all)
377                 index= -1;
378
379         if (ptr.data && prop && RNA_property_animateable(ptr.data, prop)) {
380                 path= RNA_path_from_ID_to_property(&ptr, prop);
381                 
382                 if (path) {                     
383                         success+= ANIM_add_driver(ptr.id.data, path, index, 0, DRIVER_TYPE_PYTHON);
384                         
385                         MEM_freeN(path);
386                 }
387         }
388         
389         if (success) {
390                 /* send updates */
391                 ED_anim_dag_flush_update(C);    
392                 
393                 /* for now, only send ND_KEYS for KeyingSets */
394                 WM_event_add_notifier(C, ND_KEYS, NULL); // XXX
395         }
396         
397         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
398 }
399
400 void ANIM_OT_add_driver_button (wmOperatorType *ot)
401 {
402         /* identifiers */
403         ot->name= "Add Driver";
404         ot->idname= "ANIM_OT_add_driver_button";
405         ot->description= "Add driver(s) for the property(s) connected represented by the highlighted button.";
406         
407         /* callbacks */
408         ot->exec= add_driver_button_exec; 
409         //op->poll= ??? // TODO: need to have some animateable property to do this
410         
411         /* flags */
412         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
413
414         /* properties */
415         RNA_def_boolean(ot->srna, "all", 1, "All", "Create drivers for all elements of the array.");
416 }
417
418 /* Remove Driver Button Operator ------------------------ */
419
420 static int remove_driver_button_exec (bContext *C, wmOperator *op)
421 {
422         PointerRNA ptr;
423         PropertyRNA *prop= NULL;
424         char *path;
425         short success= 0;
426         int a, index, length, all= RNA_boolean_get(op->ptr, "all");
427         
428         /* try to find driver using property retrieved from UI */
429         memset(&ptr, 0, sizeof(PointerRNA));
430         uiAnimContextProperty(C, &ptr, &prop, &index);
431
432         if (ptr.data && prop) {
433                 path= RNA_path_from_ID_to_property(&ptr, prop);
434                 
435                 if (path) {
436                         if (all) {
437                                 length= RNA_property_array_length(&ptr, prop);
438                                 
439                                 if(length) index= 0;
440                                 else length= 1;
441                         }
442                         else
443                                 length= 1;
444                         
445                         for (a=0; a<length; a++)
446                                 success+= ANIM_remove_driver(ptr.id.data, path, index+a, 0);
447                         
448                         MEM_freeN(path);
449                 }
450         }
451         
452         
453         if (success) {
454                 /* send updates */
455                 ED_anim_dag_flush_update(C);    
456                 
457                 /* for now, only send ND_KEYS for KeyingSets */
458                 WM_event_add_notifier(C, ND_KEYS, NULL);  // XXX
459         }
460         
461         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
462 }
463
464 void ANIM_OT_remove_driver_button (wmOperatorType *ot)
465 {
466         /* identifiers */
467         ot->name= "Remove Driver";
468         ot->idname= "ANIM_OT_remove_driver_button";
469         ot->description= "Remove the driver(s) for the property(s) connected represented by the highlighted button.";
470         
471         /* callbacks */
472         ot->exec= remove_driver_button_exec; 
473         //op->poll= ??? // TODO: need to have some driver to be able to do this...
474         
475         /* flags */
476         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
477
478         /* properties */
479         RNA_def_boolean(ot->srna, "all", 1, "All", "Delete drivers for all elements of the array.");
480 }
481
482 /* Copy Driver Button Operator ------------------------ */
483
484 static int copy_driver_button_exec (bContext *C, wmOperator *op)
485 {
486         PointerRNA ptr;
487         PropertyRNA *prop= NULL;
488         char *path;
489         short success= 0;
490         int index;
491         
492         /* try to create driver using property retrieved from UI */
493         memset(&ptr, 0, sizeof(PointerRNA));
494         uiAnimContextProperty(C, &ptr, &prop, &index);
495         
496         if (ptr.data && prop && RNA_property_animateable(ptr.data, prop)) {
497                 path= RNA_path_from_ID_to_property(&ptr, prop);
498                 
499                 if (path) {
500                         /* only copy the driver for the button that this was involved for */
501                         success= ANIM_copy_driver(ptr.id.data, path, index, 0);
502                         
503                         MEM_freeN(path);
504                 }
505         }
506         
507         /* since we're just copying, we don't really need to do anything else...*/
508         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
509 }
510
511 void ANIM_OT_copy_driver_button (wmOperatorType *ot)
512 {
513         /* identifiers */
514         ot->name= "Copy Driver";
515         ot->idname= "ANIM_OT_copy_driver_button";
516         ot->description= "Copy the driver for the highlighted button.";
517         
518         /* callbacks */
519         ot->exec= copy_driver_button_exec; 
520         //op->poll= ??? // TODO: need to have some driver to be able to do this...
521         
522         /* flags */
523         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
524 }
525
526 /* Paste Driver Button Operator ------------------------ */
527
528 static int paste_driver_button_exec (bContext *C, wmOperator *op)
529 {
530         PointerRNA ptr;
531         PropertyRNA *prop= NULL;
532         char *path;
533         short success= 0;
534         int index;
535         
536         /* try to create driver using property retrieved from UI */
537         memset(&ptr, 0, sizeof(PointerRNA));
538         uiAnimContextProperty(C, &ptr, &prop, &index);
539         
540         if (ptr.data && prop && RNA_property_animateable(ptr.data, prop)) {
541                 path= RNA_path_from_ID_to_property(&ptr, prop);
542                 
543                 if (path) {
544                         /* only copy the driver for the button that this was involved for */
545                         success= ANIM_paste_driver(ptr.id.data, path, index, 0);
546                         
547                         MEM_freeN(path);
548                 }
549         }
550         
551         /* since we're just copying, we don't really need to do anything else...*/
552         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
553 }
554
555 void ANIM_OT_paste_driver_button (wmOperatorType *ot)
556 {
557         /* identifiers */
558         ot->name= "Paste Driver";
559         ot->idname= "ANIM_OT_paste_driver_button";
560         ot->description= "Paste the driver in the copy/paste buffer for the highlighted button.";
561         
562         /* callbacks */
563         ot->exec= paste_driver_button_exec; 
564         //op->poll= ??? // TODO: need to have some driver to be able to do this...
565         
566         /* flags */
567         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
568 }
569
570
571 /* Copy to Clipboard Button Operator ------------------------ */
572
573 static int copy_clipboard_button_exec(bContext *C, wmOperator *op)
574 {
575         PointerRNA ptr;
576         PropertyRNA *prop= NULL;
577         char *path;
578         short success= 0;
579         int index;
580
581         /* try to create driver using property retrieved from UI */
582         memset(&ptr, 0, sizeof(PointerRNA));
583         uiAnimContextProperty(C, &ptr, &prop, &index);
584
585         if (ptr.data && prop) {
586                 path= RNA_path_from_ID_to_property(&ptr, prop);
587                 
588                 if (path) {
589                         WM_clipboard_text_set(path, FALSE);
590                         MEM_freeN(path);
591                 }
592         }
593
594         /* since we're just copying, we don't really need to do anything else...*/
595         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
596 }
597
598 void ANIM_OT_copy_clipboard_button(wmOperatorType *ot)
599 {
600         /* identifiers */
601         ot->name= "Copy Data Path";
602         ot->idname= "ANIM_OT_copy_clipboard_button";
603         ot->description= "Copy the RNA data path for this property to the clipboard.";
604
605         /* callbacks */
606         ot->exec= copy_clipboard_button_exec;
607         //op->poll= ??? // TODO: need to have some valid property before this can be done
608
609         /* flags */
610         ot->flag= OPTYPE_REGISTER;
611 }
612
613 /* ************************************************** */