manual merge trunk -r 23037
[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 FCurve *verify_driver_fcurve (ID *id, const char rna_path[], const int array_index, short add)
85 {
86         AnimData *adt;
87         FCurve *fcu;
88         
89         /* sanity checks */
90         if ELEM(NULL, id, rna_path)
91                 return NULL;
92         
93         /* init animdata if none available yet */
94         adt= BKE_animdata_from_id(id);
95         if ((adt == NULL) && (add))
96                 adt= BKE_id_add_animdata(id);
97         if (adt == NULL) { 
98                 /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
99                 return NULL;
100         }
101                 
102         /* try to find f-curve matching for this setting 
103          *      - add if not found and allowed to add one
104          *              TODO: add auto-grouping support? how this works will need to be resolved
105          */
106         fcu= list_find_fcurve(&adt->drivers, rna_path, array_index);
107         
108         if ((fcu == NULL) && (add)) {
109                 /* use default settings to make a F-Curve */
110                 fcu= MEM_callocN(sizeof(FCurve), "FCurve");
111                 
112                 fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
113                 
114                 /* store path - make copy, and store that */
115                 fcu->rna_path= BLI_strdupn(rna_path, strlen(rna_path));
116                 fcu->array_index= array_index;
117                 
118                 /* add some new driver data */
119                 fcu->driver= MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
120                 
121                 /* add simple generator modifier for driver so that there is some visible representation */
122                 add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR);
123                 
124                 /* just add F-Curve to end of driver list */
125                 BLI_addtail(&adt->drivers, fcu);
126         }
127         
128         /* return the F-Curve */
129         return fcu;
130 }
131
132 /* ************************************************** */
133 /* Driver Management API */
134
135 /* Main Driver Management API calls:
136  *      Add a new driver for the specified property on the given ID block
137  */
138 short ANIM_add_driver (ID *id, const char rna_path[], int array_index, short flag, int type)
139 {       
140         PointerRNA id_ptr, ptr;
141         PropertyRNA *prop;
142         FCurve *fcu;
143         
144         /* validate pointer first - exit if failure */
145         RNA_id_pointer_create(id, &id_ptr);
146         if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
147                 printf("Insert Key: Could not add Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path);
148                 return 0;
149         }
150         
151         /* create F-Curve with Driver */
152         fcu= verify_driver_fcurve(id, rna_path, array_index, 1);
153
154         if (fcu && fcu->driver) {
155                 fcu->driver->type= type;
156                 
157                 /* fill in current value for python */
158                 if (type == DRIVER_TYPE_PYTHON) {
159                         PropertyType proptype= RNA_property_type(prop);
160                         int array= RNA_property_array_length(&ptr, prop);
161                         char *expression= fcu->driver->expression;
162                         int val, maxlen= sizeof(fcu->driver->expression);
163                         float fval;
164                         
165                         if (proptype == PROP_BOOLEAN) {
166                                 if(!array) val= RNA_property_boolean_get(&ptr, prop);
167                                 else val= RNA_property_boolean_get_index(&ptr, prop, array_index);
168                                 
169                                 BLI_strncpy(expression, (val)? "True": "False", maxlen);
170                         }
171                         else if (proptype == PROP_INT) {
172                                 if (!array) val= RNA_property_int_get(&ptr, prop);
173                                 else val= RNA_property_int_get_index(&ptr, prop, array_index);
174                                 
175                                 BLI_snprintf(expression, maxlen, "%d", val);
176                         }
177                         else if (proptype == PROP_FLOAT) {
178                                 if (!array) fval= RNA_property_float_get(&ptr, prop);
179                                 else fval= RNA_property_float_get_index(&ptr, prop, array_index);
180                                 
181                                 BLI_snprintf(expression, maxlen, "%.3f", fval);
182                         }
183
184                 }
185         }
186         
187         /* done */
188         return (fcu != NULL);
189 }
190
191 /* Main Driver Management API calls:
192  *      Remove the driver for the specified property on the given ID block (if available)
193  */
194 short ANIM_remove_driver (struct ID *id, const char rna_path[], int array_index, short flag)
195 {
196         AnimData *adt;
197         FCurve *fcu;
198         
199         /* get F-Curve
200          * Note: here is one of the places where we don't want new F-Curve + Driver added!
201          *              so 'add' var must be 0
202          */
203         /* we don't check the validity of the path here yet, but it should be ok... */
204         fcu= verify_driver_fcurve(id, rna_path, array_index, 0);
205         adt= BKE_animdata_from_id(id);
206         
207         /* only continue if we have an driver to remove */
208         if (adt && fcu) {
209                 /* remove F-Curve from driver stack, then free it */
210                 BLI_remlink(&adt->drivers, fcu);
211                 free_fcurve(fcu);
212                 
213                 /* done successfully */
214                 return 1;
215         }
216         
217         /* failed */
218         return 0;
219 }
220
221
222 /* ************************************************** */
223 /* UI-Button Interface */
224
225 /* Add Driver Button Operator ------------------------ */
226
227 static int add_driver_button_exec (bContext *C, wmOperator *op)
228 {
229         PointerRNA ptr;
230         PropertyRNA *prop= NULL;
231         char *path;
232         short success= 0;
233         int a, index, length, all= RNA_boolean_get(op->ptr, "all");
234         
235         /* try to create driver using property retrieved from UI */
236         memset(&ptr, 0, sizeof(PointerRNA));
237         uiAnimContextProperty(C, &ptr, &prop, &index);
238         
239         if (ptr.data && prop && RNA_property_animateable(ptr.data, prop)) {
240                 path= RNA_path_from_ID_to_property(&ptr, prop);
241                 
242                 if (path) {
243                         if (all) {
244                                 length= RNA_property_array_length(&ptr, prop);
245                                 
246                                 if (length) index= 0;
247                                 else length= 1;
248                         }
249                         else
250                                 length= 1;
251                         
252                         for (a=0; a<length; a++)
253                                 success+= ANIM_add_driver(ptr.id.data, path, index+a, 0, DRIVER_TYPE_PYTHON);
254                         
255                         MEM_freeN(path);
256                 }
257         }
258         
259         if (success) {
260                 /* send updates */
261                 ED_anim_dag_flush_update(C);    
262                 
263                 /* for now, only send ND_KEYS for KeyingSets */
264                 WM_event_add_notifier(C, ND_KEYS, NULL); // XXX
265         }
266         
267         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
268 }
269
270 void ANIM_OT_add_driver_button (wmOperatorType *ot)
271 {
272         /* identifiers */
273         ot->name= "Add Driver";
274         ot->idname= "ANIM_OT_add_driver_button";
275         
276         /* callbacks */
277         ot->exec= add_driver_button_exec; 
278         //op->poll= ???
279         
280         /* flags */
281         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
282
283         /* properties */
284         RNA_def_boolean(ot->srna, "all", 1, "All", "Create drivers for all elements of the array.");
285 }
286
287 /* Remove Driver Button Operator ------------------------ */
288
289 static int remove_driver_button_exec (bContext *C, wmOperator *op)
290 {
291         PointerRNA ptr;
292         PropertyRNA *prop= NULL;
293         char *path;
294         short success= 0;
295         int a, index, length, all= RNA_boolean_get(op->ptr, "all");
296         
297         /* try to find driver using property retrieved from UI */
298         memset(&ptr, 0, sizeof(PointerRNA));
299         uiAnimContextProperty(C, &ptr, &prop, &index);
300
301         if (ptr.data && prop) {
302                 path= RNA_path_from_ID_to_property(&ptr, prop);
303                 
304                 if (path) {
305                         if (all) {
306                                 length= RNA_property_array_length(&ptr, prop);
307                                 
308                                 if(length) index= 0;
309                                 else length= 1;
310                         }
311                         else
312                                 length= 1;
313                         
314                         for (a=0; a<length; a++)
315                                 success+= ANIM_remove_driver(ptr.id.data, path, index+a, 0);
316                         
317                         MEM_freeN(path);
318                 }
319         }
320         
321         
322         if (success) {
323                 /* send updates */
324                 ED_anim_dag_flush_update(C);    
325                 
326                 /* for now, only send ND_KEYS for KeyingSets */
327                 WM_event_add_notifier(C, ND_KEYS, NULL);  // XXX
328         }
329         
330         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
331 }
332
333 void ANIM_OT_remove_driver_button (wmOperatorType *ot)
334 {
335         /* identifiers */
336         ot->name= "Remove Driver";
337         ot->idname= "ANIM_OT_remove_driver_button";
338         
339         /* callbacks */
340         ot->exec= remove_driver_button_exec; 
341         //op->poll= ???
342         
343         /* flags */
344         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
345
346         /* properties */
347         RNA_def_boolean(ot->srna, "all", 1, "All", "Delete drivers for all elements of the array.");
348 }
349
350 /* ************************************************** */