Blender  V2.93
graph_buttons.c
Go to the documentation of this file.
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.
17  * All rights reserved.
18  */
19 
24 #include <float.h>
25 #include <math.h>
26 #include <stdio.h>
27 #include <string.h>
28 
29 #include "DNA_anim_types.h"
30 #include "DNA_object_types.h"
31 #include "DNA_scene_types.h"
32 
33 #include "MEM_guardedalloc.h"
34 
35 #include "BLI_blenlib.h"
36 #include "BLI_math.h"
37 #include "BLI_utildefines.h"
38 
39 #include "BLT_translation.h"
40 
41 #include "BKE_anim_data.h"
42 #include "BKE_context.h"
43 #include "BKE_curve.h"
44 #include "BKE_fcurve.h"
45 #include "BKE_fcurve_driver.h"
46 #include "BKE_global.h"
47 #include "BKE_main.h"
48 #include "BKE_screen.h"
49 #include "BKE_unit.h"
50 
51 #include "DEG_depsgraph.h"
52 #include "DEG_depsgraph_build.h"
53 
54 #include "WM_api.h"
55 #include "WM_types.h"
56 
57 #include "RNA_access.h"
58 
59 #include "ED_anim_api.h"
60 #include "ED_keyframing.h"
61 #include "ED_screen.h"
62 #include "ED_undo.h"
63 
64 #include "UI_interface.h"
65 #include "UI_resources.h"
66 
67 #include "graph_intern.h" /* own include */
68 
69 /* ******************* graph editor space & buttons ************** */
70 
71 #define B_REDR 1
72 
73 /* -------------- */
74 
75 static bool graph_panel_context(const bContext *C, bAnimListElem **ale, FCurve **fcu)
76 {
77  bAnimContext ac;
78  bAnimListElem *elem = NULL;
79 
80  /* For now, only draw if we could init the anim-context info
81  * (necessary for all animation-related tools)
82  * to work correctly is able to be correctly retrieved.
83  * There's no point showing empty panels?
84  */
85  if (ANIM_animdata_get_context(C, &ac) == 0) {
86  return false;
87  }
88 
89  /* try to find 'active' F-Curve */
90  elem = get_active_fcurve_channel(&ac);
91  if (elem == NULL) {
92  return false;
93  }
94 
95  if (fcu) {
96  *fcu = (FCurve *)elem->data;
97  }
98  if (ale) {
99  *ale = elem;
100  }
101  else {
102  MEM_freeN(elem);
103  }
104 
105  return true;
106 }
107 
109 {
110  FCurve *fcu;
111  if (!graph_panel_context(C, NULL, &fcu)) {
112  return NULL;
113  }
114 
115  return fcu;
116 }
117 
118 static bool graph_panel_poll(const bContext *C, PanelType *UNUSED(pt))
119 {
120  return graph_panel_context(C, NULL, NULL);
121 }
122 
123 /* -------------- */
124 
125 static void graph_panel_cursor_header(const bContext *C, Panel *panel)
126 {
127  bScreen *screen = CTX_wm_screen(C);
130  PointerRNA spaceptr, sceneptr;
131  uiLayout *col;
132 
133  /* get RNA pointers for use when creating the UI elements */
134  RNA_id_pointer_create(&scene->id, &sceneptr);
135  RNA_pointer_create(&screen->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
136 
137  /* 2D-Cursor */
138  col = uiLayoutColumn(panel->layout, false);
139  uiItemR(col, &spaceptr, "show_cursor", 0, "", ICON_NONE);
140 }
141 
142 static void graph_panel_cursor(const bContext *C, Panel *panel)
143 {
144  bScreen *screen = CTX_wm_screen(C);
147  PointerRNA spaceptr, sceneptr;
148  uiLayout *layout = panel->layout;
149  uiLayout *col, *sub;
150 
151  /* get RNA pointers for use when creating the UI elements */
152  RNA_id_pointer_create(&scene->id, &sceneptr);
153  RNA_pointer_create(&screen->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
154 
155  uiLayoutSetPropSep(layout, true);
156  uiLayoutSetPropDecorate(layout, false);
157 
158  /* 2D-Cursor */
159  col = uiLayoutColumn(layout, false);
160  uiLayoutSetActive(col, RNA_boolean_get(&spaceptr, "show_cursor"));
161 
162  sub = uiLayoutColumn(col, true);
163  if (sipo->mode == SIPO_MODE_DRIVERS) {
164  uiItemR(sub, &spaceptr, "cursor_position_x", 0, IFACE_("Cursor X"), ICON_NONE);
165  }
166  else {
167  uiItemR(sub, &sceneptr, "frame_current", 0, IFACE_("Cursor X"), ICON_NONE);
168  }
169 
170  uiItemR(sub, &spaceptr, "cursor_position_y", 0, IFACE_("Y"), ICON_NONE);
171 
172  sub = uiLayoutColumn(col, true);
173  uiItemO(sub, IFACE_("Cursor to Selection"), ICON_NONE, "GRAPH_OT_frame_jump");
174  uiItemO(sub, IFACE_("Cursor Value to Selection"), ICON_NONE, "GRAPH_OT_snap_cursor_value");
175 }
176 
177 /* ******************* active F-Curve ************** */
178 
179 static void graph_panel_properties(const bContext *C, Panel *panel)
180 {
181  bAnimListElem *ale;
182  FCurve *fcu;
183  PointerRNA fcu_ptr;
184  uiLayout *layout = panel->layout;
185  uiLayout *col;
186  char name[256];
187  int icon = 0;
188 
189  if (!graph_panel_context(C, &ale, &fcu)) {
190  return;
191  }
192 
193  /* F-Curve pointer */
194  RNA_pointer_create(ale->fcurve_owner_id, &RNA_FCurve, fcu, &fcu_ptr);
195 
196  /* user-friendly 'name' for F-Curve */
197  col = uiLayoutColumn(layout, false);
198  if (ale->type == ANIMTYPE_FCURVE) {
199  /* get user-friendly name for F-Curve */
200  icon = getname_anim_fcurve(name, ale->id, fcu);
201  }
202  else {
203  /* NLA Control Curve, etc. */
205 
206  /* get name */
207  if (acf && acf->name) {
208  acf->name(ale, name);
209  }
210  else {
211  strcpy(name, IFACE_("<invalid>"));
212  icon = ICON_ERROR;
213  }
214 
215  /* icon */
216  if (ale->type == ANIMTYPE_NLACURVE) {
217  icon = ICON_NLA;
218  }
219  }
220  uiItemL(col, name, icon);
221 
222  uiLayoutSetPropSep(layout, true);
223  uiLayoutSetPropDecorate(layout, false);
224 
225  /* RNA-Path Editing - only really should be enabled when things aren't working */
226  col = uiLayoutColumn(layout, false);
227  uiLayoutSetEnabled(col, (fcu->flag & FCURVE_DISABLED) != 0);
228  uiItemR(col, &fcu_ptr, "data_path", 0, "", ICON_RNA);
229  uiItemR(col, &fcu_ptr, "array_index", 0, NULL, ICON_NONE);
230 
231  /* color settings */
232  col = uiLayoutColumn(layout, true);
233  uiItemR(col, &fcu_ptr, "color_mode", 0, "Display Color", ICON_NONE);
234 
235  if (fcu->color_mode == FCURVE_COLOR_CUSTOM) {
236  uiItemR(col, &fcu_ptr, "color", 0, "Color", ICON_NONE);
237  }
238 
239  /* smoothing setting */
240  col = uiLayoutColumn(layout, true);
241  uiItemR(col, &fcu_ptr, "auto_smoothing", 0, "Handle Smoothing", ICON_NONE);
242 
243  MEM_freeN(ale);
244 }
245 
246 /* ******************* active Keyframe ************** */
247 
248 /* get 'active' keyframe for panel editing */
250  BezTriple **r_bezt,
251  BezTriple **r_prevbezt)
252 {
253  /* zero the pointers */
254  *r_bezt = *r_prevbezt = NULL;
255 
256  const int active_keyframe_index = BKE_fcurve_active_keyframe_index(fcu);
257  if (active_keyframe_index == FCURVE_ACTIVE_KEYFRAME_NONE) {
258  return false;
259  }
260 
261  /* The active keyframe should be selected. */
262  BLI_assert(BEZT_ISSEL_ANY(&fcu->bezt[active_keyframe_index]));
263 
264  *r_bezt = &fcu->bezt[active_keyframe_index];
265  /* Previous is either one before the active, or the point itself if it's the first. */
266  const int prev_index = max_ii(active_keyframe_index - 1, 0);
267  *r_prevbezt = &fcu->bezt[prev_index];
268 
269  return true;
270 }
271 
272 /* update callback for active keyframe properties - base updates stuff */
274  void *fcu_ptr,
275  void *UNUSED(bezt_ptr))
276 {
277  FCurve *fcu = (FCurve *)fcu_ptr;
278 
279  /* make sure F-Curve and its handles are still valid after this editing */
280  sort_time_fcurve(fcu);
281  calchandles_fcurve(fcu);
282 }
283 
284 /* update callback for active keyframe properties - handle-editing wrapper */
285 static void graphedit_activekey_handles_cb(bContext *C, void *fcu_ptr, void *bezt_ptr)
286 {
287  BezTriple *bezt = (BezTriple *)bezt_ptr;
288 
289  /* since editing the handles, make sure they're set to types which are receptive to editing
290  * see transform_conversions.c :: createTransGraphEditData(), last step in second loop
291  */
292  if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) && ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
293  /* by changing to aligned handles, these can now be moved... */
294  bezt->h1 = HD_ALIGN;
295  bezt->h2 = HD_ALIGN;
296  }
297  else {
298  BKE_nurb_bezt_handle_test(bezt, SELECT, true, false);
299  }
300 
301  /* now call standard updates */
302  graphedit_activekey_update_cb(C, fcu_ptr, bezt_ptr);
303 }
304 
305 /* update callback for editing coordinates of right handle in active keyframe properties
306  * NOTE: we cannot just do graphedit_activekey_handles_cb() due to "order of computation"
307  * weirdness (see calchandleNurb_intern() and T39911)
308  */
309 static void graphedit_activekey_left_handle_coord_cb(bContext *C, void *fcu_ptr, void *bezt_ptr)
310 {
311  BezTriple *bezt = (BezTriple *)bezt_ptr;
312 
313  const char f1 = bezt->f1;
314  const char f3 = bezt->f3;
315 
316  bezt->f1 |= SELECT;
317  bezt->f3 &= ~SELECT;
318 
319  /* perform normal updates NOW */
320  graphedit_activekey_handles_cb(C, fcu_ptr, bezt_ptr);
321 
322  /* restore selection state so that no one notices this hack */
323  bezt->f1 = f1;
324  bezt->f3 = f3;
325 }
326 
327 static void graphedit_activekey_right_handle_coord_cb(bContext *C, void *fcu_ptr, void *bezt_ptr)
328 {
329  BezTriple *bezt = (BezTriple *)bezt_ptr;
330 
331  /* original state of handle selection - to be restored after performing the recalculation */
332  const char f1 = bezt->f1;
333  const char f3 = bezt->f3;
334 
335  /* temporarily make it so that only the right handle is selected, so that updates go correctly
336  * (i.e. it now acts as if we've just transforming the vert when it is selected by itself)
337  */
338  bezt->f1 &= ~SELECT;
339  bezt->f3 |= SELECT;
340 
341  /* perform normal updates NOW */
342  graphedit_activekey_handles_cb(C, fcu_ptr, bezt_ptr);
343 
344  /* restore selection state so that no one notices this hack */
345  bezt->f1 = f1;
346  bezt->f3 = f3;
347 }
348 
349 static void graph_panel_key_properties(const bContext *C, Panel *panel)
350 {
351  bAnimListElem *ale;
352  FCurve *fcu;
353  BezTriple *bezt, *prevbezt;
354 
355  uiLayout *layout = panel->layout;
356  const ARegion *region = CTX_wm_region(C);
357  /* Just a width big enough so buttons use entire layout width (will be clamped by it then). */
358  const int but_max_width = region->winx;
359  uiLayout *col;
360  uiBlock *block;
361 
362  if (!graph_panel_context(C, &ale, &fcu)) {
363  return;
364  }
365 
366  block = uiLayoutGetBlock(layout);
367  /* UI_block_func_handle_set(block, do_graph_region_buttons, NULL); */
368  uiLayoutSetPropSep(layout, true);
369  uiLayoutSetPropDecorate(layout, false);
370 
371  /* only show this info if there are keyframes to edit */
372  if (get_active_fcurve_keyframe_edit(fcu, &bezt, &prevbezt)) {
373  PointerRNA bezt_ptr, id_ptr, fcu_prop_ptr;
374  PropertyRNA *fcu_prop = NULL;
375  uiBut *but;
376  int unit = B_UNIT_NONE;
377 
378  /* RNA pointer to keyframe, to allow editing */
379  RNA_pointer_create(ale->fcurve_owner_id, &RNA_Keyframe, bezt, &bezt_ptr);
380 
381  /* get property that F-Curve affects, for some unit-conversion magic */
382  RNA_id_pointer_create(ale->id, &id_ptr);
383  if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &fcu_prop_ptr, &fcu_prop)) {
384  /* determine the unit for this property */
385  unit = RNA_SUBTYPE_UNIT(RNA_property_subtype(fcu_prop));
386  }
387 
388  /* interpolation */
389  col = uiLayoutColumn(layout, false);
390  if (fcu->flag & FCURVE_DISCRETE_VALUES) {
391  uiLayout *split = uiLayoutSplit(col, 0.33f, true);
392  uiItemL(split, IFACE_("Interpolation:"), ICON_NONE);
393  uiItemL(split, IFACE_("None for Enum/Boolean"), ICON_IPO_CONSTANT);
394  }
395  else {
396  uiItemR(col, &bezt_ptr, "interpolation", 0, NULL, ICON_NONE);
397  }
398 
399  /* easing type */
400  if (bezt->ipo > BEZT_IPO_BEZ) {
401  uiItemR(col, &bezt_ptr, "easing", 0, NULL, 0);
402  }
403 
404  /* easing extra */
405  switch (bezt->ipo) {
406  case BEZT_IPO_BACK:
407  col = uiLayoutColumn(layout, 1);
408  uiItemR(col, &bezt_ptr, "back", 0, NULL, 0);
409  break;
410  case BEZT_IPO_ELASTIC:
411  col = uiLayoutColumn(layout, 1);
412  uiItemR(col, &bezt_ptr, "amplitude", 0, NULL, 0);
413  uiItemR(col, &bezt_ptr, "period", 0, NULL, 0);
414  break;
415  default:
416  break;
417  }
418 
419  /* numerical coordinate editing
420  * - we use the button-versions of the calls so that we can attach special update handlers
421  * and unit conversion magic that cannot be achieved using a purely RNA-approach
422  */
423  col = uiLayoutColumn(layout, true);
424  /* keyframe itself */
425  {
426  uiItemL_respect_property_split(col, IFACE_("Key Frame"), ICON_NONE);
427  but = uiDefButR(block,
428  UI_BTYPE_NUM,
429  B_REDR,
430  "",
431  0,
432  0,
433  but_max_width,
434  UI_UNIT_Y,
435  &bezt_ptr,
436  "co_ui",
437  0,
438  0,
439  0,
440  0,
441  0,
442  NULL);
444 
445  uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE);
446  but = uiDefButR(block,
447  UI_BTYPE_NUM,
448  B_REDR,
449  "",
450  0,
451  0,
452  but_max_width,
453  UI_UNIT_Y,
454  &bezt_ptr,
455  "co_ui",
456  1,
457  0,
458  0,
459  0,
460  0,
461  NULL);
463  UI_but_unit_type_set(but, unit);
464  }
465 
466  /* previous handle - only if previous was Bezier interpolation */
467  if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ)) {
468 
469  col = uiLayoutColumn(layout, true);
470  uiItemL_respect_property_split(col, IFACE_("Left Handle Type"), ICON_NONE);
471  but = uiDefButR(block,
473  B_REDR,
474  NULL,
475  0,
476  0,
477  but_max_width,
478  UI_UNIT_Y,
479  &bezt_ptr,
480  "handle_left_type",
481  0,
482  0,
483  0,
484  -1,
485  -1,
486  "Type of left handle");
488 
489  uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE);
490  but = uiDefButR(block,
491  UI_BTYPE_NUM,
492  B_REDR,
493  "",
494  0,
495  0,
496  but_max_width,
497  UI_UNIT_Y,
498  &bezt_ptr,
499  "handle_left",
500  0,
501  0,
502  0,
503  0,
504  0,
505  NULL);
507 
508  uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE);
509  but = uiDefButR(block,
510  UI_BTYPE_NUM,
511  B_REDR,
512  "",
513  0,
514  0,
515  but_max_width,
516  UI_UNIT_Y,
517  &bezt_ptr,
518  "handle_left",
519  1,
520  0,
521  0,
522  0,
523  0,
524  NULL);
526  UI_but_unit_type_set(but, unit);
527  }
528 
529  /* next handle - only if current is Bezier interpolation */
530  if (bezt->ipo == BEZT_IPO_BEZ) {
531  /* NOTE: special update callbacks are needed on the coords here due to T39911 */
532 
533  col = uiLayoutColumn(layout, true);
534  uiItemL_respect_property_split(col, IFACE_("Right Handle Type"), ICON_NONE);
535  but = uiDefButR(block,
537  B_REDR,
538  NULL,
539  0,
540  0,
541  but_max_width,
542  UI_UNIT_Y,
543  &bezt_ptr,
544  "handle_right_type",
545  0,
546  0,
547  0,
548  -1,
549  -1,
550  "Type of right handle");
552 
553  uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE);
554  but = uiDefButR(block,
555  UI_BTYPE_NUM,
556  B_REDR,
557  "",
558  0,
559  0,
560  but_max_width,
561  UI_UNIT_Y,
562  &bezt_ptr,
563  "handle_right",
564  0,
565  0,
566  0,
567  0,
568  0,
569  NULL);
571 
572  uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE);
573  but = uiDefButR(block,
574  UI_BTYPE_NUM,
575  B_REDR,
576  "",
577  0,
578  0,
579  but_max_width,
580  UI_UNIT_Y,
581  &bezt_ptr,
582  "handle_right",
583  1,
584  0,
585  0,
586  0,
587  0,
588  NULL);
590  UI_but_unit_type_set(but, unit);
591  }
592  }
593  else {
594  if ((fcu->bezt == NULL) && (fcu->modifiers.first)) {
595  /* modifiers only - so no keyframes to be active */
596  uiItemL(layout, IFACE_("F-Curve only has F-Modifiers"), ICON_NONE);
597  uiItemL(layout, IFACE_("See Modifiers panel below"), ICON_INFO);
598  }
599  else if (fcu->fpt) {
600  /* samples only */
601  uiItemL(layout,
602  IFACE_("F-Curve doesn't have any keyframes as it only contains sampled points"),
603  ICON_NONE);
604  }
605  else {
606  uiItemL(layout, IFACE_("No active keyframe on F-Curve"), ICON_NONE);
607  }
608  }
609 
610  MEM_freeN(ale);
611 }
612 
613 /* ******************* drivers ******************************** */
614 
615 #define B_IPO_DEPCHANGE 10
616 
617 static void do_graph_region_driver_buttons(bContext *C, void *id_v, int event)
618 {
619  Main *bmain = CTX_data_main(C);
621 
622  switch (event) {
623  case B_IPO_DEPCHANGE: {
624  /* Was not actually run ever (NULL always passed as arg to this callback).
625  * If needed again, will need to check how to pass both fcurve and ID... :/ */
626 #if 0
627  /* force F-Curve & Driver to get re-evaluated (same as the old Update Dependencies) */
628  FCurve *fcu = (FCurve *)fcu_v;
629  ChannelDriver *driver = (fcu) ? fcu->driver : NULL;
630 
631  /* clear invalid flags */
632  if (fcu) {
633  fcu->flag &= ~FCURVE_DISABLED;
634  driver->flag &= ~DRIVER_FLAG_INVALID;
635  }
636 #endif
637  ID *id = id_v;
638  AnimData *adt = BKE_animdata_from_id(id);
639 
640  /* rebuild depsgraph for the new deps, and ensure COW copies get flushed. */
643  if (adt != NULL) {
644  if (adt->action != NULL) {
646  }
647  if (adt->tmpact != NULL) {
649  }
650  }
651 
652  break;
653  }
654  }
655 
656  /* default for now */
657  WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); /* XXX could use better notifier */
658 }
659 
660 /* callback to add a target variable to the active driver */
661 static void driver_add_var_cb(bContext *C, void *driver_v, void *UNUSED(arg))
662 {
663  ChannelDriver *driver = (ChannelDriver *)driver_v;
664 
665  /* add a new variable */
666  driver_add_new_variable(driver);
667  ED_undo_push(C, "Add Driver Variable");
668 }
669 
670 /* callback to remove target variable from active driver */
671 static void driver_delete_var_cb(bContext *C, void *driver_v, void *dvar_v)
672 {
673  ChannelDriver *driver = (ChannelDriver *)driver_v;
674  DriverVar *dvar = (DriverVar *)dvar_v;
675 
676  /* remove the active variable */
677  driver_free_variable_ex(driver, dvar);
678  ED_undo_push(C, "Delete Driver Variable");
679 }
680 
681 /* callback to report why a driver variable is invalid */
682 static void driver_dvar_invalid_name_query_cb(bContext *C, void *dvar_v, void *UNUSED(arg))
683 {
685  C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Invalid Variable Name"), ICON_NONE);
686  uiLayout *layout = UI_popup_menu_layout(pup);
687 
688  DriverVar *dvar = (DriverVar *)dvar_v;
689 
690  if (dvar->flag & DVAR_FLAG_INVALID_EMPTY) {
691  uiItemL(layout, "It cannot be left blank", ICON_ERROR);
692  }
693  if (dvar->flag & DVAR_FLAG_INVALID_START_NUM) {
694  uiItemL(layout, "It cannot start with a number", ICON_ERROR);
695  }
696  if (dvar->flag & DVAR_FLAG_INVALID_START_CHAR) {
697  uiItemL(layout,
698  "It cannot start with a special character,"
699  " including '$', '@', '!', '~', '+', '-', '_', '.', or ' '",
700  ICON_NONE);
701  }
702  if (dvar->flag & DVAR_FLAG_INVALID_HAS_SPACE) {
703  uiItemL(layout, "It cannot contain spaces (e.g. 'a space')", ICON_ERROR);
704  }
705  if (dvar->flag & DVAR_FLAG_INVALID_HAS_DOT) {
706  uiItemL(layout, "It cannot contain dots (e.g. 'a.dot')", ICON_ERROR);
707  }
708  if (dvar->flag & DVAR_FLAG_INVALID_HAS_SPECIAL) {
709  uiItemL(layout, "It cannot contain special (non-alphabetical/numeric) characters", ICON_ERROR);
710  }
711  if (dvar->flag & DVAR_FLAG_INVALID_PY_KEYWORD) {
712  uiItemL(layout, "It cannot be a reserved keyword in Python", ICON_INFO);
713  }
714 
715  UI_popup_menu_end(C, pup);
716 }
717 
718 /* callback to reset the driver's flags */
719 static void driver_update_flags_cb(bContext *UNUSED(C), void *fcu_v, void *UNUSED(arg))
720 {
721  FCurve *fcu = (FCurve *)fcu_v;
722  ChannelDriver *driver = fcu->driver;
723 
724  /* clear invalid flags */
725  fcu->flag &= ~FCURVE_DISABLED;
726  driver->flag &= ~DRIVER_FLAG_INVALID;
727 }
728 
729 /* drivers panel poll */
731 {
733 
734  if (sipo->mode != SIPO_MODE_DRIVERS) {
735  return false;
736  }
737 
738  return graph_panel_context(C, NULL, NULL);
739 }
740 
741 /* settings for 'single property' driver variable type */
742 static void graph_panel_driverVar__singleProp(uiLayout *layout, ID *id, DriverVar *dvar)
743 {
744  DriverTarget *dtar = &dvar->targets[0];
745  PointerRNA dtar_ptr;
746  uiLayout *row, *col;
747 
748  /* initialize RNA pointer to the target */
749  RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
750 
751  /* Target ID */
752  row = uiLayoutRow(layout, false);
753  uiLayoutSetRedAlert(row, ((dtar->flag & DTAR_FLAG_INVALID) && !dtar->id));
754  uiTemplateAnyID(row, &dtar_ptr, "id", "id_type", IFACE_("Prop:"));
755 
756  /* Target Property */
757  if (dtar->id) {
758  PointerRNA root_ptr;
759 
760  /* get pointer for resolving the property selected */
761  RNA_id_pointer_create(dtar->id, &root_ptr);
762 
763  /* rna path */
764  col = uiLayoutColumn(layout, true);
766  uiTemplatePathBuilder(col, &dtar_ptr, "data_path", &root_ptr, IFACE_("Path"));
767  }
768 }
769 
770 /* settings for 'rotation difference' driver variable type */
771 /* FIXME: 1) Must be same armature for both dtars, 2) Alignment issues... */
772 static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *dvar)
773 {
774  DriverTarget *dtar = &dvar->targets[0];
775  DriverTarget *dtar2 = &dvar->targets[1];
776  Object *ob1 = (Object *)dtar->id;
777  Object *ob2 = (Object *)dtar2->id;
778  PointerRNA dtar_ptr, dtar2_ptr;
779  uiLayout *col;
780 
781  /* initialize RNA pointer to the target */
782  RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
783  RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr);
784 
785  /* Object 1 */
786  col = uiLayoutColumn(layout, true);
787  uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
788  uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Object 1"), ICON_NONE);
789 
790  if (dtar->id && GS(dtar->id->name) == ID_OB && ob1->pose) {
791  PointerRNA tar_ptr;
792 
793  RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
794  uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
795  }
796 
797  /* Object 2 */
798  col = uiLayoutColumn(layout, true);
799  uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
800  uiItemR(col, &dtar2_ptr, "id", 0, IFACE_("Object 2"), ICON_NONE);
801 
802  if (dtar2->id && GS(dtar2->id->name) == ID_OB && ob2->pose) {
803  PointerRNA tar_ptr;
804 
805  RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
806  uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
807  }
808 }
809 
810 /* settings for 'location difference' driver variable type */
811 static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *dvar)
812 {
813  DriverTarget *dtar = &dvar->targets[0];
814  DriverTarget *dtar2 = &dvar->targets[1];
815  Object *ob1 = (Object *)dtar->id;
816  Object *ob2 = (Object *)dtar2->id;
817  PointerRNA dtar_ptr, dtar2_ptr;
818  uiLayout *col;
819 
820  /* initialize RNA pointer to the target */
821  RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
822  RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr);
823 
824  /* Object 1 */
825  col = uiLayoutColumn(layout, true);
826  uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
827  uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Object 1"), ICON_NONE);
828 
829  if (dtar->id && GS(dtar->id->name) == ID_OB && ob1->pose) {
830  PointerRNA tar_ptr;
831 
832  RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
834  col, &dtar_ptr, "bone_target", &tar_ptr, "bones", IFACE_("Bone"), ICON_BONE_DATA);
835  }
836 
837  /* we can clear it again now - it's only needed when creating the ID/Bone fields */
838  uiLayoutSetRedAlert(col, false);
839 
840  uiItemR(col, &dtar_ptr, "transform_space", 0, NULL, ICON_NONE);
841 
842  /* Object 2 */
843  col = uiLayoutColumn(layout, true);
844  uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
845  uiItemR(col, &dtar2_ptr, "id", 0, IFACE_("Object 2"), ICON_NONE);
846 
847  if (dtar2->id && GS(dtar2->id->name) == ID_OB && ob2->pose) {
848  PointerRNA tar_ptr;
849 
850  RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
852  col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", IFACE_("Bone"), ICON_BONE_DATA);
853  }
854 
855  /* we can clear it again now - it's only needed when creating the ID/Bone fields */
856  uiLayoutSetRedAlert(col, false);
857 
858  uiItemR(col, &dtar2_ptr, "transform_space", 0, NULL, ICON_NONE);
859 }
860 
861 /* settings for 'transform channel' driver variable type */
862 static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar *dvar)
863 {
864  DriverTarget *dtar = &dvar->targets[0];
865  Object *ob = (Object *)dtar->id;
866  PointerRNA dtar_ptr;
867  uiLayout *col, *sub;
868 
869  /* initialize RNA pointer to the target */
870  RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
871 
872  /* properties */
873  col = uiLayoutColumn(layout, true);
874  uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
875  uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Object"), ICON_NONE);
876 
877  if (dtar->id && GS(dtar->id->name) == ID_OB && ob->pose) {
878  PointerRNA tar_ptr;
879 
880  RNA_pointer_create(dtar->id, &RNA_Pose, ob->pose, &tar_ptr);
882  col, &dtar_ptr, "bone_target", &tar_ptr, "bones", IFACE_("Bone"), ICON_BONE_DATA);
883  }
884 
885  sub = uiLayoutColumn(layout, true);
886  uiItemR(sub, &dtar_ptr, "transform_type", 0, NULL, ICON_NONE);
887 
888  if (ELEM(dtar->transChan,
893  uiItemR(sub, &dtar_ptr, "rotation_mode", 0, IFACE_("Mode"), ICON_NONE);
894  }
895 
896  uiItemR(sub, &dtar_ptr, "transform_space", 0, IFACE_("Space"), ICON_NONE);
897 }
898 
899 /* ----------------------------------------------------------------- */
900 
901 /* property driven by the driver - duplicates Active FCurve, but useful for clarity */
902 static void graph_draw_driven_property_panel(uiLayout *layout, ID *id, FCurve *fcu)
903 {
904  PointerRNA fcu_ptr;
905  uiLayout *row;
906  char name[256];
907  int icon = 0;
908 
909  /* F-Curve pointer */
910  RNA_pointer_create(id, &RNA_FCurve, fcu, &fcu_ptr);
911 
912  /* get user-friendly 'name' for F-Curve */
913  icon = getname_anim_fcurve(name, id, fcu);
914 
915  /* panel layout... */
916  row = uiLayoutRow(layout, true);
918 
919  /* -> user friendly 'name' for datablock that owns F-Curve */
920  /* XXX: Actually, we may need the datablock icons only...
921  * (e.g. right now will show bone for bone props). */
922  uiItemL(row, id->name + 2, icon);
923 
924  /* -> user friendly 'name' for F-Curve/driver target */
925  uiItemL(row, "", ICON_SMALL_TRI_RIGHT_VEC);
926  uiItemL(row, name, ICON_RNA);
927 }
928 
929 /* UI properties panel layout for driver settings - shared for Drivers Editor and for */
931  ID *id,
932  FCurve *fcu,
933  const bool is_popover)
934 {
935  ChannelDriver *driver = fcu->driver;
936  DriverVar *dvar;
937 
938  PointerRNA driver_ptr;
939  uiLayout *col, *row, *row_outer;
940  uiBlock *block;
941  uiBut *but;
942 
943  /* set event handler for panel */
944  block = uiLayoutGetBlock(layout);
946 
947  /* driver-level settings - type, expressions, and errors */
948  RNA_pointer_create(id, &RNA_Driver, driver, &driver_ptr);
949 
950  col = uiLayoutColumn(layout, true);
951  block = uiLayoutGetBlock(col);
952  uiItemR(col, &driver_ptr, "type", 0, NULL, ICON_NONE);
953 
954  {
955  char valBuf[32];
956 
957  /* value of driver */
958  row = uiLayoutRow(col, true);
959  uiItemL(row, IFACE_("Driver Value:"), ICON_NONE);
960  BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", driver->curval);
961  uiItemL(row, valBuf, ICON_NONE);
962  }
963 
964  uiItemS(layout);
965  uiItemS(layout);
966 
967  /* show expression box if doing scripted drivers,
968  * and/or error messages when invalid drivers exist */
969  if (driver->type == DRIVER_TYPE_PYTHON) {
970  bool bpy_data_expr_error = (strstr(driver->expression, "bpy.data.") != NULL);
971  bool bpy_ctx_expr_error = (strstr(driver->expression, "bpy.context.") != NULL);
972 
973  /* expression */
974  /* TODO: "Show syntax hints" button */
975  col = uiLayoutColumn(layout, true);
976  block = uiLayoutGetBlock(col);
977 
978  uiItemL(col, IFACE_("Expression:"), ICON_NONE);
979  uiItemR(col, &driver_ptr, "expression", 0, "", ICON_NONE);
980  uiItemR(col, &driver_ptr, "use_self", 0, NULL, ICON_NONE);
981 
982  /* errors? */
983  col = uiLayoutColumn(layout, true);
984  block = uiLayoutGetBlock(col);
985 
986  if (driver->flag & DRIVER_FLAG_INVALID) {
987  uiItemL(col, TIP_("ERROR: Invalid Python expression"), ICON_CANCEL);
988  }
989  else if (!BKE_driver_has_simple_expression(driver)) {
990  if ((G.f & G_FLAG_SCRIPT_AUTOEXEC) == 0) {
991  /* TODO: Add button to enable? */
992  uiItemL(col, TIP_("Python restricted for security"), ICON_ERROR);
993  }
994  else {
995  uiItemL(col, TIP_("Slow Python expression"), ICON_INFO);
996  }
997  }
998 
999  /* Explicit bpy-references are evil. Warn about these to prevent errors */
1000  /* TODO: put these in a box? */
1001  if (bpy_data_expr_error || bpy_ctx_expr_error) {
1002  uiItemL(col, TIP_("WARNING: Driver expression may not work correctly"), ICON_HELP);
1003 
1004  if (bpy_data_expr_error) {
1005  uiItemL(col, TIP_("TIP: Use variables instead of bpy.data paths (see below)"), ICON_ERROR);
1006  }
1007  if (bpy_ctx_expr_error) {
1008  uiItemL(col, TIP_("TIP: bpy.context is not safe for renderfarm usage"), ICON_ERROR);
1009  }
1010  }
1011  }
1012  else {
1013  /* errors? */
1014  col = uiLayoutColumn(layout, true);
1015  block = uiLayoutGetBlock(col);
1016 
1017  if (driver->flag & DRIVER_FLAG_INVALID) {
1018  uiItemL(col, TIP_("ERROR: Invalid target channel(s)"), ICON_ERROR);
1019  }
1020 
1021  /* Warnings about a lack of variables
1022  * NOTE: The lack of variables is generally a bad thing, since it indicates
1023  * that the driver doesn't work at all. This particular scenario arises
1024  * primarily when users mistakenly try to use drivers for procedural
1025  * property animation
1026  */
1027  if (BLI_listbase_is_empty(&driver->variables)) {
1028  uiItemL(col, TIP_("ERROR: Driver is useless without any inputs"), ICON_ERROR);
1029 
1030  if (!BLI_listbase_is_empty(&fcu->modifiers)) {
1031  uiItemL(col, TIP_("TIP: Use F-Curves for procedural animation instead"), ICON_INFO);
1032  uiItemL(col, TIP_("F-Modifiers can generate curves for those too"), ICON_INFO);
1033  }
1034  }
1035  }
1036 
1037  uiItemS(layout);
1038 
1039  /* add/copy/paste driver variables */
1040  row_outer = uiLayoutRow(layout, false);
1041 
1042  /* add driver variable - add blank */
1043  row = uiLayoutRow(row_outer, true);
1044  block = uiLayoutGetBlock(row);
1045  but = uiDefIconTextBut(
1046  block,
1047  UI_BTYPE_BUT,
1049  ICON_ADD,
1050  IFACE_("Add Input Variable"),
1051  0,
1052  0,
1053  10 * UI_UNIT_X,
1054  UI_UNIT_Y,
1055  NULL,
1056  0.0,
1057  0.0,
1058  0,
1059  0,
1060  TIP_("Add a Driver Variable to keep track of an input used by the driver"));
1061  UI_but_func_set(but, driver_add_var_cb, driver, NULL);
1062 
1063  if (is_popover) {
1064  /* add driver variable - add using eyedropper */
1065  /* XXX: will this operator work like this? */
1066  uiItemO(row, "", ICON_EYEDROPPER, "UI_OT_eyedropper_driver");
1067  }
1068 
1069  /* copy/paste (as sub-row) */
1070  row = uiLayoutRow(row_outer, true);
1071  block = uiLayoutGetBlock(row);
1072 
1073  uiItemO(row, "", ICON_COPYDOWN, "GRAPH_OT_driver_variables_copy");
1074  uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_driver_variables_paste");
1075 
1076  /* loop over targets, drawing them */
1077  for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
1078  PointerRNA dvar_ptr;
1079  uiLayout *box;
1080  uiLayout *subrow, *sub;
1081 
1082  /* sub-layout column for this variable's settings */
1083  col = uiLayoutColumn(layout, true);
1084 
1085  /* 1) header panel */
1086  box = uiLayoutBox(col);
1087  RNA_pointer_create(id, &RNA_DriverVariable, dvar, &dvar_ptr);
1088 
1089  row = uiLayoutRow(box, false);
1090  block = uiLayoutGetBlock(row);
1091 
1092  /* 1.1) variable type and name */
1093  subrow = uiLayoutRow(row, true);
1094 
1095  /* 1.1.1) variable type */
1096 
1097  /* HACK: special group just for the enum,
1098  * otherwise we get ugly layout with text included too... */
1099  sub = uiLayoutRow(subrow, true);
1100 
1102 
1103  uiItemR(sub, &dvar_ptr, "type", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
1104 
1105  /* 1.1.2) variable name */
1106 
1107  /* HACK: special group to counteract the effects of the previous enum,
1108  * which now pushes everything too far right */
1109  sub = uiLayoutRow(subrow, true);
1110 
1112 
1113  uiItemR(sub, &dvar_ptr, "name", 0, "", ICON_NONE);
1114 
1115  /* 1.2) invalid name? */
1117 
1118  if (dvar->flag & DVAR_FLAG_INVALID_NAME) {
1119  but = uiDefIconBut(block,
1120  UI_BTYPE_BUT,
1122  ICON_ERROR,
1123  290,
1124  0,
1125  UI_UNIT_X,
1126  UI_UNIT_Y,
1127  NULL,
1128  0.0,
1129  0.0,
1130  0.0,
1131  0.0,
1132  TIP_("Invalid variable name, click here for details"));
1133  UI_but_func_set(but, driver_dvar_invalid_name_query_cb, dvar, NULL); /* XXX: reports? */
1134  }
1135 
1136  /* 1.3) remove button */
1137  but = uiDefIconBut(block,
1138  UI_BTYPE_BUT,
1140  ICON_X,
1141  290,
1142  0,
1143  UI_UNIT_X,
1144  UI_UNIT_Y,
1145  NULL,
1146  0.0,
1147  0.0,
1148  0.0,
1149  0.0,
1150  TIP_("Delete target variable"));
1151  UI_but_func_set(but, driver_delete_var_cb, driver, dvar);
1153 
1154  /* 2) variable type settings */
1155  box = uiLayoutBox(col);
1156  /* controls to draw depends on the type of variable */
1157  switch (dvar->type) {
1158  case DVAR_TYPE_SINGLE_PROP: /* single property */
1159  graph_panel_driverVar__singleProp(box, id, dvar);
1160  break;
1161  case DVAR_TYPE_ROT_DIFF: /* rotational difference */
1162  graph_panel_driverVar__rotDiff(box, id, dvar);
1163  break;
1164  case DVAR_TYPE_LOC_DIFF: /* location difference */
1165  graph_panel_driverVar__locDiff(box, id, dvar);
1166  break;
1167  case DVAR_TYPE_TRANSFORM_CHAN: /* transform channel */
1168  graph_panel_driverVar__transChan(box, id, dvar);
1169  break;
1170  }
1171 
1172  /* 3) value of variable */
1173  {
1174  char valBuf[32];
1175 
1176  box = uiLayoutBox(col);
1177  row = uiLayoutRow(box, true);
1178  uiItemL(row, IFACE_("Value:"), ICON_NONE);
1179 
1180  if ((dvar->type == DVAR_TYPE_ROT_DIFF) ||
1181  (dvar->type == DVAR_TYPE_TRANSFORM_CHAN &&
1182  ELEM(dvar->targets[0].transChan,
1188  BLI_snprintf(
1189  valBuf, sizeof(valBuf), "%.3f (%4.1f°)", dvar->curval, RAD2DEGF(dvar->curval));
1190  }
1191  else {
1192  BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", dvar->curval);
1193  }
1194 
1195  uiItemL(row, valBuf, ICON_NONE);
1196  }
1197  }
1198 
1199  uiItemS(layout);
1200  uiItemS(layout);
1201 
1202  /* XXX: This should become redundant. But sometimes the flushing fails,
1203  * so keep this around for a while longer as a "last resort" */
1204  row = uiLayoutRow(layout, true);
1205  block = uiLayoutGetBlock(row);
1206  but = uiDefIconTextBut(
1207  block,
1208  UI_BTYPE_BUT,
1210  ICON_FILE_REFRESH,
1211  IFACE_("Update Dependencies"),
1212  0,
1213  0,
1214  10 * UI_UNIT_X,
1215  UI_UNIT_Y,
1216  NULL,
1217  0.0,
1218  0.0,
1219  0,
1220  0,
1221  TIP_("Force updates of dependencies - Only use this if drivers are not updating correctly"));
1223 }
1224 
1225 /* ----------------------------------------------------------------- */
1226 
1227 /* Panel to show property driven by the driver (in Drivers Editor) - duplicates Active FCurve,
1228  * but useful for clarity. */
1229 static void graph_panel_driven_property(const bContext *C, Panel *panel)
1230 {
1231  bAnimListElem *ale;
1232  FCurve *fcu;
1233 
1234  if (!graph_panel_context(C, &ale, &fcu)) {
1235  return;
1236  }
1237 
1238  graph_draw_driven_property_panel(panel->layout, ale->id, fcu);
1239 
1240  MEM_freeN(ale);
1241 }
1242 
1243 /* driver settings for active F-Curve
1244  * (only for 'Drivers' mode in Graph Editor, i.e. the full "Drivers Editor") */
1245 static void graph_panel_drivers(const bContext *C, Panel *panel)
1246 {
1247  bAnimListElem *ale;
1248  FCurve *fcu;
1249 
1250  /* Get settings from context */
1251  if (!graph_panel_context(C, &ale, &fcu)) {
1252  return;
1253  }
1254 
1255  graph_draw_driver_settings_panel(panel->layout, ale->id, fcu, false);
1256 
1257  /* cleanup */
1258  MEM_freeN(ale);
1259 }
1260 
1261 /* ----------------------------------------------------------------- */
1262 
1263 /* Poll to make this not show up in the graph editor,
1264  * as this is only to be used as a popup elsewhere. */
1266 {
1267  return ED_operator_graphedit_active((bContext *)C) == false;
1268 }
1269 
1270 /* popover panel for driver editing anywhere in ui */
1271 static void graph_panel_drivers_popover(const bContext *C, Panel *panel)
1272 {
1273  uiLayout *layout = panel->layout;
1274 
1275  PointerRNA ptr = {NULL};
1276  PropertyRNA *prop = NULL;
1277  int index = -1;
1278  uiBut *but = NULL;
1279 
1280  /* Get active property to show driver properties for */
1281  but = UI_context_active_but_prop_get((bContext *)C, &ptr, &prop, &index);
1282  if (but) {
1283  FCurve *fcu;
1284  bool driven, special;
1285 
1287  (bContext *)C, &ptr, prop, index, NULL, NULL, &driven, &special);
1288 
1289  /* Hack: Force all buttons in this panel to be able to know the driver button
1290  * this panel is getting spawned from, so that things like the "Open Drivers Editor"
1291  * button will work.
1292  */
1293  uiLayoutSetContextFromBut(layout, but);
1294 
1295  /* Populate Panel - With a combination of the contents of the Driven and Driver panels */
1296  if (fcu && fcu->driver) {
1297  ID *id = ptr.owner_id;
1298 
1299  PointerRNA ptr_fcurve;
1300  RNA_pointer_create(id, &RNA_FCurve, fcu, &ptr_fcurve);
1301  uiLayoutSetContextPointer(layout, "active_editable_fcurve", &ptr_fcurve);
1302 
1303  /* Driven Property Settings */
1304  uiItemL(layout, IFACE_("Driven Property:"), ICON_NONE);
1305  graph_draw_driven_property_panel(panel->layout, id, fcu);
1306  /* TODO: All vs Single */
1307 
1308  uiItemS(layout);
1309  uiItemS(layout);
1310 
1311  /* Drivers Settings */
1312  uiItemL(layout, IFACE_("Driver Settings:"), ICON_NONE);
1313  graph_draw_driver_settings_panel(panel->layout, id, fcu, true);
1314  }
1315  }
1316 
1317  /* Show drivers editor is always visible */
1318  uiItemO(layout, IFACE_("Show in Drivers Editor"), ICON_DRIVER, "SCREEN_OT_drivers_editor_show");
1319 }
1320 
1321 /* ******************* F-Modifiers ******************************** */
1322 /* All the drawing code is in editors/animation/fmodifier_ui.c */
1323 
1324 #define B_FMODIFIER_REDRAW 20
1326 #define GRAPH_FMODIFIER_PANEL_PREFIX "GRAPH"
1327 
1328 static void graph_fmodifier_panel_id(void *fcm_link, char *r_name)
1329 {
1330  FModifier *fcm = (FModifier *)fcm_link;
1331  eFModifier_Types type = fcm->type;
1333  BLI_snprintf(r_name, BKE_ST_MAXNAME, "%s_PT_%s", GRAPH_FMODIFIER_PANEL_PREFIX, fmi->name);
1334 }
1335 
1336 static void do_graph_region_modifier_buttons(bContext *C, void *UNUSED(arg), int event)
1337 {
1338  switch (event) {
1339  case B_FMODIFIER_REDRAW: /* XXX this should send depsgraph updates too */
1341  C, NC_ANIMATION, NULL); /* XXX need a notifier specially for F-Modifiers */
1342  break;
1343  }
1344 }
1345 
1346 static void graph_panel_modifiers(const bContext *C, Panel *panel)
1347 {
1348  bAnimListElem *ale;
1349  FCurve *fcu;
1350  uiLayout *row;
1351  uiBlock *block;
1352 
1353  if (!graph_panel_context(C, &ale, &fcu)) {
1354  return;
1355  }
1356 
1357  block = uiLayoutGetBlock(panel->layout);
1359 
1360  /* 'add modifier' button at top of panel */
1361  {
1362  row = uiLayoutRow(panel->layout, false);
1363 
1364  /* this is an operator button which calls a 'add modifier' operator...
1365  * a menu might be nicer but would be tricky as we need some custom filtering
1366  */
1368  row, (bContext *)C, "GRAPH_OT_fmodifier_add", "type", IFACE_("Add Modifier"), ICON_NONE);
1369 
1370  /* copy/paste (as sub-row) */
1371  row = uiLayoutRow(row, true);
1372  uiItemO(row, "", ICON_COPYDOWN, "GRAPH_OT_fmodifier_copy");
1373  uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_fmodifier_paste");
1374  }
1375 
1377 
1378  MEM_freeN(ale);
1379 }
1380 
1381 /* ******************* general ******************************** */
1382 
1384 {
1385  PanelType *pt;
1386 
1387  pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
1388  strcpy(pt->idname, "GRAPH_PT_properties");
1389  strcpy(pt->label, N_("Active F-Curve"));
1390  strcpy(pt->category, "F-Curve");
1393  pt->poll = graph_panel_poll;
1394  BLI_addtail(&art->paneltypes, pt);
1395 
1396  pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
1397  strcpy(pt->idname, "GRAPH_PT_key_properties");
1398  strcpy(pt->label, N_("Active Keyframe"));
1399  strcpy(pt->category, "F-Curve");
1402  pt->poll = graph_panel_poll;
1403  BLI_addtail(&art->paneltypes, pt);
1404 
1405  pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers driven");
1406  strcpy(pt->idname, "GRAPH_PT_driven_property");
1407  strcpy(pt->label, N_("Driven Property"));
1408  strcpy(pt->category, "Drivers");
1412  BLI_addtail(&art->paneltypes, pt);
1413 
1414  pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers");
1415  strcpy(pt->idname, "GRAPH_PT_drivers");
1416  strcpy(pt->label, N_("Driver"));
1417  strcpy(pt->category, "Drivers");
1419  pt->draw = graph_panel_drivers;
1421  BLI_addtail(&art->paneltypes, pt);
1422 
1423  pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers popover");
1424  strcpy(pt->idname, "GRAPH_PT_drivers_popover");
1425  strcpy(pt->label, N_("Add/Edit Driver"));
1426  strcpy(pt->category, "Drivers");
1430  BLI_addtail(&art->paneltypes, pt);
1431  /* This panel isn't used in this region.
1432  * Add explicitly to global list (so popovers work). */
1433  WM_paneltype_add(pt);
1434 
1435  pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel modifiers");
1436  strcpy(pt->idname, "GRAPH_PT_modifiers");
1437  strcpy(pt->label, N_("Modifiers"));
1438  strcpy(pt->category, "Modifiers");
1440  pt->flag = PANEL_TYPE_NO_HEADER;
1442  pt->poll = graph_panel_poll;
1443  BLI_addtail(&art->paneltypes, pt);
1444 
1447 
1448  pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel view");
1449  strcpy(pt->idname, "GRAPH_PT_view");
1450  strcpy(pt->label, N_("Show Cursor"));
1451  strcpy(pt->category, "View");
1453  pt->draw = graph_panel_cursor;
1455  BLI_addtail(&art->paneltypes, pt);
1456 }
struct AnimData * BKE_animdata_from_id(struct ID *id)
Definition: anim_data.c:96
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct SpaceGraph * CTX_wm_space_graph(const bContext *C)
Definition: context.c:863
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:709
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
void BKE_nurb_bezt_handle_test(struct BezTriple *bezt, const eBezTriple_Flag__Alias sel_flag, const bool use_handle, const bool use_around_local)
Definition: curve.c:4161
struct FCurve * BKE_fcurve_find_by_rna_context_ui(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, int rnaindex, struct AnimData **r_animdata, struct bAction **r_action, bool *r_driven, bool *r_special)
Definition: fcurve.c:390
void sort_time_fcurve(struct FCurve *fcu)
Definition: fcurve.c:1429
const FModifierTypeInfo * get_fmodifier_typeinfo(const int type)
Definition: fmodifier.c:1072
void calchandles_fcurve(struct FCurve *fcu)
Definition: fcurve.c:1391
int BKE_fcurve_active_keyframe_index(const struct FCurve *fcu)
bool BKE_driver_has_simple_expression(struct ChannelDriver *driver)
struct DriverVar * driver_add_new_variable(struct ChannelDriver *driver)
void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dvar)
@ G_FLAG_SCRIPT_AUTOEXEC
Definition: BKE_global.h:116
#define BKE_ST_MAXNAME
Definition: BKE_screen.h:68
@ PANEL_TYPE_NO_HEADER
Definition: BKE_screen.h:298
@ B_UNIT_NONE
Definition: BKE_unit.h:78
#define BLI_assert(a)
Definition: BLI_assert.h:58
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
MINLINE int max_ii(int a, int b)
#define RAD2DEGF(_rad)
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#define UNUSED(x)
#define ELEM(...)
#define TIP_(msgid)
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
#define IFACE_(msgid)
#define BLT_I18NCONTEXT_DEFAULT_BPYRNA
#define N_(msgid)
void DEG_id_tag_update_ex(struct Main *bmain, struct ID *id, int flag)
void DEG_relations_tag_update(struct Main *bmain)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:654
@ ID_OB
Definition: DNA_ID_enums.h:59
@ DTAR_TRANSCHAN_ROTZ
@ DTAR_TRANSCHAN_ROTW
@ DTAR_TRANSCHAN_ROTX
@ DTAR_TRANSCHAN_ROTY
@ DRIVER_TYPE_PYTHON
@ FCURVE_COLOR_CUSTOM
@ DVAR_TYPE_LOC_DIFF
@ DVAR_TYPE_TRANSFORM_CHAN
@ DVAR_TYPE_ROT_DIFF
@ DVAR_TYPE_SINGLE_PROP
eFModifier_Types
@ DTAR_ROTMODE_QUATERNION
@ DTAR_FLAG_INVALID
@ DRIVER_FLAG_INVALID
#define FCURVE_ACTIVE_KEYFRAME_NONE
@ FCURVE_DISABLED
@ FCURVE_DISCRETE_VALUES
@ DVAR_FLAG_INVALID_START_CHAR
@ DVAR_FLAG_INVALID_NAME
@ DVAR_FLAG_INVALID_EMPTY
@ DVAR_FLAG_INVALID_START_NUM
@ DVAR_FLAG_INVALID_HAS_SPACE
@ DVAR_FLAG_INVALID_HAS_DOT
@ DVAR_FLAG_INVALID_HAS_SPECIAL
@ DVAR_FLAG_INVALID_PY_KEYWORD
#define BEZT_ISSEL_ANY(bezt)
@ HD_AUTO_ANIM
@ HD_AUTO
@ HD_ALIGN
@ BEZT_IPO_ELASTIC
@ BEZT_IPO_BACK
@ BEZT_IPO_BEZ
Object is a sort of wrapper for general info.
@ SIPO_MODE_DRIVERS
@ ANIMTYPE_NLACURVE
Definition: ED_anim_api.h:210
@ ANIMTYPE_FCURVE
Definition: ED_anim_api.h:207
bool ED_operator_graphedit_active(struct bContext *C)
Definition: screen_ops.c:314
void ED_undo_push(struct bContext *C, const char *str)
Definition: ed_undo.c:117
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
StructRNA RNA_DriverVariable
StructRNA RNA_DriverTarget
StructRNA RNA_FCurve
StructRNA RNA_Keyframe
StructRNA RNA_Pose
StructRNA RNA_Driver
StructRNA RNA_SpaceGraphEditor
#define RNA_SUBTYPE_UNIT(subtype)
Definition: RNA_types.h:98
#define C
Definition: RandGen.cpp:39
uiBut * uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, const char *str, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.c:5603
#define UI_UNIT_Y
void uiLayoutSetActive(uiLayout *layout, bool active)
@ UI_ITEM_R_ICON_ONLY
uiBlock * uiLayoutGetBlock(uiLayout *layout)
@ UI_EMBOSS_NONE
Definition: UI_interface.h:108
@ UI_EMBOSS
Definition: UI_interface.h:107
uiBut * uiDefIconBut(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.c:5223
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiTemplatePathBuilder(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *root_ptr, const char *text)
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiItemMenuEnumO(uiLayout *layout, struct bContext *C, const char *opname, const char *propname, const char *name, int icon)
void uiLayoutSetRedAlert(uiLayout *layout, bool redalert)
struct uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
uiLayout * uiLayoutBox(uiLayout *layout)
void uiLayoutSetAlignment(uiLayout *layout, char alignment)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg)
Definition: interface.c:6247
void uiItemS(uiLayout *layout)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
@ UI_LAYOUT_ALIGN_LEFT
@ UI_LAYOUT_ALIGN_EXPAND
uiBut * uiDefButR(uiBlock *block, int type, int retval, const char *str, int x, int y, short width, short height, struct PointerRNA *ptr, const char *propname, int index, float min, float max, float a1, float a2, const char *tip)
Definition: interface.c:5144
void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss)
Definition: interface.c:3542
void UI_but_unit_type_set(uiBut *but, const int unit_type)
Definition: interface.c:6228
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void UI_but_func_set(uiBut *but, uiButHandleFunc func, void *arg1, void *arg2)
Definition: interface.c:6294
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, struct PointerRNA *ptr)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutSplit(uiLayout *layout, float percentage, bool align)
void uiLayoutSetContextFromBut(uiLayout *layout, uiBut *but)
uiLayout * uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon)
uiBut * UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index)
void UI_popup_menu_end(struct bContext *C, struct uiPopupMenu *pup)
void uiTemplateAnyID(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *proptypename, const char *text)
#define UI_UNIT_X
@ UI_BTYPE_BUT
Definition: UI_interface.h:334
@ UI_BTYPE_NUM
Definition: UI_interface.h:341
@ UI_BTYPE_MENU
Definition: UI_interface.h:338
void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
uiPopupMenu * UI_popup_menu_begin(struct bContext *C, const char *title, int icon) ATTR_NONNULL()
#define NC_ANIMATION
Definition: WM_types.h:289
#define NC_SCENE
Definition: WM_types.h:279
#define ND_FRAME
Definition: WM_types.h:334
const bAnimChannelType * ANIM_channel_get_typeinfo(bAnimListElem *ale)
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
Definition: anim_filter.c:405
int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
#define SELECT
Scene scene
void ANIM_modifier_panels_register_graph_only(ARegionType *region_type, const char *modifier_panel_prefix, PanelTypePollFn poll_function)
Definition: fmodifier_ui.c:954
void ANIM_modifier_panels_register_graph_and_NLA(ARegionType *region_type, const char *modifier_panel_prefix, PanelTypePollFn poll_function)
Definition: fmodifier_ui.c:942
void ANIM_fmodifier_panels(const bContext *C, ID *owner_id, ListBase *fmodifiers, uiListPanelIDFromDataFunc panel_id_fn)
Definition: fmodifier_ui.c:900
uint col
static bool graph_panel_context(const bContext *C, bAnimListElem **ale, FCurve **fcu)
Definition: graph_buttons.c:75
static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *dvar)
#define B_FMODIFIER_REDRAW
static void driver_add_var_cb(bContext *C, void *driver_v, void *UNUSED(arg))
static void graph_panel_properties(const bContext *C, Panel *panel)
static void graph_panel_key_properties(const bContext *C, Panel *panel)
static void graph_draw_driver_settings_panel(uiLayout *layout, ID *id, FCurve *fcu, const bool is_popover)
static void graph_draw_driven_property_panel(uiLayout *layout, ID *id, FCurve *fcu)
static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar *dvar)
static void graphedit_activekey_left_handle_coord_cb(bContext *C, void *fcu_ptr, void *bezt_ptr)
static void graphedit_activekey_handles_cb(bContext *C, void *fcu_ptr, void *bezt_ptr)
#define B_IPO_DEPCHANGE
static bool graph_panel_drivers_poll(const bContext *C, PanelType *UNUSED(pt))
static void do_graph_region_driver_buttons(bContext *C, void *id_v, int event)
FCurve * ANIM_graph_context_fcurve(const bContext *C)
#define B_REDR
Definition: graph_buttons.c:71
static void graph_panel_cursor(const bContext *C, Panel *panel)
static void graphedit_activekey_update_cb(bContext *UNUSED(C), void *fcu_ptr, void *UNUSED(bezt_ptr))
void graph_buttons_register(ARegionType *art)
static bool graph_panel_poll(const bContext *C, PanelType *UNUSED(pt))
static void graph_panel_modifiers(const bContext *C, Panel *panel)
static void driver_delete_var_cb(bContext *C, void *driver_v, void *dvar_v)
static void graph_panel_driverVar__singleProp(uiLayout *layout, ID *id, DriverVar *dvar)
static void graph_panel_driven_property(const bContext *C, Panel *panel)
#define GRAPH_FMODIFIER_PANEL_PREFIX
static void graph_panel_cursor_header(const bContext *C, Panel *panel)
static bool get_active_fcurve_keyframe_edit(const FCurve *fcu, BezTriple **r_bezt, BezTriple **r_prevbezt)
static void driver_dvar_invalid_name_query_cb(bContext *C, void *dvar_v, void *UNUSED(arg))
static bool graph_panel_drivers_popover_poll(const bContext *C, PanelType *UNUSED(pt))
static void do_graph_region_modifier_buttons(bContext *C, void *UNUSED(arg), int event)
static void graph_fmodifier_panel_id(void *fcm_link, char *r_name)
static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *dvar)
static void graph_panel_drivers(const bContext *C, Panel *panel)
static void graph_panel_drivers_popover(const bContext *C, Panel *panel)
static void graphedit_activekey_right_handle_coord_cb(bContext *C, void *fcu_ptr, void *bezt_ptr)
static void driver_update_flags_cb(bContext *UNUSED(C), void *fcu_v, void *UNUSED(arg))
struct bAnimListElem * get_active_fcurve_channel(struct bAnimContext *ac)
Definition: graph_utils.c:104
#define GS(x)
Definition: iris.c:241
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
Definition: abc_util.cc:115
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:146
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:122
PropertySubType RNA_property_subtype(PropertyRNA *prop)
Definition: rna_access.c:1160
bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition: rna_access.c:5434
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
ListBase paneltypes
Definition: BKE_screen.h:216
bAction * action
bAction * tmpact
ListBase variables
char expression[256]
struct DriverVar * next
DriverTarget targets[8]
int color_mode
char * rna_path
FPoint * fpt
ChannelDriver * driver
BezTriple * bezt
short flag
ListBase modifiers
Definition: DNA_ID.h:273
char name[66]
Definition: DNA_ID.h:283
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
struct bPose * pose
void(* draw)(const struct bContext *C, struct Panel *panel)
Definition: BKE_screen.h:266
bool(* poll)(const struct bContext *C, struct PanelType *pt)
Definition: BKE_screen.h:260
void(* draw_header)(const struct bContext *C, struct Panel *panel)
Definition: BKE_screen.h:262
char idname[BKE_ST_MAXNAME]
Definition: BKE_screen.h:241
char translation_context[BKE_ST_MAXNAME]
Definition: BKE_screen.h:244
char category[BKE_ST_MAXNAME]
Definition: BKE_screen.h:246
char label[BKE_ST_MAXNAME]
Definition: BKE_screen.h:242
struct uiLayout * layout
struct ID * owner_id
Definition: RNA_types.h:50
void(* name)(bAnimListElem *ale, char *name)
Definition: ED_anim_api.h:554
struct ID * fcurve_owner_id
Definition: ED_anim_api.h:183
struct ID * id
Definition: ED_anim_api.h:168
#define G(x, y, z)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition: wm_files.c:3157
bool WM_paneltype_add(PanelType *pt)
Definition: wm_panel_type.c:58