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