4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
20 * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): Joshua Leung (full recode)
27 * ***** END GPL LICENSE BLOCK *****
36 #include "MEM_guardedalloc.h"
38 #include "BLI_blenlib.h"
39 #include "BLI_arithb.h"
40 #include "BLI_dynstr.h"
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"
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"
61 #include "BKE_material.h"
63 #include "ED_anim_api.h"
64 #include "ED_keyframing.h"
65 #include "ED_keyframes_edit.h"
66 #include "ED_screen.h"
69 #include "UI_interface.h"
74 #include "RNA_access.h"
75 #include "RNA_define.h"
76 #include "RNA_types.h"
78 /* ************************************************** */
79 /* Animation Data Validation */
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.
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)
88 FCurve *verify_driver_fcurve (ID *id, const char rna_path[], const int array_index, short add)
94 if ELEM(NULL, id, rna_path)
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);
102 /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
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
110 fcu= list_find_fcurve(&adt->drivers, rna_path, array_index);
112 if ((fcu == NULL) && (add)) {
113 /* use default settings to make a F-Curve */
114 fcu= MEM_callocN(sizeof(FCurve), "FCurve");
116 fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
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;
122 /* if add is negative, don't init this data yet, since it will be filled in by the pasted driver */
124 /* add some new driver data */
125 fcu->driver= MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
127 /* add simple generator modifier for driver so that there is some visible representation */
128 add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR);
131 /* just add F-Curve to end of driver list */
132 BLI_addtail(&adt->drivers, fcu);
135 /* return the F-Curve */
139 /* ************************************************** */
140 /* Driver Management API */
142 /* Main Driver Management API calls:
143 * Add a new driver for the specified property on the given ID block
145 short ANIM_add_driver (ID *id, const char rna_path[], int array_index, short flag, int type)
147 PointerRNA id_ptr, ptr;
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);
158 /* create F-Curve with Driver */
159 fcu= verify_driver_fcurve(id, rna_path, array_index, 1);
161 if (fcu && fcu->driver) {
162 fcu->driver->type= type;
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);
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);
176 BLI_strncpy(expression, (val)? "True": "False", maxlen);
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);
182 BLI_snprintf(expression, maxlen, "%d", val);
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);
188 BLI_snprintf(expression, maxlen, "%.3f", fval);
194 return (fcu != NULL);
197 /* Main Driver Management API calls:
198 * Remove the driver for the specified property on the given ID block (if available)
200 short ANIM_remove_driver (struct ID *id, const char rna_path[], int array_index, short flag)
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
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);
213 /* only continue if we have an driver to remove */
215 /* remove F-Curve from driver stack, then free it */
216 BLI_remlink(&adt->drivers, fcu);
219 /* done successfully */
227 /* ************************************************** */
228 /* Driver Management API - Copy/Paste Drivers */
230 /* Copy/Paste Buffer for Driver Data... */
231 static FCurve *channeldriver_copypaste_buf = NULL;
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)
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;
243 /* Checks if there is a driver in the copy/paste buffer */
244 short ANIM_driver_can_paste (void)
246 return (channeldriver_copypaste_buf != NULL);
249 /* ------------------- */
251 /* Main Driver Management API calls:
252 * Make a copy of the driver for the specified property on the given ID block
254 short ANIM_copy_driver (ID *id, const char rna_path[], int array_index, short flag)
256 PointerRNA id_ptr, ptr;
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);
267 /* try to get F-Curve with Driver */
268 fcu= verify_driver_fcurve(id, rna_path, array_index, 0);
270 /* clear copy/paste buffer first (for consistency with other copy/paste buffers) */
271 free_anim_drivers_copybuf();
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...
278 char *tmp_path = fcu->rna_path;
281 /* make a copy of the F-Curve with */
282 channeldriver_copypaste_buf= copy_fcurve(fcu);
284 /* restore the path */
285 fcu->rna_path= tmp_path;
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
299 short ANIM_paste_driver (ID *id, const char rna_path[], int array_index, short flag)
301 PointerRNA id_ptr, ptr;
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);
312 /* if the buffer is empty, cannot paste... */
313 if (channeldriver_copypaste_buf == NULL) {
314 printf("Paste Driver: No Driver to paste. \n");
318 /* create Driver F-Curve, but without data which will be copied across... */
319 fcu= verify_driver_fcurve(id, rna_path, array_index, -1);
322 /* copy across the curve data from the buffer curve
323 * NOTE: this step needs care to not miss new settings
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;
331 copy_fmodifiers(&fcu->modifiers, &channeldriver_copypaste_buf->modifiers);
333 /* flags - on a per-relevant-flag basis */
334 if (channeldriver_copypaste_buf->flag & FCURVE_AUTO_HANDLES)
335 fcu->flag |= FCURVE_AUTO_HANDLES;
337 fcu->flag &= ~FCURVE_AUTO_HANDLES;
338 /* extrapolation mode */
339 fcu->extend= channeldriver_copypaste_buf->extend;
341 /* the 'juicy' stuff - the driver */
342 fcu->driver= fcurve_copy_driver(channeldriver_copypaste_buf->driver);
346 return (fcu != NULL);
349 /* ************************************************** */
350 /* UI-Button Interface */
352 /* Add Driver Button Operator ------------------------ */
354 static int add_driver_button_exec (bContext *C, wmOperator *op)
357 PropertyRNA *prop= NULL;
360 int a, index, length, all= RNA_boolean_get(op->ptr, "all");
362 /* try to create driver using property retrieved from UI */
363 memset(&ptr, 0, sizeof(PointerRNA));
364 uiAnimContextProperty(C, &ptr, &prop, &index);
366 if (ptr.data && prop && RNA_property_animateable(ptr.data, prop)) {
367 path= RNA_path_from_ID_to_property(&ptr, prop);
371 length= RNA_property_array_length(&ptr, prop);
373 if (length) index= 0;
379 for (a=0; a<length; a++)
380 success+= ANIM_add_driver(ptr.id.data, path, index+a, 0, DRIVER_TYPE_PYTHON);
388 ED_anim_dag_flush_update(C);
390 /* for now, only send ND_KEYS for KeyingSets */
391 WM_event_add_notifier(C, ND_KEYS, NULL); // XXX
394 return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
397 void ANIM_OT_add_driver_button (wmOperatorType *ot)
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.";
405 ot->exec= add_driver_button_exec;
406 //op->poll= ??? // TODO: need to have some animateable property to do this
409 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
412 RNA_def_boolean(ot->srna, "all", 1, "All", "Create drivers for all elements of the array.");
415 /* Remove Driver Button Operator ------------------------ */
417 static int remove_driver_button_exec (bContext *C, wmOperator *op)
420 PropertyRNA *prop= NULL;
423 int a, index, length, all= RNA_boolean_get(op->ptr, "all");
425 /* try to find driver using property retrieved from UI */
426 memset(&ptr, 0, sizeof(PointerRNA));
427 uiAnimContextProperty(C, &ptr, &prop, &index);
429 if (ptr.data && prop) {
430 path= RNA_path_from_ID_to_property(&ptr, prop);
434 length= RNA_property_array_length(&ptr, prop);
442 for (a=0; a<length; a++)
443 success+= ANIM_remove_driver(ptr.id.data, path, index+a, 0);
452 ED_anim_dag_flush_update(C);
454 /* for now, only send ND_KEYS for KeyingSets */
455 WM_event_add_notifier(C, ND_KEYS, NULL); // XXX
458 return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
461 void ANIM_OT_remove_driver_button (wmOperatorType *ot)
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.";
469 ot->exec= remove_driver_button_exec;
470 //op->poll= ??? // TODO: need to have some driver to be able to do this...
473 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
476 RNA_def_boolean(ot->srna, "all", 1, "All", "Delete drivers for all elements of the array.");
479 /* Copy Driver Button Operator ------------------------ */
481 static int copy_driver_button_exec (bContext *C, wmOperator *op)
484 PropertyRNA *prop= NULL;
489 /* try to create driver using property retrieved from UI */
490 memset(&ptr, 0, sizeof(PointerRNA));
491 uiAnimContextProperty(C, &ptr, &prop, &index);
493 if (ptr.data && prop && RNA_property_animateable(ptr.data, prop)) {
494 path= RNA_path_from_ID_to_property(&ptr, prop);
497 /* only copy the driver for the button that this was involved for */
498 success= ANIM_copy_driver(ptr.id.data, path, index, 0);
504 /* since we're just copying, we don't really need to do anything else...*/
505 return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
508 void ANIM_OT_copy_driver_button (wmOperatorType *ot)
511 ot->name= "Copy Driver";
512 ot->idname= "ANIM_OT_copy_driver_button";
513 ot->description= "Copy the driver for the highlighted button.";
516 ot->exec= copy_driver_button_exec;
517 //op->poll= ??? // TODO: need to have some driver to be able to do this...
520 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
523 /* Paste Driver Button Operator ------------------------ */
525 static int paste_driver_button_exec (bContext *C, wmOperator *op)
528 PropertyRNA *prop= NULL;
533 /* try to create driver using property retrieved from UI */
534 memset(&ptr, 0, sizeof(PointerRNA));
535 uiAnimContextProperty(C, &ptr, &prop, &index);
537 if (ptr.data && prop && RNA_property_animateable(ptr.data, prop)) {
538 path= RNA_path_from_ID_to_property(&ptr, prop);
541 /* only copy the driver for the button that this was involved for */
542 success= ANIM_paste_driver(ptr.id.data, path, index, 0);
548 /* since we're just copying, we don't really need to do anything else...*/
549 return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
552 void ANIM_OT_paste_driver_button (wmOperatorType *ot)
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.";
560 ot->exec= paste_driver_button_exec;
561 //op->poll= ??? // TODO: need to have some driver to be able to do this...
564 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
568 /* Copy to Clipboard Button Operator ------------------------ */
570 static int copy_clipboard_button_exec(bContext *C, wmOperator *op)
573 PropertyRNA *prop= NULL;
578 /* try to create driver using property retrieved from UI */
579 memset(&ptr, 0, sizeof(PointerRNA));
580 uiAnimContextProperty(C, &ptr, &prop, &index);
582 if (ptr.data && prop) {
583 path= RNA_path_from_ID_to_property(&ptr, prop);
586 WM_clipboard_text_set(path, FALSE);
591 /* since we're just copying, we don't really need to do anything else...*/
592 return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
595 void ANIM_OT_copy_clipboard_button(wmOperatorType *ot)
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.";
603 ot->exec= copy_clipboard_button_exec;
604 //op->poll= ??? // TODO: need to have some valid property before this can be done
607 ot->flag= OPTYPE_REGISTER;
610 /* ************************************************** */