1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup edanimation
22  */
23 
24 #include <ctype.h>
25 #include <stdio.h>
26 #include <string.h>
27 
28 #include "MEM_guardedalloc.h"
29 
30 #include "BLI_blenlib.h"
31 #include "BLI_string.h"
32 #include "BLI_utildefines.h"
33 
34 #include "DNA_anim_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_space_types.h"
37 #include "DNA_texture_types.h"
38 
39 #include "BKE_anim_data.h"
40 #include "BKE_animsys.h"
41 #include "BKE_context.h"
42 #include "BKE_fcurve.h"
43 #include "BKE_fcurve_driver.h"
44 #include "BKE_report.h"
45 
46 #include "DEG_depsgraph.h"
47 #include "DEG_depsgraph_build.h"
48 
49 #include "ED_keyframing.h"
50 
51 #include "UI_interface.h"
52 #include "UI_resources.h"
53 
54 #include "WM_api.h"
55 #include "WM_types.h"
56 
57 #include "RNA_access.h"
58 #include "RNA_define.h"
59 
60 #include "anim_intern.h"
61 
62 /* ************************************************** */
63 /* Animation Data Validation */
64 
65 /* Get (or add relevant data to be able to do so) F-Curve from the driver stack,
66  * for the given Animation Data block. This assumes that all the destinations are valid.
67  */
verify_driver_fcurve(ID * id,const char rna_path[],const int array_index,eDriverFCurveCreationMode creation_mode)68 FCurve *verify_driver_fcurve(ID *id,
69                              const char rna_path[],
70                              const int array_index,
71                              eDriverFCurveCreationMode creation_mode)
72 {
73   AnimData *adt;
74   FCurve *fcu;
75 
76   /* sanity checks */
77   if (ELEM(NULL, id, rna_path)) {
78     return NULL;
79   }
80 
81   /* init animdata if none available yet */
82   adt = BKE_animdata_from_id(id);
83   if (adt == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) {
84     adt = BKE_animdata_add_id(id);
85   }
86   if (adt == NULL) {
87     /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
88     return NULL;
89   }
90 
91   /* try to find f-curve matching for this setting
92    * - add if not found and allowed to add one
93    * TODO: add auto-grouping support? how this works will need to be resolved
94    */
95   fcu = BKE_fcurve_find(&adt->drivers, rna_path, array_index);
96 
97   if (fcu == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) {
98     /* use default settings to make a F-Curve */
99     fcu = alloc_driver_fcurve(rna_path, array_index, creation_mode);
100 
101     /* just add F-Curve to end of driver list */
102     BLI_addtail(&adt->drivers, fcu);
103   }
104 
105   /* return the F-Curve */
106   return fcu;
107 }
108 
alloc_driver_fcurve(const char rna_path[],const int array_index,eDriverFCurveCreationMode creation_mode)109 struct FCurve *alloc_driver_fcurve(const char rna_path[],
110                                    const int array_index,
111                                    eDriverFCurveCreationMode creation_mode)
112 {
113   FCurve *fcu = BKE_fcurve_create();
114 
115   fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
116   fcu->auto_smoothing = U.auto_smoothing_new;
117 
118   /* store path - make copy, and store that */
119   if (rna_path) {
120     fcu->rna_path = BLI_strdup(rna_path);
121   }
122   fcu->array_index = array_index;
123 
124   if (!ELEM(creation_mode, DRIVER_FCURVE_LOOKUP_ONLY, DRIVER_FCURVE_EMPTY)) {
125     /* add some new driver data */
126     fcu->driver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
127 
128     /* F-Modifier or Keyframes? */
129     if (creation_mode == DRIVER_FCURVE_GENERATOR) {
130       /* Python API Backwards compatibility hack:
131        * Create FModifier so that old scripts won't break
132        * for now before 2.7 series -- (September 4, 2013)
133        */
134       add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR, fcu);
135     }
136     else {
137       /* add 2 keyframes so that user has something to work with
138        * - These are configured to 0,0 and 1,1 to give a 1-1 mapping
139        *   which can be easily tweaked from there.
140        */
141       insert_vert_fcurve(
142           fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST | INSERTKEY_NO_USERPREF);
143       insert_vert_fcurve(
144           fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST | INSERTKEY_NO_USERPREF);
145       fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
146       calchandles_fcurve(fcu);
147     }
148   }
149 
150   return fcu;
151 }
152 
153 /* ************************************************** */
154 /* Driver Management API */
155 
156 /* Helper for ANIM_add_driver_with_target - Adds the actual driver */
add_driver_with_target(ReportList * UNUSED (reports),ID * dst_id,const char dst_path[],int dst_index,ID * src_id,const char src_path[],int src_index,PointerRNA * dst_ptr,PropertyRNA * dst_prop,PointerRNA * src_ptr,PropertyRNA * src_prop,short flag,int driver_type)157 static int add_driver_with_target(ReportList *UNUSED(reports),
158                                   ID *dst_id,
159                                   const char dst_path[],
160                                   int dst_index,
161                                   ID *src_id,
162                                   const char src_path[],
163                                   int src_index,
164                                   PointerRNA *dst_ptr,
165                                   PropertyRNA *dst_prop,
166                                   PointerRNA *src_ptr,
167                                   PropertyRNA *src_prop,
168                                   short flag,
169                                   int driver_type)
170 {
171   FCurve *fcu;
172   short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? DRIVER_FCURVE_GENERATOR :
173                                                           DRIVER_FCURVE_KEYFRAMES;
174   const char *prop_name = RNA_property_identifier(src_prop);
175 
176   /* Create F-Curve with Driver */
177   fcu = verify_driver_fcurve(dst_id, dst_path, dst_index, add_mode);
178 
179   if (fcu && fcu->driver) {
180     ChannelDriver *driver = fcu->driver;
181     DriverVar *dvar;
182 
183     /* Set the type of the driver */
184     driver->type = driver_type;
185 
186     /* Set driver expression, so that the driver works out of the box
187      *
188      * The following checks define a bit of "auto-detection magic" we use
189      * to ensure that the drivers will behave as expected out of the box
190      * when faced with properties with different units.
191      */
192     /* XXX: if we have N-1 mapping, should we include all those in the expression? */
193     if ((RNA_property_unit(dst_prop) == PROP_UNIT_ROTATION) &&
194         (RNA_property_unit(src_prop) != PROP_UNIT_ROTATION)) {
195       /* Rotation Destination:  normal -> radians,  so convert src to radians
196        * (However, if both input and output is a rotation, don't apply such corrections)
197        */
198       BLI_strncpy(driver->expression, "radians(var)", sizeof(driver->expression));
199     }
200     else if ((RNA_property_unit(src_prop) == PROP_UNIT_ROTATION) &&
201              (RNA_property_unit(dst_prop) != PROP_UNIT_ROTATION)) {
202       /* Rotation Source:  radians -> normal,  so convert src to degrees
203        * (However, if both input and output is a rotation, don't apply such corrections)
204        */
205       BLI_strncpy(driver->expression, "degrees(var)", sizeof(driver->expression));
206     }
207     else {
208       /* Just a normal property without any unit problems */
209       BLI_strncpy(driver->expression, "var", sizeof(driver->expression));
210     }
211 
212     /* Create a driver variable for the target
213      *   - For transform properties, we want to automatically use "transform channel" instead
214      *     (The only issue is with quaternion rotations vs euler channels...)
215      *   - To avoid problems with transform properties depending on the final transform that they
216      *     control (thus creating pseudo-cycles - see T48734), we don't use transform channels
217      *     when both the source and destinations are in same places.
218      */
219     dvar = driver_add_new_variable(driver);
220 
221     if (ELEM(src_ptr->type, &RNA_Object, &RNA_PoseBone) &&
222         (STREQ(prop_name, "location") || STREQ(prop_name, "scale") ||
223          STRPREFIX(prop_name, "rotation_")) &&
224         (src_ptr->data != dst_ptr->data)) {
225       /* Transform Channel */
226       DriverTarget *dtar;
227 
228       driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN);
229       dtar = &dvar->targets[0];
230 
231       /* Bone or Object target? */
232       dtar->id = src_id;
233       dtar->idtype = GS(src_id->name);
234 
235       if (src_ptr->type == &RNA_PoseBone) {
236         RNA_string_get(src_ptr, "name", dtar->pchan_name);
237       }
238 
239       /* Transform channel depends on type */
240       if (STREQ(prop_name, "location")) {
241         if (src_index == 2) {
242           dtar->transChan = DTAR_TRANSCHAN_LOCZ;
243         }
244         else if (src_index == 1) {
245           dtar->transChan = DTAR_TRANSCHAN_LOCY;
246         }
247         else {
248           dtar->transChan = DTAR_TRANSCHAN_LOCX;
249         }
250       }
251       else if (STREQ(prop_name, "scale")) {
252         if (src_index == 2) {
253           dtar->transChan = DTAR_TRANSCHAN_SCALEZ;
254         }
255         else if (src_index == 1) {
256           dtar->transChan = DTAR_TRANSCHAN_SCALEY;
257         }
258         else {
259           dtar->transChan = DTAR_TRANSCHAN_SCALEX;
260         }
261       }
262       else {
263         /* XXX: With quaternions and axis-angle, this mapping might not be correct...
264          *      But since those have 4 elements instead, there's not much we can do
265          */
266         if (src_index == 2) {
267           dtar->transChan = DTAR_TRANSCHAN_ROTZ;
268         }
269         else if (src_index == 1) {
270           dtar->transChan = DTAR_TRANSCHAN_ROTY;
271         }
272         else {
273           dtar->transChan = DTAR_TRANSCHAN_ROTX;
274         }
275       }
276     }
277     else {
278       /* Single RNA Property */
279       DriverTarget *dtar = &dvar->targets[0];
280 
281       /* ID is as-is */
282       dtar->id = src_id;
283       dtar->idtype = GS(src_id->name);
284 
285       /* Need to make a copy of the path (or build one with array index built in) */
286       if (RNA_property_array_check(src_prop)) {
287         dtar->rna_path = BLI_sprintfN("%s[%d]", src_path, src_index);
288       }
289       else {
290         dtar->rna_path = BLI_strdup(src_path);
291       }
292     }
293   }
294 
295   /* set the done status */
296   return (fcu != NULL);
297 }
298 
299 /* Main Driver Management API calls:
300  * Add a new driver for the specified property on the given ID block,
301  * and make it be driven by the specified target.
302  *
303  * This is intended to be used in conjunction with a modal "eyedropper"
304  * for picking the variable that is going to be used to drive this one.
305  *
306  * - flag: eCreateDriverFlags
307  * - driver_type: eDriver_Types
308  * - mapping_type: eCreateDriver_MappingTypes
309  */
ANIM_add_driver_with_target(ReportList * reports,ID * dst_id,const char dst_path[],int dst_index,ID * src_id,const char src_path[],int src_index,short flag,int driver_type,short mapping_type)310 int ANIM_add_driver_with_target(ReportList *reports,
311                                 ID *dst_id,
312                                 const char dst_path[],
313                                 int dst_index,
314                                 ID *src_id,
315                                 const char src_path[],
316                                 int src_index,
317                                 short flag,
318                                 int driver_type,
319                                 short mapping_type)
320 {
321   PointerRNA id_ptr, ptr;
322   PropertyRNA *prop;
323 
324   PointerRNA id_ptr2, ptr2;
325   PropertyRNA *prop2;
326   int done_tot = 0;
327 
328   /* validate pointers first - exit if failure */
329   RNA_id_pointer_create(dst_id, &id_ptr);
330   if (RNA_path_resolve_property(&id_ptr, dst_path, &ptr, &prop) == false) {
331     BKE_reportf(
332         reports,
333         RPT_ERROR,
334         "Could not add driver, as RNA path is invalid for the given ID (ID = %s, path = %s)",
335         dst_id->name,
336         dst_path);
337     return 0;
338   }
339 
340   RNA_id_pointer_create(src_id, &id_ptr2);
341   if ((RNA_path_resolve_property(&id_ptr2, src_path, &ptr2, &prop2) == false) ||
342       (mapping_type == CREATEDRIVER_MAPPING_NONE)) {
343     /* No target - So, fall back to default method for adding a "simple" driver normally */
344     return ANIM_add_driver(
345         reports, dst_id, dst_path, dst_index, flag | CREATEDRIVER_WITH_DEFAULT_DVAR, driver_type);
346   }
347 
348   /* handle curve-property mappings based on mapping_type */
349   switch (mapping_type) {
350     case CREATEDRIVER_MAPPING_N_N: /* N-N - Try to match as much as possible,
351                                     * then use the first one */
352     {
353       /* Use the shorter of the two (to avoid out of bounds access) */
354       int dst_len = (RNA_property_array_check(prop)) ? RNA_property_array_length(&ptr, prop) : 1;
355       int src_len = (RNA_property_array_check(prop)) ? RNA_property_array_length(&ptr2, prop2) : 1;
356 
357       int len = MIN2(dst_len, src_len);
358 
359       for (int i = 0; i < len; i++) {
360         done_tot += add_driver_with_target(reports,
361                                            dst_id,
362                                            dst_path,
363                                            i,
364                                            src_id,
365                                            src_path,
366                                            i,
367                                            &ptr,
368                                            prop,
369                                            &ptr2,
370                                            prop2,
371                                            flag,
372                                            driver_type);
373       }
374       break;
375     }
376 
377     case CREATEDRIVER_MAPPING_1_N: /* 1-N - Specified target index for all */
378     default: {
379       int len = (RNA_property_array_check(prop)) ? RNA_property_array_length(&ptr, prop) : 1;
380 
381       for (int i = 0; i < len; i++) {
382         done_tot += add_driver_with_target(reports,
383                                            dst_id,
384                                            dst_path,
385                                            i,
386                                            src_id,
387                                            src_path,
388                                            src_index,
389                                            &ptr,
390                                            prop,
391                                            &ptr2,
392                                            prop2,
393                                            flag,
394                                            driver_type);
395       }
396       break;
397     }
398 
399     case CREATEDRIVER_MAPPING_1_1: /* 1-1 - Use the specified index (unless -1) */
400     {
401       done_tot = add_driver_with_target(reports,
402                                         dst_id,
403                                         dst_path,
404                                         dst_index,
405                                         src_id,
406                                         src_path,
407                                         src_index,
408                                         &ptr,
409                                         prop,
410                                         &ptr2,
411                                         prop2,
412                                         flag,
413                                         driver_type);
414       break;
415     }
416   }
417 
418   /* done */
419   return done_tot;
420 }
421 
422 /* --------------------------------- */
423 
424 /**
425  * Main Driver Management API calls:
426  * Add a new driver for the specified property on the given ID block
427  */
ANIM_add_driver(ReportList * reports,ID * id,const char rna_path[],int array_index,short flag,int type)428 int ANIM_add_driver(
429     ReportList *reports, ID *id, const char rna_path[], int array_index, short flag, int type)
430 {
431   PointerRNA id_ptr, ptr;
432   PropertyRNA *prop;
433   FCurve *fcu;
434   int array_index_max;
435   int done_tot = 0;
436 
437   /* validate pointer first - exit if failure */
438   RNA_id_pointer_create(id, &id_ptr);
439   if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) {
440     BKE_reportf(
441         reports,
442         RPT_ERROR,
443         "Could not add driver, as RNA path is invalid for the given ID (ID = %s, path = %s)",
444         id->name,
445         rna_path);
446     return 0;
447   }
448 
449   /* key entire array convenience method */
450   if (array_index == -1) {
451     array_index_max = RNA_property_array_length(&ptr, prop);
452     array_index = 0;
453   }
454   else {
455     array_index_max = array_index;
456   }
457 
458   /* maximum index should be greater than the start index */
459   if (array_index == array_index_max) {
460     array_index_max += 1;
461   }
462 
463   /* will only loop once unless the array index was -1 */
464   for (; array_index < array_index_max; array_index++) {
465     short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1;
466 
467     /* create F-Curve with Driver */
468     fcu = verify_driver_fcurve(id, rna_path, array_index, add_mode);
469 
470     if (fcu && fcu->driver) {
471       ChannelDriver *driver = fcu->driver;
472 
473       /* set the type of the driver */
474       driver->type = type;
475 
476       /* Creating drivers for buttons will create the driver(s) with type
477        * "scripted expression" so that their values won't be lost immediately,
478        * so here we copy those values over to the driver's expression
479        *
480        * If the "default dvar" option (for easier UI setup of drivers) is provided,
481        * include "var" in the expressions too, so that the user doesn't have to edit
482        * it to get something to happen. It should be fine to just add it to the default
483        * value, so that we get both in the expression, even if it's a bit more confusing
484        * that way...
485        */
486       if (type == DRIVER_TYPE_PYTHON) {
487         PropertyType proptype = RNA_property_type(prop);
488         int array = RNA_property_array_length(&ptr, prop);
489         const char *dvar_prefix = (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) ? "var + " : "";
490         char *expression = driver->expression;
491         int val, maxlen = sizeof(driver->expression);
492         float fval;
493 
494         if (proptype == PROP_BOOLEAN) {
495           if (!array) {
496             val = RNA_property_boolean_get(&ptr, prop);
497           }
498           else {
499             val = RNA_property_boolean_get_index(&ptr, prop, array_index);
500           }
501 
502           BLI_snprintf(expression, maxlen, "%s%s", dvar_prefix, (val) ? "True" : "False");
503         }
504         else if (proptype == PROP_INT) {
505           if (!array) {
506             val = RNA_property_int_get(&ptr, prop);
507           }
508           else {
509             val = RNA_property_int_get_index(&ptr, prop, array_index);
510           }
511 
512           BLI_snprintf(expression, maxlen, "%s%d", dvar_prefix, val);
513         }
514         else if (proptype == PROP_FLOAT) {
515           if (!array) {
516             fval = RNA_property_float_get(&ptr, prop);
517           }
518           else {
519             fval = RNA_property_float_get_index(&ptr, prop, array_index);
520           }
521 
522           BLI_snprintf(expression, maxlen, "%s%.3f", dvar_prefix, fval);
523           BLI_str_rstrip_float_zero(expression, '\0');
524         }
525         else if (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) {
526           BLI_strncpy(expression, "var", maxlen);
527         }
528       }
529 
530       /* for easier setup of drivers from UI, a driver variable should be
531        * added if flag is set (UI calls only)
532        */
533       if (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) {
534         /* assume that users will mostly want this to be of type "Transform Channel" too,
535          * since this allows the easiest setting up of common rig components
536          */
537         DriverVar *dvar = driver_add_new_variable(driver);
538         driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN);
539       }
540     }
541 
542     /* set the done status */
543     done_tot += (fcu != NULL);
544   }
545 
546   /* done */
547   return done_tot;
548 }
549 
550 /* Main Driver Management API calls:
551  * Remove the driver for the specified property on the given ID block (if available)
552  */
ANIM_remove_driver(ReportList * UNUSED (reports),ID * id,const char rna_path[],int array_index,short UNUSED (flag))553 bool ANIM_remove_driver(ReportList *UNUSED(reports),
554                         ID *id,
555                         const char rna_path[],
556                         int array_index,
557                         short UNUSED(flag))
558 {
559   AnimData *adt;
560   FCurve *fcu;
561   bool success = false;
562 
563   /* we don't check the validity of the path here yet, but it should be ok... */
564   adt = BKE_animdata_from_id(id);
565 
566   if (adt) {
567     if (array_index == -1) {
568       /* step through all drivers, removing all of those with the same base path */
569       FCurve *fcu_iter = adt->drivers.first;
570 
571       while ((fcu = BKE_fcurve_iter_step(fcu_iter, rna_path)) != NULL) {
572         /* store the next fcurve for looping  */
573         fcu_iter = fcu->next;
574 
575         /* remove F-Curve from driver stack, then free it */
576         BLI_remlink(&adt->drivers, fcu);
577         BKE_fcurve_free(fcu);
578 
579         /* done successfully */
580         success = true;
581       }
582     }
583     else {
584       /* find the matching driver and remove it only
585        * Note: here is one of the places where we don't want new F-Curve + Driver added!
586        *      so 'add' var must be 0
587        */
588       fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_LOOKUP_ONLY);
589       if (fcu) {
590         BLI_remlink(&adt->drivers, fcu);
591         BKE_fcurve_free(fcu);
592 
593         success = true;
594       }
595     }
596   }
597 
598   return success;
599 }
600 
601 /* ************************************************** */
602 /* Driver Management API - Copy/Paste Drivers */
603 
604 /* Copy/Paste Buffer for Driver Data... */
605 static FCurve *channeldriver_copypaste_buf = NULL;
606 
607 /* This function frees any MEM_calloc'ed copy/paste buffer data */
ANIM_drivers_copybuf_free(void)608 void ANIM_drivers_copybuf_free(void)
609 {
610   /* free the buffer F-Curve if it exists, as if it were just another F-Curve */
611   if (channeldriver_copypaste_buf) {
612     BKE_fcurve_free(channeldriver_copypaste_buf);
613   }
614   channeldriver_copypaste_buf = NULL;
615 }
616 
617 /* Checks if there is a driver in the copy/paste buffer */
ANIM_driver_can_paste(void)618 bool ANIM_driver_can_paste(void)
619 {
620   return (channeldriver_copypaste_buf != NULL);
621 }
622 
623 /* ------------------- */
624 
625 /* Main Driver Management API calls:
626  *  Make a copy of the driver for the specified property on the given ID block
627  */
ANIM_copy_driver(ReportList * reports,ID * id,const char rna_path[],int array_index,short UNUSED (flag))628 bool ANIM_copy_driver(
629     ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag))
630 {
631   PointerRNA id_ptr, ptr;
632   PropertyRNA *prop;
633   FCurve *fcu;
634 
635   /* validate pointer first - exit if failure */
636   RNA_id_pointer_create(id, &id_ptr);
637   if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) {
638     BKE_reportf(reports,
639                 RPT_ERROR,
640                 "Could not find driver to copy, as RNA path is invalid for the given ID (ID = %s, "
641                 "path = %s)",
642                 id->name,
643                 rna_path);
644     return 0;
645   }
646 
647   /* try to get F-Curve with Driver */
648   fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_LOOKUP_ONLY);
649 
650   /* clear copy/paste buffer first (for consistency with other copy/paste buffers) */
651   ANIM_drivers_copybuf_free();
652 
653   /* copy this to the copy/paste buf if it exists */
654   if (fcu && fcu->driver) {
655     /* Make copies of some info such as the rna_path, then clear this info from the
656      * F-Curve temporarily so that we don't end up wasting memory storing the path
657      * which won't get used ever.
658      */
659     char *tmp_path = fcu->rna_path;
660     fcu->rna_path = NULL;
661 
662     /* make a copy of the F-Curve with */
663     channeldriver_copypaste_buf = BKE_fcurve_copy(fcu);
664 
665     /* restore the path */
666     fcu->rna_path = tmp_path;
667 
668     /* copied... */
669     return 1;
670   }
671 
672   /* done */
673   return 0;
674 }
675 
676 /* Main Driver Management API calls:
677  * Add a new driver for the specified property on the given ID block or replace an existing one
678  * with the driver + driver-curve data from the buffer
679  */
ANIM_paste_driver(ReportList * reports,ID * id,const char rna_path[],int array_index,short UNUSED (flag))680 bool ANIM_paste_driver(
681     ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag))
682 {
683   PointerRNA id_ptr, ptr;
684   PropertyRNA *prop;
685   FCurve *fcu;
686 
687   /* validate pointer first - exit if failure */
688   RNA_id_pointer_create(id, &id_ptr);
689   if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) {
690     BKE_reportf(
691         reports,
692         RPT_ERROR,
693         "Could not paste driver, as RNA path is invalid for the given ID (ID = %s, path = %s)",
694         id->name,
695         rna_path);
696     return 0;
697   }
698 
699   /* if the buffer is empty, cannot paste... */
700   if (channeldriver_copypaste_buf == NULL) {
701     BKE_report(reports, RPT_ERROR, "Paste driver: no driver to paste");
702     return 0;
703   }
704 
705   /* create Driver F-Curve, but without data which will be copied across... */
706   fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_EMPTY);
707 
708   if (fcu) {
709     /* copy across the curve data from the buffer curve
710      * NOTE: this step needs care to not miss new settings
711      */
712     /* keyframes/samples */
713     fcu->bezt = MEM_dupallocN(channeldriver_copypaste_buf->bezt);
714     fcu->fpt = MEM_dupallocN(channeldriver_copypaste_buf->fpt);
715     fcu->totvert = channeldriver_copypaste_buf->totvert;
716 
717     /* modifiers */
718     copy_fmodifiers(&fcu->modifiers, &channeldriver_copypaste_buf->modifiers);
719 
720     /* extrapolation mode */
721     fcu->extend = channeldriver_copypaste_buf->extend;
722 
723     /* the 'juicy' stuff - the driver */
724     fcu->driver = fcurve_copy_driver(channeldriver_copypaste_buf->driver);
725   }
726 
727   /* done */
728   return (fcu != NULL);
729 }
730 
731 /* ************************************************** */
732 /* Driver Management API - Copy/Paste Driver Variables */
733 
734 /* Copy/Paste Buffer for Driver Variables... */
735 static ListBase driver_vars_copybuf = {NULL, NULL};
736 
737 /* This function frees any MEM_calloc'ed copy/paste buffer data */
ANIM_driver_vars_copybuf_free(void)738 void ANIM_driver_vars_copybuf_free(void)
739 {
740   /* Free the driver variables kept in the buffer */
741   if (driver_vars_copybuf.first) {
742     DriverVar *dvar, *dvarn;
743 
744     /* Free variables (and any data they use) */
745     for (dvar = driver_vars_copybuf.first; dvar; dvar = dvarn) {
746       dvarn = dvar->next;
747       driver_free_variable(&driver_vars_copybuf, dvar);
748     }
749   }
750 
751   BLI_listbase_clear(&driver_vars_copybuf);
752 }
753 
754 /* Checks if there are driver variables in the copy/paste buffer */
ANIM_driver_vars_can_paste(void)755 bool ANIM_driver_vars_can_paste(void)
756 {
757   return (BLI_listbase_is_empty(&driver_vars_copybuf) == false);
758 }
759 
760 /* -------------------------------------------------- */
761 
762 /* Copy the given driver's variables to the buffer */
ANIM_driver_vars_copy(ReportList * reports,FCurve * fcu)763 bool ANIM_driver_vars_copy(ReportList *reports, FCurve *fcu)
764 {
765   /* sanity checks */
766   if (ELEM(NULL, fcu, fcu->driver)) {
767     BKE_report(reports, RPT_ERROR, "No driver to copy variables from");
768     return false;
769   }
770 
771   if (BLI_listbase_is_empty(&fcu->driver->variables)) {
772     BKE_report(reports, RPT_ERROR, "Driver has no variables to copy");
773     return false;
774   }
775 
776   /* clear buffer */
777   ANIM_driver_vars_copybuf_free();
778 
779   /* copy over the variables */
780   driver_variables_copy(&driver_vars_copybuf, &fcu->driver->variables);
781 
782   return (BLI_listbase_is_empty(&driver_vars_copybuf) == false);
783 }
784 
785 /* Paste the variables in the buffer to the given FCurve */
ANIM_driver_vars_paste(ReportList * reports,FCurve * fcu,bool replace)786 bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
787 {
788   ChannelDriver *driver = (fcu) ? fcu->driver : NULL;
789   ListBase tmp_list = {NULL, NULL};
790 
791   /* sanity checks */
792   if (BLI_listbase_is_empty(&driver_vars_copybuf)) {
793     BKE_report(reports, RPT_ERROR, "No driver variables in clipboard to paste");
794     return false;
795   }
796 
797   if (ELEM(NULL, fcu, fcu->driver)) {
798     BKE_report(reports, RPT_ERROR, "Cannot paste driver variables without a driver");
799     return false;
800   }
801 
802   /* 1) Make a new copy of the variables in the buffer - these will get pasted later... */
803   driver_variables_copy(&tmp_list, &driver_vars_copybuf);
804 
805   /* 2) Prepare destination array */
806   if (replace) {
807     DriverVar *dvar, *dvarn;
808 
809     /* Free all existing vars first - We aren't retaining anything */
810     for (dvar = driver->variables.first; dvar; dvar = dvarn) {
811       dvarn = dvar->next;
812       driver_free_variable_ex(driver, dvar);
813     }
814 
815     BLI_listbase_clear(&driver->variables);
816   }
817 
818   /* 3) Add new vars */
819   if (driver->variables.last) {
820     DriverVar *last = driver->variables.last;
821     DriverVar *first = tmp_list.first;
822 
823     last->next = first;
824     first->prev = last;
825 
826     driver->variables.last = tmp_list.last;
827   }
828   else {
829     driver->variables.first = tmp_list.first;
830     driver->variables.last = tmp_list.last;
831   }
832 
833   /* since driver variables are cached, the expression needs re-compiling too */
834   BKE_driver_invalidate_expression(driver, false, true);
835 
836   return true;
837 }
838 
839 /* -------------------------------------------------- */
840 
841 /* Create a driver & variable that reads the specified property,
842  * and store it in the buffers for Paste Driver and Paste Variables. */
ANIM_copy_as_driver(struct ID * target_id,const char * target_path,const char * var_name)843 void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const char *var_name)
844 {
845   /* Clear copy/paste buffer first (for consistency with other copy/paste buffers). */
846   ANIM_drivers_copybuf_free();
847   ANIM_driver_vars_copybuf_free();
848 
849   /* Create a dummy driver F-Curve. */
850   FCurve *fcu = alloc_driver_fcurve(NULL, 0, DRIVER_FCURVE_KEYFRAMES);
851   ChannelDriver *driver = fcu->driver;
852 
853   /* Create a variable. */
854   DriverVar *var = driver_add_new_variable(driver);
855   DriverTarget *target = &var->targets[0];
856 
857   target->idtype = GS(target_id->name);
858   target->id = target_id;
859   target->rna_path = MEM_dupallocN(target_path);
860 
861   /* Set the variable name. */
862   if (var_name) {
863     BLI_strncpy(var->name, var_name, sizeof(var->name));
864 
865     /* Sanitize the name. */
866     for (int i = 0; var->name[i]; i++) {
867       if (!(i > 0 ? isalnum(var->name[i]) : isalpha(var->name[i]))) {
868         var->name[i] = '_';
869       }
870     }
871   }
872 
873   BLI_strncpy(driver->expression, var->name, sizeof(driver->expression));
874 
875   /* Store the driver into the copy/paste buffers. */
876   channeldriver_copypaste_buf = fcu;
877 
878   driver_variables_copy(&driver_vars_copybuf, &driver->variables);
879 }
880 
881 /* ************************************************** */
882 /* UI-Button Interface */
883 
884 /* Add Driver - Enum Defines ------------------------- */
885 
886 /**
887  * Mapping Types enum for operators.
888  * \note Used by #ANIM_OT_driver_button_add and #UI_OT_eyedropper_driver.
889  *
890  * XXX: These names need reviewing.
891  */
892 EnumPropertyItem prop_driver_create_mapping_types[] = {
893     {CREATEDRIVER_MAPPING_1_N,
894      "SINGLE_MANY",
895      0,
896      "All from Target",
897      "Drive all components of this property using the target picked"},
898     {CREATEDRIVER_MAPPING_1_1,
899      "DIRECT",
900      0,
901      "Single from Target",
902      "Drive this component of this property using the target picked"},
903 
904     {CREATEDRIVER_MAPPING_N_N,
905      "MATCH",
906      ICON_COLOR,
907      "Match Indices",
908      "Create drivers for each pair of corresponding elements"},
909 
910     {CREATEDRIVER_MAPPING_NONE_ALL,
911      "NONE_ALL",
912      ICON_HAND,
913      "Manually Create Later",
914      "Create drivers for all properties without assigning any targets yet"},
915     {CREATEDRIVER_MAPPING_NONE,
916      "NONE_SINGLE",
917      0,
918      "Manually Create Later (Single)",
919      "Create driver for this property only and without assigning any targets yet"},
920     {0, NULL, 0, NULL, NULL},
921 };
922 
923 /* Filtering callback for driver mapping types enum */
driver_mapping_type_itemsf(bContext * C,PointerRNA * UNUSED (owner_ptr),PropertyRNA * UNUSED (owner_prop),bool * r_free)924 static const EnumPropertyItem *driver_mapping_type_itemsf(bContext *C,
925                                                           PointerRNA *UNUSED(owner_ptr),
926                                                           PropertyRNA *UNUSED(owner_prop),
927                                                           bool *r_free)
928 {
929   EnumPropertyItem *input = prop_driver_create_mapping_types;
930   EnumPropertyItem *item = NULL;
931 
932   PointerRNA ptr = {NULL};
933   PropertyRNA *prop = NULL;
934   int index;
935 
936   int totitem = 0;
937 
938   if (!C) { /* needed for docs */
939     return prop_driver_create_mapping_types;
940   }
941 
942   UI_context_active_but_prop_get(C, &ptr, &prop, &index);
943 
944   if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
945     const bool is_array = RNA_property_array_check(prop);
946 
947     while (input->identifier) {
948       if (ELEM(input->value, CREATEDRIVER_MAPPING_1_1, CREATEDRIVER_MAPPING_NONE) || (is_array)) {
949         RNA_enum_item_add(&item, &totitem, input);
950       }
951       input++;
952     }
953   }
954   else {
955     /* We need at least this one! */
956     RNA_enum_items_add_value(&item, &totitem, input, CREATEDRIVER_MAPPING_NONE);
957   }
958 
959   RNA_enum_item_end(&item, &totitem);
960 
961   *r_free = true;
962   return item;
963 }
964 
965 /* Add Driver (With Menu) Button Operator ------------------------ */
966 
add_driver_button_poll(bContext * C)967 static bool add_driver_button_poll(bContext *C)
968 {
969   PointerRNA ptr = {NULL};
970   PropertyRNA *prop = NULL;
971   int index;
972   bool driven, special;
973 
974   /* this operator can only run if there's a property button active, and it can be animated */
975   UI_context_active_but_prop_get(C, &ptr, &prop, &index);
976 
977   if (!(ptr.owner_id && ptr.data && prop)) {
978     return false;
979   }
980   if (!RNA_property_animateable(&ptr, prop)) {
981     return false;
982   }
983 
984   /* Don't do anything if there is an fcurve for animation without a driver. */
985   FCurve *fcu = BKE_fcurve_find_by_rna_context_ui(
986       C, &ptr, prop, index, NULL, NULL, &driven, &special);
987   return (fcu == NULL || fcu->driver);
988 }
989 
990 /* Wrapper for creating a driver without knowing what the targets will be yet
991  * (i.e. "manual/add later"). */
add_driver_button_none(bContext * C,wmOperator * op,short mapping_type)992 static int add_driver_button_none(bContext *C, wmOperator *op, short mapping_type)
993 {
994   PointerRNA ptr = {NULL};
995   PropertyRNA *prop = NULL;
996   int index;
997   int success = 0;
998 
999   UI_context_active_but_prop_get(C, &ptr, &prop, &index);
1000 
1001   if (mapping_type == CREATEDRIVER_MAPPING_NONE_ALL) {
1002     index = -1;
1003   }
1004 
1005   if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
1006     char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
1007     short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
1008 
1009     if (path) {
1010       success += ANIM_add_driver(
1011           op->reports, ptr.owner_id, path, index, flags, DRIVER_TYPE_PYTHON);
1012       MEM_freeN(path);
1013     }
1014   }
1015 
1016   if (success) {
1017     /* send updates */
1018     UI_context_update_anim_flag(C);
1019     DEG_relations_tag_update(CTX_data_main(C));
1020     WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); /* XXX */
1021 
1022     return OPERATOR_FINISHED;
1023   }
1024   return OPERATOR_CANCELLED;
1025 }
1026 
add_driver_button_menu_exec(bContext * C,wmOperator * op)1027 static int add_driver_button_menu_exec(bContext *C, wmOperator *op)
1028 {
1029   short mapping_type = RNA_enum_get(op->ptr, "mapping_type");
1030   if (ELEM(mapping_type, CREATEDRIVER_MAPPING_NONE, CREATEDRIVER_MAPPING_NONE_ALL)) {
1031     /* Just create driver with no targets */
1032     return add_driver_button_none(C, op, mapping_type);
1033   }
1034 
1035   /* Create Driver using Eyedropper */
1036   wmOperatorType *ot = WM_operatortype_find("UI_OT_eyedropper_driver", true);
1037 
1038   /* XXX: We assume that it's fine to use the same set of properties,
1039    * since they're actually the same. */
1040   WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, op->ptr);
1041 
1042   return OPERATOR_FINISHED;
1043 }
1044 
1045 /* Show menu or create drivers */
add_driver_button_menu_invoke(bContext * C,wmOperator * op,const wmEvent * UNUSED (event))1046 static int add_driver_button_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1047 {
1048   PropertyRNA *prop;
1049 
1050   if ((prop = RNA_struct_find_property(op->ptr, "mapping_type")) &&
1051       RNA_property_is_set(op->ptr, prop)) {
1052     /* Mapping Type is Set - Directly go into creating drivers */
1053     return add_driver_button_menu_exec(C, op);
1054   }
1055 
1056   /* Show menu */
1057   /* TODO: This should get filtered by the enum filter. */
1058   /* important to execute in the region we're currently in. */
1059   return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_DEFAULT);
1060 }
1061 
UNUSED_FUNCTION(ANIM_OT_driver_button_add_menu)1062 static void UNUSED_FUNCTION(ANIM_OT_driver_button_add_menu)(wmOperatorType *ot)
1063 {
1064   /* identifiers */
1065   ot->name = "Add Driver Menu";
1066   ot->idname = "ANIM_OT_driver_button_add_menu";
1067   ot->description = "Add driver(s) for the property(s) represented by the highlighted button";
1068 
1069   /* callbacks */
1070   ot->invoke = add_driver_button_menu_invoke;
1071   ot->exec = add_driver_button_menu_exec;
1072   ot->poll = add_driver_button_poll;
1073 
1074   /* flags */
1075   ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
1076 
1077   /* properties */
1078   ot->prop = RNA_def_enum(ot->srna,
1079                           "mapping_type",
1080                           prop_driver_create_mapping_types,
1081                           0,
1082                           "Mapping Type",
1083                           "Method used to match target and driven properties");
1084   RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemsf);
1085 }
1086 
1087 /* Add Driver Button Operator ------------------------ */
1088 
add_driver_button_invoke(bContext * C,wmOperator * op,const wmEvent * UNUSED (event))1089 static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1090 {
1091   PointerRNA ptr = {NULL};
1092   PropertyRNA *prop = NULL;
1093   int index;
1094 
1095   /* try to find driver using property retrieved from UI */
1096   UI_context_active_but_prop_get(C, &ptr, &prop, &index);
1097 
1098   if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
1099     /* 1) Create a new "empty" driver for this property */
1100     char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
1101     short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
1102     bool changed = false;
1103 
1104     if (path) {
1105       changed |= (ANIM_add_driver(
1106                       op->reports, ptr.owner_id, path, index, flags, DRIVER_TYPE_PYTHON) != 0);
1107       MEM_freeN(path);
1108     }
1109 
1110     if (changed) {
1111       /* send updates */
1112       UI_context_update_anim_flag(C);
1113       DEG_id_tag_update(ptr.owner_id, ID_RECALC_COPY_ON_WRITE);
1114       DEG_relations_tag_update(CTX_data_main(C));
1115       WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL);
1116     }
1117 
1118     /* 2) Show editing panel for setting up this driver */
1119     /* TODO: Use a different one from the editing popever, so we can have the single/all toggle? */
1120     UI_popover_panel_invoke(C, "GRAPH_PT_drivers_popover", true, op->reports);
1121   }
1122 
1123   return OPERATOR_INTERFACE;
1124 }
1125 
ANIM_OT_driver_button_add(wmOperatorType * ot)1126 void ANIM_OT_driver_button_add(wmOperatorType *ot)
1127 {
1128   /* identifiers */
1129   ot->name = "Add Driver";
1130   ot->idname = "ANIM_OT_driver_button_add";
1131   ot->description = "Add driver for the property under the cursor";
1132 
1133   /* callbacks */
1134   /* NOTE: No exec, as we need all these to use the current context info */
1135   ot->invoke = add_driver_button_invoke;
1136   ot->poll = add_driver_button_poll;
1137 
1138   /* flags */
1139   ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
1140 }
1141 
1142 /* Remove Driver Button Operator ------------------------ */
1143 
remove_driver_button_exec(bContext * C,wmOperator * op)1144 static int remove_driver_button_exec(bContext *C, wmOperator *op)
1145 {
1146   PointerRNA ptr = {NULL};
1147   PropertyRNA *prop = NULL;
1148   bool changed = false;
1149   int index;
1150   const bool all = RNA_boolean_get(op->ptr, "all");
1151 
1152   /* try to find driver using property retrieved from UI */
1153   UI_context_active_but_prop_get(C, &ptr, &prop, &index);
1154 
1155   if (all) {
1156     index = -1;
1157   }
1158 
1159   if (ptr.owner_id && ptr.data && prop) {
1160     char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
1161 
1162     if (path) {
1163       changed = ANIM_remove_driver(op->reports, ptr.owner_id, path, index, 0);
1164 
1165       MEM_freeN(path);
1166     }
1167   }
1168 
1169   if (changed) {
1170     /* send updates */
1171     UI_context_update_anim_flag(C);
1172     DEG_relations_tag_update(CTX_data_main(C));
1173     WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); /* XXX */
1174   }
1175 
1176   return (changed) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1177 }
1178 
ANIM_OT_driver_button_remove(wmOperatorType * ot)1179 void ANIM_OT_driver_button_remove(wmOperatorType *ot)
1180 {
1181   /* identifiers */
1182   ot->name = "Remove Driver";
1183   ot->idname = "ANIM_OT_driver_button_remove";
1184   ot->description =
1185       "Remove the driver(s) for the property(s) connected represented by the highlighted button";
1186 
1187   /* callbacks */
1188   ot->exec = remove_driver_button_exec;
1189   /* TODO: `op->poll` need to have some driver to be able to do this. */
1190 
1191   /* flags */
1192   ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
1193 
1194   /* properties */
1195   RNA_def_boolean(ot->srna, "all", 1, "All", "Delete drivers for all elements of the array");
1196 }
1197 
1198 /* Edit Driver Button Operator ------------------------ */
1199 
edit_driver_button_exec(bContext * C,wmOperator * op)1200 static int edit_driver_button_exec(bContext *C, wmOperator *op)
1201 {
1202   PointerRNA ptr = {NULL};
1203   PropertyRNA *prop = NULL;
1204   int index;
1205 
1206   /* try to find driver using property retrieved from UI */
1207   UI_context_active_but_prop_get(C, &ptr, &prop, &index);
1208 
1209   if (ptr.owner_id && ptr.data && prop) {
1210     UI_popover_panel_invoke(C, "GRAPH_PT_drivers_popover", true, op->reports);
1211   }
1212 
1213   return OPERATOR_INTERFACE;
1214 }
1215 
ANIM_OT_driver_button_edit(wmOperatorType * ot)1216 void ANIM_OT_driver_button_edit(wmOperatorType *ot)
1217 {
1218   /* identifiers */
1219   ot->name = "Edit Driver";
1220   ot->idname = "ANIM_OT_driver_button_edit";
1221   ot->description =
1222       "Edit the drivers for the property connected represented by the highlighted button";
1223 
1224   /* callbacks */
1225   ot->exec = edit_driver_button_exec;
1226   /* TODO: `op->poll` need to have some driver to be able to do this. */
1227 
1228   /* flags */
1229   ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
1230 }
1231 
1232 /* Copy Driver Button Operator ------------------------ */
1233 
copy_driver_button_exec(bContext * C,wmOperator * op)1234 static int copy_driver_button_exec(bContext *C, wmOperator *op)
1235 {
1236   PointerRNA ptr = {NULL};
1237   PropertyRNA *prop = NULL;
1238   bool changed = false;
1239   int index;
1240 
1241   /* try to create driver using property retrieved from UI */
1242   UI_context_active_but_prop_get(C, &ptr, &prop, &index);
1243 
1244   if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
1245     char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
1246 
1247     if (path) {
1248       /* only copy the driver for the button that this was involved for */
1249       changed = ANIM_copy_driver(op->reports, ptr.owner_id, path, index, 0);
1250 
1251       UI_context_update_anim_flag(C);
1252 
1253       MEM_freeN(path);
1254     }
1255   }
1256 
1257   /* since we're just copying, we don't really need to do anything else...*/
1258   return (changed) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1259 }
1260 
ANIM_OT_copy_driver_button(wmOperatorType * ot)1261 void ANIM_OT_copy_driver_button(wmOperatorType *ot)
1262 {
1263   /* identifiers */
1264   ot->name = "Copy Driver";
1265   ot->idname = "ANIM_OT_copy_driver_button";
1266   ot->description = "Copy the driver for the highlighted button";
1267 
1268   /* callbacks */
1269   ot->exec = copy_driver_button_exec;
1270   /* TODO: `op->poll` need to have some driver to be able to do this. */
1271 
1272   /* flags */
1273   ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
1274 }
1275 
1276 /* Paste Driver Button Operator ------------------------ */
1277 
paste_driver_button_exec(bContext * C,wmOperator * op)1278 static int paste_driver_button_exec(bContext *C, wmOperator *op)
1279 {
1280   PointerRNA ptr = {NULL};
1281   PropertyRNA *prop = NULL;
1282   bool changed = false;
1283   int index;
1284 
1285   /* try to create driver using property retrieved from UI */
1286   UI_context_active_but_prop_get(C, &ptr, &prop, &index);
1287 
1288   if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
1289     char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
1290 
1291     if (path) {
1292       /* only copy the driver for the button that this was involved for */
1293       changed = ANIM_paste_driver(op->reports, ptr.owner_id, path, index, 0);
1294 
1295       UI_context_update_anim_flag(C);
1296 
1297       DEG_relations_tag_update(CTX_data_main(C));
1298 
1299       DEG_id_tag_update(ptr.owner_id, ID_RECALC_ANIMATION);
1300 
1301       WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); /* XXX */
1302 
1303       MEM_freeN(path);
1304     }
1305   }
1306 
1307   /* since we're just copying, we don't really need to do anything else...*/
1308   return (changed) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1309 }
1310 
ANIM_OT_paste_driver_button(wmOperatorType * ot)1311 void ANIM_OT_paste_driver_button(wmOperatorType *ot)
1312 {
1313   /* identifiers */
1314   ot->name = "Paste Driver";
1315   ot->idname = "ANIM_OT_paste_driver_button";
1316   ot->description = "Paste the driver in the copy/paste buffer for the highlighted button";
1317 
1318   /* callbacks */
1319   ot->exec = paste_driver_button_exec;
1320   /* TODO: `op->poll` need to have some driver to be able to do this. */
1321 
1322   /* flags */
1323   ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
1324 }
1325 
1326 /* ************************************************** */
1327