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