code cleanup: spelling
[blender.git] / source / blender / editors / animation / drivers.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Joshua Leung (full recode)
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/animation/drivers.c
29  *  \ingroup edanimation
30  */
31
32  
33 #include <stdio.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_utildefines.h"
40
41 #include "DNA_anim_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_material_types.h"
44 #include "DNA_texture_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_space_types.h"
47
48 #include "BKE_animsys.h"
49 #include "BKE_depsgraph.h"
50 #include "BKE_fcurve.h"
51 #include "BKE_context.h"
52 #include "BKE_report.h"
53 #include "BKE_material.h"
54 #include "BKE_texture.h"
55
56 #include "ED_keyframing.h"
57
58 #include "UI_interface.h"
59
60 #include "WM_api.h"
61 #include "WM_types.h"
62
63 #include "RNA_access.h"
64 #include "RNA_define.h"
65
66 #include "anim_intern.h"
67
68 /* called by WM */
69 void free_anim_drivers_copybuf(void);
70
71 /* ************************************************** */
72 /* Animation Data Validation */
73
74 /* Get (or add relevant data to be able to do so) F-Curve from the driver stack, 
75  * for the given Animation Data block. This assumes that all the destinations are valid.
76  *      
77  *      - add:  0 - don't add anything if not found, 
78  *                      1 - add new Driver FCurve (with keyframes for visual tweaking),
79  *                      2 - add new Driver FCurve (with generator, for script backwards compatibility)
80  *                      -1 - add new Driver FCurve without driver stuff (for pasting)
81  */
82 FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_index, short add)
83 {
84         AnimData *adt;
85         FCurve *fcu;
86         
87         /* sanity checks */
88         if (ELEM(NULL, id, rna_path))
89                 return NULL;
90         
91         /* init animdata if none available yet */
92         adt = BKE_animdata_from_id(id);
93         if ((adt == NULL) && (add))
94                 adt = BKE_id_add_animdata(id);
95         if (adt == NULL) {
96                 /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
97                 return NULL;
98         }
99                 
100         /* try to find f-curve matching for this setting 
101          *      - add if not found and allowed to add one
102          *              TODO: add auto-grouping support? how this works will need to be resolved
103          */
104         fcu = list_find_fcurve(&adt->drivers, rna_path, array_index);
105         
106         if ((fcu == NULL) && (add)) {
107                 /* use default settings to make a F-Curve */
108                 fcu = MEM_callocN(sizeof(FCurve), "FCurve");
109                 
110                 fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
111                 
112                 /* store path - make copy, and store that */
113                 fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
114                 fcu->array_index = array_index;
115                 
116                 /* if add is negative, don't init this data yet, since it will be filled in by the pasted driver */
117                 if (add > 0) {
118                         BezTriple *bezt;
119                         size_t i;
120                         
121                         /* add some new driver data */
122                         fcu->driver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
123                         fcu->driver->flag |= DRIVER_FLAG_SHOWDEBUG;
124                         
125                         /* F-Modifier or Keyframes? */
126                         // FIXME: replace these magic numbers with defines
127                         if (add == 2) {
128                                 /* Python API Backwards compatibility hack:
129                                  * Create FModifier so that old scripts won't break
130                                  * for now before 2.7 series -- (September 4, 2013)
131                                  */
132                                 add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR);
133                         }
134                         else {
135                                 /* add 2 keyframes so that user has something to work with 
136                                  * - These are configured to 0,0 and 1,1 to give a 1-1 mapping
137                                  *   which can be easily tweaked from there.
138                                  */
139                                 insert_vert_fcurve(fcu, 0.0f, 0.0f, INSERTKEY_FAST);
140                                 insert_vert_fcurve(fcu, 1.0f, 1.0f, INSERTKEY_FAST);
141                                 
142                                 /* configure this curve to extrapolate */
143                                 for (i = 0, bezt = fcu->bezt;  (i < fcu->totvert) && bezt;  i++, bezt++) {
144                                         bezt->h1 = bezt->h2 = HD_VECT;
145                                 }
146                                 
147                                 fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
148                                 calchandles_fcurve(fcu);
149                         }
150                 }
151                 
152                 /* just add F-Curve to end of driver list */
153                 BLI_addtail(&adt->drivers, fcu);
154         }
155         
156         /* return the F-Curve */
157         return fcu;
158 }
159
160 /* ************************************************** */
161 /* Driver Management API */
162
163 /* Main Driver Management API calls:
164  *  Add a new driver for the specified property on the given ID block
165  */
166 short ANIM_add_driver(ReportList *reports, ID *id, const char rna_path[], int array_index, short flag, int type)
167 {       
168         PointerRNA id_ptr, ptr;
169         PropertyRNA *prop;
170         FCurve *fcu;
171         int array_index_max;
172         int done = FALSE;
173         
174         /* validate pointer first - exit if failure */
175         RNA_id_pointer_create(id, &id_ptr);
176         if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) {
177                 BKE_reportf(reports, RPT_ERROR, 
178                             "Could not add driver, as RNA path is invalid for the given ID (ID = %s, path = %s)",
179                             id->name, rna_path);
180                 return 0;
181         }
182         
183         /* key entire array convenience method */
184         if (array_index == -1) {
185                 array_index_max = RNA_property_array_length(&ptr, prop);
186                 array_index = 0;
187         }
188         else
189                 array_index_max = array_index;
190         
191         /* maximum index should be greater than the start index */
192         if (array_index == array_index_max)
193                 array_index_max += 1;
194         
195         /* will only loop once unless the array index was -1 */
196         for (; array_index < array_index_max; array_index++) {
197                 short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1;
198                 
199                 /* create F-Curve with Driver */
200                 fcu = verify_driver_fcurve(id, rna_path, array_index, add_mode);
201                 
202                 if (fcu && fcu->driver) {
203                         ChannelDriver *driver = fcu->driver;
204                         
205                         /* set the type of the driver */
206                         driver->type = type;
207                         
208                         /* creating drivers for buttons will create the driver(s) with type 
209                          * "scripted expression" so that their values won't be lost immediately,
210                          * so here we copy those values over to the driver's expression
211                          */
212                         if (type == DRIVER_TYPE_PYTHON) {
213                                 PropertyType proptype = RNA_property_type(prop);
214                                 int array = RNA_property_array_length(&ptr, prop);
215                                 char *expression = driver->expression;
216                                 int val, maxlen = sizeof(driver->expression);
217                                 float fval;
218                                 
219                                 if (proptype == PROP_BOOLEAN) {
220                                         if (!array) val = RNA_property_boolean_get(&ptr, prop);
221                                         else val = RNA_property_boolean_get_index(&ptr, prop, array_index);
222                                         
223                                         BLI_strncpy(expression, (val) ? "True" : "False", maxlen);
224                                 }
225                                 else if (proptype == PROP_INT) {
226                                         if (!array) val = RNA_property_int_get(&ptr, prop);
227                                         else val = RNA_property_int_get_index(&ptr, prop, array_index);
228                                         
229                                         BLI_snprintf(expression, maxlen, "%d", val);
230                                 }
231                                 else if (proptype == PROP_FLOAT) {
232                                         if (!array) fval = RNA_property_float_get(&ptr, prop);
233                                         else fval = RNA_property_float_get_index(&ptr, prop, array_index);
234                                         
235                                         BLI_snprintf(expression, maxlen, "%.3f", fval);
236                                 }
237                         }
238                         
239                         /* for easier setup of drivers from UI, a driver variable should be 
240                          * added if flag is set (UI calls only)
241                          */
242                         if (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) {
243                                 /* assume that users will mostly want this to be of type "Transform Channel" too,
244                                  * since this allows the easiest setting up of common rig components
245                                  */
246                                 DriverVar *dvar = driver_add_new_variable(driver);
247                                 driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN);
248                         }
249                 }
250                 
251                 /* set the done status */
252                 done += (fcu != NULL);
253         }
254         
255         /* done */
256         return done;
257 }
258
259 /* Main Driver Management API calls:
260  *  Remove the driver for the specified property on the given ID block (if available)
261  */
262 short ANIM_remove_driver(ReportList *UNUSED(reports), ID *id, const char rna_path[], int array_index, short UNUSED(flag))
263 {
264         AnimData *adt;
265         FCurve *fcu;
266         int success = 0;
267         
268         /* we don't check the validity of the path here yet, but it should be ok... */
269         adt = BKE_animdata_from_id(id);
270         
271         if (adt) {
272                 if (array_index == -1) {
273                         /* step through all drivers, removing all of those with the same base path */
274                         FCurve *fcu_iter = adt->drivers.first;
275                         
276                         while ((fcu = iter_step_fcurve(fcu_iter, rna_path)) != NULL) {
277                                 /* store the next fcurve for looping  */
278                                 fcu_iter = fcu->next;
279                                 
280                                 /* remove F-Curve from driver stack, then free it */
281                                 BLI_remlink(&adt->drivers, fcu);
282                                 free_fcurve(fcu);
283                                 
284                                 /* done successfully */
285                                 success |= 1;
286                         }
287                 }
288                 else {
289                         /* find the matching driver and remove it only 
290                          * Note: here is one of the places where we don't want new F-Curve + Driver added!
291                          *      so 'add' var must be 0
292                          */
293                         fcu = verify_driver_fcurve(id, rna_path, array_index, 0);
294                         if (fcu) {
295                                 BLI_remlink(&adt->drivers, fcu);
296                                 free_fcurve(fcu);
297                                 
298                                 success = 1;
299                         }
300                 }
301         }
302
303         return success;
304 }
305
306 /* ************************************************** */
307 /* Driver Management API - Copy/Paste Drivers */
308
309 /* Copy/Paste Buffer for Driver Data... */
310 static FCurve *channeldriver_copypaste_buf = NULL;
311
312 /* This function frees any MEM_calloc'ed copy/paste buffer data */
313 // XXX find some header to put this in!
314 void free_anim_drivers_copybuf(void)
315 {
316         /* free the buffer F-Curve if it exists, as if it were just another F-Curve */
317         if (channeldriver_copypaste_buf)
318                 free_fcurve(channeldriver_copypaste_buf);
319         channeldriver_copypaste_buf = NULL;
320 }
321
322 /* Checks if there is a driver in the copy/paste buffer */
323 short ANIM_driver_can_paste(void)
324 {
325         return (channeldriver_copypaste_buf != NULL);
326 }
327
328 /* ------------------- */
329
330 /* Main Driver Management API calls:
331  *  Make a copy of the driver for the specified property on the given ID block
332  */
333 short ANIM_copy_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_property(&id_ptr, rna_path, &ptr, &prop) == false) {
342                 BKE_reportf(reports, RPT_ERROR,
343                             "Could not find driver to copy, as RNA path is invalid for the given ID (ID = %s, path = %s)",
344                             id->name, rna_path);
345                 return 0;
346         }
347         
348         /* try to get F-Curve with Driver */
349         fcu = verify_driver_fcurve(id, rna_path, array_index, 0);
350         
351         /* clear copy/paste buffer first (for consistency with other copy/paste buffers) */
352         free_anim_drivers_copybuf();
353         
354         /* copy this to the copy/paste buf if it exists */
355         if (fcu && fcu->driver) {
356                 /* make copies of some info such as the rna_path, then clear this info from the F-Curve temporarily
357                  * so that we don't end up wasting memory storing the path which won't get used ever...
358                  */
359                 char *tmp_path = fcu->rna_path;
360                 fcu->rna_path = NULL;
361                 
362                 /* make a copy of the F-Curve with */
363                 channeldriver_copypaste_buf = copy_fcurve(fcu);
364                 
365                 /* restore the path */
366                 fcu->rna_path = tmp_path;
367                 
368                 /* copied... */
369                 return 1;
370         }
371         
372         /* done */
373         return 0;
374 }
375
376 /* Main Driver Management API calls:
377  *  Add a new driver for the specified property on the given ID block or replace an existing one
378  *      with the driver + driver-curve data from the buffer 
379  */
380 short ANIM_paste_driver(ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag))
381 {       
382         PointerRNA id_ptr, ptr;
383         PropertyRNA *prop;
384         FCurve *fcu;
385         
386         /* validate pointer first - exit if failure */
387         RNA_id_pointer_create(id, &id_ptr);
388         if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) {
389                 BKE_reportf(reports, RPT_ERROR,
390                             "Could not paste driver, as RNA path is invalid for the given ID (ID = %s, path = %s)",
391                             id->name, rna_path);
392                 return 0;
393         }
394         
395         /* if the buffer is empty, cannot paste... */
396         if (channeldriver_copypaste_buf == NULL) {
397                 BKE_report(reports, RPT_ERROR, "Paste driver: no driver to paste");
398                 return 0;
399         }
400         
401         /* create Driver F-Curve, but without data which will be copied across... */
402         fcu = verify_driver_fcurve(id, rna_path, array_index, -1);
403
404         if (fcu) {
405                 /* copy across the curve data from the buffer curve 
406                  * NOTE: this step needs care to not miss new settings
407                  */
408                 /* keyframes/samples */
409                 fcu->bezt = MEM_dupallocN(channeldriver_copypaste_buf->bezt);
410                 fcu->fpt = MEM_dupallocN(channeldriver_copypaste_buf->fpt);
411                 fcu->totvert = channeldriver_copypaste_buf->totvert;
412                 
413                 /* modifiers */
414                 copy_fmodifiers(&fcu->modifiers, &channeldriver_copypaste_buf->modifiers);
415                 
416                 /* extrapolation mode */
417                 fcu->extend = channeldriver_copypaste_buf->extend;
418                         
419                 /* the 'juicy' stuff - the driver */
420                 fcu->driver = fcurve_copy_driver(channeldriver_copypaste_buf->driver);
421         }
422         
423         /* done */
424         return (fcu != NULL);
425 }
426
427 /* ************************************************** */
428 /* UI-Button Interface */
429
430 /* Temporary wrapper for driver operators for buttons to make it easier to create
431  * such drivers by rerouting all paths through the active object instead so that
432  * they will get picked up by the dependency system.
433  *
434  * < C: context pointer - for getting active data 
435  * <> ptr: RNA pointer for property's datablock. May be modified as result of path remapping.
436  * < prop: RNA definition of property to add for
437  *
438  * > returns: MEM_alloc'd string representing the path to the property from the given PointerRNA
439  */
440 static char *get_driver_path_hack(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
441 {
442         ID *id = (ID *)ptr->id.data;
443         ScrArea *sa = CTX_wm_area(C);
444         
445         /* get standard path which may be extended */
446         char *basepath = RNA_path_from_ID_to_property(ptr, prop);
447         char *path = basepath; /* in case no remapping is needed */
448         
449         
450         /* Remapping will only be performed in the Properties Editor, as only this 
451          * restricts the subspace of options to the 'active' data (a manageable state)
452          */
453         // TODO: watch out for pinned context?
454         if ((sa) && (sa->spacetype == SPACE_BUTS)) {
455                 Object *ob = CTX_data_active_object(C);
456                 
457                 if (ob && id) {
458                         /* only id-types which can be remapped to go through objects should be considered */
459                         switch (GS(id->name)) {
460                                 case ID_TE: /* textures */
461                                 {
462                                         Material *ma = give_current_material(ob, ob->actcol);
463                                         Tex *tex = give_current_material_texture(ma);
464                                         
465                                         /* assumes: texture will only be shown if it is active material's active texture it's ok */
466                                         if ((ID *)tex == id) {
467                                                 char name_esc_ma[(sizeof(ma->id.name) - 2) * 2];
468                                                 char name_esc_tex[(sizeof(tex->id.name) - 2) * 2];
469
470                                                 BLI_strescape(name_esc_ma, ma->id.name + 2, sizeof(name_esc_ma));
471                                                 BLI_strescape(name_esc_tex, tex->id.name + 2, sizeof(name_esc_tex));
472
473                                                 /* create new path */
474                                                 // TODO: use RNA path functions to construct step by step instead?
475                                                 // FIXME: maybe this isn't even needed anymore...
476                                                 path = BLI_sprintfN("material_slots[\"%s\"].material.texture_slots[\"%s\"].texture.%s", 
477                                                                     name_esc_ma, name_esc_tex, basepath);
478                                                         
479                                                 /* free old one */
480                                                 MEM_freeN(basepath);
481                                         }
482                                         break;
483                                 }
484                         }
485                         
486                         /* fix RNA pointer, as we've now changed the ID root by changing the paths */
487                         if (basepath != path) {
488                                 /* rebase provided pointer so that it starts from object... */
489                                 RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr);
490                         }
491                 }
492         }
493         
494         /* the path should now have been corrected for use */
495         return path;
496 }
497
498 /* Add Driver Button Operator ------------------------ */
499
500 static int add_driver_button_exec(bContext *C, wmOperator *op)
501 {
502         PointerRNA ptr = {{NULL}};
503         PropertyRNA *prop = NULL;
504         short success = 0;
505         int index, all = RNA_boolean_get(op->ptr, "all");
506         
507         /* try to create driver using property retrieved from UI */
508         uiContextActiveProperty(C, &ptr, &prop, &index);
509         
510         if (all)
511                 index = -1;
512         
513         if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
514                 char *path = get_driver_path_hack(C, &ptr, prop);
515                 short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
516                 
517                 if (path) {
518                         success += ANIM_add_driver(op->reports, ptr.id.data, path, index, flags, DRIVER_TYPE_PYTHON);
519                         
520                         MEM_freeN(path);
521                 }
522         }
523         
524         if (success) {
525                 /* send updates */
526                 uiContextAnimUpdate(C);
527                 
528                 WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
529         }
530         
531         return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
532 }
533
534 void ANIM_OT_driver_button_add(wmOperatorType *ot)
535 {
536         /* identifiers */
537         ot->name = "Add Driver";
538         ot->idname = "ANIM_OT_driver_button_add";
539         ot->description = "Add driver(s) for the property(s) connected represented by the highlighted button";
540         
541         /* callbacks */
542         ot->exec = add_driver_button_exec; 
543         //op->poll = ??? // TODO: need to have some animatable property to do this
544         
545         /* flags */
546         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
547
548         /* properties */
549         RNA_def_boolean(ot->srna, "all", 1, "All", "Create drivers for all elements of the array");
550 }
551
552 /* Remove Driver Button Operator ------------------------ */
553
554 static int remove_driver_button_exec(bContext *C, wmOperator *op)
555 {
556         PointerRNA ptr = {{NULL}};
557         PropertyRNA *prop = NULL;
558         short success = 0;
559         int index, all = RNA_boolean_get(op->ptr, "all");
560         
561         /* try to find driver using property retrieved from UI */
562         uiContextActiveProperty(C, &ptr, &prop, &index);
563         
564         if (all)
565                 index = -1;
566         
567         if (ptr.id.data && ptr.data && prop) {
568                 char *path = get_driver_path_hack(C, &ptr, prop);
569                 
570                 success = ANIM_remove_driver(op->reports, ptr.id.data, path, index, 0);
571                 MEM_freeN(path);
572         }
573         
574         if (success) {
575                 /* send updates */
576                 uiContextAnimUpdate(C);
577                 
578                 WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL);  // XXX
579         }
580         
581         return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
582 }
583
584 void ANIM_OT_driver_button_remove(wmOperatorType *ot)
585 {
586         /* identifiers */
587         ot->name = "Remove Driver";
588         ot->idname = "ANIM_OT_driver_button_remove";
589         ot->description = "Remove the driver(s) for the property(s) connected represented by the highlighted button";
590         
591         /* callbacks */
592         ot->exec = remove_driver_button_exec; 
593         //op->poll = ??? // TODO: need to have some driver to be able to do this...
594         
595         /* flags */
596         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
597
598         /* properties */
599         RNA_def_boolean(ot->srna, "all", 1, "All", "Delete drivers for all elements of the array");
600 }
601
602 /* Copy Driver Button Operator ------------------------ */
603
604 static int copy_driver_button_exec(bContext *C, wmOperator *op)
605 {
606         PointerRNA ptr = {{NULL}};
607         PropertyRNA *prop = NULL;
608         short success = 0;
609         int index;
610         
611         /* try to create driver using property retrieved from UI */
612         uiContextActiveProperty(C, &ptr, &prop, &index);
613         
614         if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
615                 char *path = get_driver_path_hack(C, &ptr, prop);
616                 
617                 if (path) {
618                         /* only copy the driver for the button that this was involved for */
619                         success = ANIM_copy_driver(op->reports, ptr.id.data, path, index, 0);
620                         
621                         uiContextAnimUpdate(C);
622                         
623                         MEM_freeN(path);
624                 }
625         }
626         
627         /* since we're just copying, we don't really need to do anything else...*/
628         return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
629 }
630
631 void ANIM_OT_copy_driver_button(wmOperatorType *ot)
632 {
633         /* identifiers */
634         ot->name = "Copy Driver";
635         ot->idname = "ANIM_OT_copy_driver_button";
636         ot->description = "Copy the driver for the highlighted button";
637         
638         /* callbacks */
639         ot->exec = copy_driver_button_exec; 
640         //op->poll = ??? // TODO: need to have some driver to be able to do this...
641         
642         /* flags */
643         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
644 }
645
646 /* Paste Driver Button Operator ------------------------ */
647
648 static int paste_driver_button_exec(bContext *C, wmOperator *op)
649 {
650         PointerRNA ptr = {{NULL}};
651         PropertyRNA *prop = NULL;
652         short success = 0;
653         int index;
654         
655         /* try to create driver using property retrieved from UI */
656         uiContextActiveProperty(C, &ptr, &prop, &index);
657         
658         if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
659                 char *path = get_driver_path_hack(C, &ptr, prop);
660                 
661                 if (path) {
662                         /* only copy the driver for the button that this was involved for */
663                         success = ANIM_paste_driver(op->reports, ptr.id.data, path, index, 0);
664                         
665                         uiContextAnimUpdate(C);
666                         
667                         MEM_freeN(path);
668                 }
669         }
670         
671         /* since we're just copying, we don't really need to do anything else...*/
672         return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
673 }
674
675 void ANIM_OT_paste_driver_button(wmOperatorType *ot)
676 {
677         /* identifiers */
678         ot->name = "Paste Driver";
679         ot->idname = "ANIM_OT_paste_driver_button";
680         ot->description = "Paste the driver in the copy/paste buffer for the highlighted button";
681         
682         /* callbacks */
683         ot->exec = paste_driver_button_exec; 
684         //op->poll = ??? // TODO: need to have some driver to be able to do this...
685         
686         /* flags */
687         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
688 }
689
690 /* ************************************************** */