Blender  V3.3
graph_buttons.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2009 Blender Foundation. All rights reserved. */
3 
10 #include <float.h>
11 #include <math.h>
12 #include <stdio.h>
13 #include <string.h>
14 
15 #include "DNA_anim_types.h"
16 #include "DNA_object_types.h"
17 #include "DNA_scene_types.h"
18 
19 #include "MEM_guardedalloc.h"
20 
21 #include "BLI_blenlib.h"
22 #include "BLI_math.h"
23 #include "BLI_utildefines.h"
24 
25 #include "BLT_translation.h"
26 
27 #include "BKE_anim_data.h"
28 #include "BKE_context.h"
29 #include "BKE_curve.h"
30 #include "BKE_fcurve.h"
31 #include "BKE_fcurve_driver.h"
32 #include "BKE_global.h"
33 #include "BKE_main.h"
34 #include "BKE_screen.h"
35 #include "BKE_unit.h"
36 
37 #include "DEG_depsgraph.h"
38 #include "DEG_depsgraph_build.h"
39 
40 #include "WM_api.h"
41 #include "WM_types.h"
42 
43 #include "RNA_access.h"
44 #include "RNA_path.h"
45 #include "RNA_prototypes.h"
46 
47 #include "ED_anim_api.h"
48 #include "ED_keyframing.h"
49 #include "ED_screen.h"
50 #include "ED_undo.h"
51 
52 #include "UI_interface.h"
53 #include "UI_resources.h"
54 
55 #include "graph_intern.h" /* own include */
56 
57 #define B_REDR 1
58 
59 /* -------------------------------------------------------------------- */
63 static bool graph_panel_context(const bContext *C, bAnimListElem **ale, FCurve **fcu)
64 {
65  bAnimContext ac;
66  bAnimListElem *elem = NULL;
67 
68  /* For now, only draw if we could init the anim-context info
69  * (necessary for all animation-related tools)
70  * to work correctly is able to be correctly retrieved.
71  * There's no point showing empty panels?
72  */
73  if (ANIM_animdata_get_context(C, &ac) == 0) {
74  return false;
75  }
76 
77  /* try to find 'active' F-Curve */
78  elem = get_active_fcurve_channel(&ac);
79  if (elem == NULL) {
80  return false;
81  }
82 
83  if (fcu) {
84  *fcu = (FCurve *)elem->data;
85  }
86  if (ale) {
87  *ale = elem;
88  }
89  else {
90  MEM_freeN(elem);
91  }
92 
93  return true;
94 }
95 
97 {
98  FCurve *fcu;
99  if (!graph_panel_context(C, NULL, &fcu)) {
100  return NULL;
101  }
102 
103  return fcu;
104 }
105 
106 static bool graph_panel_poll(const bContext *C, PanelType *UNUSED(pt))
107 {
108  return graph_panel_context(C, NULL, NULL);
109 }
110 
113 /* -------------------------------------------------------------------- */
117 static void graph_panel_cursor_header(const bContext *C, Panel *panel)
118 {
119  bScreen *screen = CTX_wm_screen(C);
122  PointerRNA spaceptr, sceneptr;
123  uiLayout *col;
124 
125  /* get RNA pointers for use when creating the UI elements */
126  RNA_id_pointer_create(&scene->id, &sceneptr);
127  RNA_pointer_create(&screen->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
128 
129  /* 2D-Cursor */
130  col = uiLayoutColumn(panel->layout, false);
131  uiItemR(col, &spaceptr, "show_cursor", 0, "", ICON_NONE);
132 }
133 
134 static void graph_panel_cursor(const bContext *C, Panel *panel)
135 {
136  bScreen *screen = CTX_wm_screen(C);
139  PointerRNA spaceptr, sceneptr;
140  uiLayout *layout = panel->layout;
141  uiLayout *col, *sub;
142 
143  /* get RNA pointers for use when creating the UI elements */
144  RNA_id_pointer_create(&scene->id, &sceneptr);
145  RNA_pointer_create(&screen->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
146 
147  uiLayoutSetPropSep(layout, true);
148  uiLayoutSetPropDecorate(layout, false);
149 
150  /* 2D-Cursor */
151  col = uiLayoutColumn(layout, false);
152  uiLayoutSetActive(col, RNA_boolean_get(&spaceptr, "show_cursor"));
153 
154  sub = uiLayoutColumn(col, true);
155  if (sipo->mode == SIPO_MODE_DRIVERS) {
156  uiItemR(sub, &spaceptr, "cursor_position_x", 0, IFACE_("Cursor X"), ICON_NONE);
157  }
158  else {
159  uiItemR(sub, &sceneptr, "frame_current", 0, IFACE_("Cursor X"), ICON_NONE);
160  }
161 
162  uiItemR(sub, &spaceptr, "cursor_position_y", 0, IFACE_("Y"), ICON_NONE);
163 
164  sub = uiLayoutColumn(col, true);
165  uiItemO(sub, IFACE_("Cursor to Selection"), ICON_NONE, "GRAPH_OT_frame_jump");
166  uiItemO(sub, IFACE_("Cursor Value to Selection"), ICON_NONE, "GRAPH_OT_snap_cursor_value");
167 }
168 
171 /* -------------------------------------------------------------------- */
175 static void graph_panel_properties(const bContext *C, Panel *panel)
176 {
177  bAnimListElem *ale;
178  FCurve *fcu;
179  PointerRNA fcu_ptr;
180  uiLayout *layout = panel->layout;
181  uiLayout *col;
182  char name[256];
183  int icon = 0;
184 
185  if (!graph_panel_context(C, &ale, &fcu)) {
186  return;
187  }
188 
189  /* F-Curve pointer */
190  RNA_pointer_create(ale->fcurve_owner_id, &RNA_FCurve, fcu, &fcu_ptr);
191 
192  /* user-friendly 'name' for F-Curve */
193  col = uiLayoutColumn(layout, false);
194  if (ale->type == ANIMTYPE_FCURVE) {
195  /* get user-friendly name for F-Curve */
196  icon = getname_anim_fcurve(name, ale->id, fcu);
197  }
198  else {
199  /* NLA Control Curve, etc. */
201 
202  /* get name */
203  if (acf && acf->name) {
204  acf->name(ale, name);
205  }
206  else {
207  strcpy(name, IFACE_("<invalid>"));
208  icon = ICON_ERROR;
209  }
210 
211  /* icon */
212  if (ale->type == ANIMTYPE_NLACURVE) {
213  icon = ICON_NLA;
214  }
215  }
216  uiItemL(col, name, icon);
217 
218  uiLayoutSetPropSep(layout, true);
219  uiLayoutSetPropDecorate(layout, false);
220 
221  /* RNA-Path Editing - only really should be enabled when things aren't working */
222  col = uiLayoutColumn(layout, false);
223  uiLayoutSetEnabled(col, (fcu->flag & FCURVE_DISABLED) != 0);
224  uiItemR(col, &fcu_ptr, "data_path", 0, "", ICON_RNA);
225  uiItemR(col, &fcu_ptr, "array_index", 0, NULL, ICON_NONE);
226 
227  /* color settings */
228  col = uiLayoutColumn(layout, true);
229  uiItemR(col, &fcu_ptr, "color_mode", 0, "Display Color", ICON_NONE);
230 
231  if (fcu->color_mode == FCURVE_COLOR_CUSTOM) {
232  uiItemR(col, &fcu_ptr, "color", 0, "Color", ICON_NONE);
233  }
234 
235  /* smoothing setting */
236  col = uiLayoutColumn(layout, true);
237  uiItemR(col, &fcu_ptr, "auto_smoothing", 0, "Handle Smoothing", ICON_NONE);
238 
239  MEM_freeN(ale);
240 }
241 
244 /* -------------------------------------------------------------------- */
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);
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, TIP_("F-Curve only has F-Modifiers"), ICON_NONE);
597  uiItemL(layout, TIP_("See Modifiers panel below"), ICON_INFO);
598  }
599  else if (fcu->fpt) {
600  /* samples only */
601  uiItemL(layout,
602  TIP_("F-Curve doesn't have any keyframes as it only contains sampled points"),
603  ICON_NONE);
604  }
605  else {
606  uiItemL(layout, TIP_("No active keyframe on F-Curve"), ICON_NONE);
607  }
608  }
609 
610  MEM_freeN(ale);
611 }
612 
615 /* -------------------------------------------------------------------- */
619 #define B_IPO_DEPCHANGE 10
620 
621 static void do_graph_region_driver_buttons(bContext *C, void *id_v, int event)
622 {
623  Main *bmain = CTX_data_main(C);
625 
626  switch (event) {
627  case B_IPO_DEPCHANGE: {
628  /* Was not actually run ever (NULL always passed as arg to this callback).
629  * If needed again, will need to check how to pass both fcurve and ID... :/ */
630 #if 0
631  /* force F-Curve & Driver to get re-evaluated (same as the old Update Dependencies) */
632  FCurve *fcu = (FCurve *)fcu_v;
633  ChannelDriver *driver = (fcu) ? fcu->driver : NULL;
634 
635  /* clear invalid flags */
636  if (fcu) {
637  fcu->flag &= ~FCURVE_DISABLED;
638  driver->flag &= ~DRIVER_FLAG_INVALID;
639  }
640 #endif
641  ID *id = id_v;
642  AnimData *adt = BKE_animdata_from_id(id);
643 
644  /* rebuild depsgraph for the new deps, and ensure COW copies get flushed. */
647  if (adt != NULL) {
648  if (adt->action != NULL) {
650  }
651  if (adt->tmpact != NULL) {
653  }
654  }
655 
656  break;
657  }
658  }
659 
660  /* default for now */
661  WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); /* XXX could use better notifier */
662 }
663 
664 /* callback to add a target variable to the active driver */
665 static void driver_add_var_cb(bContext *C, void *driver_v, void *UNUSED(arg))
666 {
667  ChannelDriver *driver = (ChannelDriver *)driver_v;
668 
669  /* add a new variable */
670  driver_add_new_variable(driver);
671  ED_undo_push(C, "Add Driver Variable");
672 }
673 
674 /* callback to remove target variable from active driver */
675 static void driver_delete_var_cb(bContext *C, void *driver_v, void *dvar_v)
676 {
677  ChannelDriver *driver = (ChannelDriver *)driver_v;
678  DriverVar *dvar = (DriverVar *)dvar_v;
679 
680  /* remove the active variable */
681  driver_free_variable_ex(driver, dvar);
682  ED_undo_push(C, "Delete Driver Variable");
683 }
684 
685 /* callback to report why a driver variable is invalid */
686 static void driver_dvar_invalid_name_query_cb(bContext *C, void *dvar_v, void *UNUSED(arg))
687 {
689  C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Invalid Variable Name"), ICON_NONE);
690  uiLayout *layout = UI_popup_menu_layout(pup);
691 
692  DriverVar *dvar = (DriverVar *)dvar_v;
693 
694  if (dvar->flag & DVAR_FLAG_INVALID_EMPTY) {
695  uiItemL(layout, TIP_("It cannot be left blank"), ICON_ERROR);
696  }
697  if (dvar->flag & DVAR_FLAG_INVALID_START_NUM) {
698  uiItemL(layout, TIP_("It cannot start with a number"), ICON_ERROR);
699  }
700  if (dvar->flag & DVAR_FLAG_INVALID_START_CHAR) {
701  uiItemL(layout,
702  TIP_("It cannot start with a special character,"
703  " including '$', '@', '!', '~', '+', '-', '_', '.', or ' '"),
704  ICON_NONE);
705  }
706  if (dvar->flag & DVAR_FLAG_INVALID_HAS_SPACE) {
707  uiItemL(layout, TIP_("It cannot contain spaces (e.g. 'a space')"), ICON_ERROR);
708  }
709  if (dvar->flag & DVAR_FLAG_INVALID_HAS_DOT) {
710  uiItemL(layout, TIP_("It cannot contain dots (e.g. 'a.dot')"), ICON_ERROR);
711  }
712  if (dvar->flag & DVAR_FLAG_INVALID_HAS_SPECIAL) {
713  uiItemL(layout,
714  TIP_("It cannot contain special (non-alphabetical/numeric) characters"),
715  ICON_ERROR);
716  }
717  if (dvar->flag & DVAR_FLAG_INVALID_PY_KEYWORD) {
718  uiItemL(layout, TIP_("It cannot be a reserved keyword in Python"), ICON_INFO);
719  }
720 
721  UI_popup_menu_end(C, pup);
722 }
723 
724 /* callback to reset the driver's flags */
725 static void driver_update_flags_cb(bContext *UNUSED(C), void *fcu_v, void *UNUSED(arg))
726 {
727  FCurve *fcu = (FCurve *)fcu_v;
728  ChannelDriver *driver = fcu->driver;
729 
730  /* clear invalid flags */
731  fcu->flag &= ~FCURVE_DISABLED;
732  driver->flag &= ~DRIVER_FLAG_INVALID;
733 }
734 
735 /* drivers panel poll */
737 {
739 
740  if (sipo->mode != SIPO_MODE_DRIVERS) {
741  return false;
742  }
743 
744  return graph_panel_context(C, NULL, NULL);
745 }
746 
747 /* settings for 'single property' driver variable type */
748 static void graph_panel_driverVar__singleProp(uiLayout *layout, ID *id, DriverVar *dvar)
749 {
750  DriverTarget *dtar = &dvar->targets[0];
751  PointerRNA dtar_ptr;
752  uiLayout *row, *col;
753 
754  /* initialize RNA pointer to the target */
755  RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
756 
757  /* Target ID */
758  row = uiLayoutRow(layout, false);
759  uiLayoutSetRedAlert(row, ((dtar->flag & DTAR_FLAG_INVALID) && !dtar->id));
760  uiTemplateAnyID(row, &dtar_ptr, "id", "id_type", IFACE_("Prop:"));
761 
762  /* Target Property */
763  if (dtar->id) {
764  PointerRNA root_ptr;
765 
766  /* get pointer for resolving the property selected */
767  RNA_id_pointer_create(dtar->id, &root_ptr);
768 
769  /* rna path */
770  col = uiLayoutColumn(layout, true);
772  uiTemplatePathBuilder(col, &dtar_ptr, "data_path", &root_ptr, IFACE_("Path"));
773  }
774 }
775 
776 /* settings for 'rotation difference' driver variable type */
777 /* FIXME: 1) Must be same armature for both dtars, 2) Alignment issues... */
778 static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *dvar)
779 {
780  DriverTarget *dtar = &dvar->targets[0];
781  DriverTarget *dtar2 = &dvar->targets[1];
782  Object *ob1 = (Object *)dtar->id;
783  Object *ob2 = (Object *)dtar2->id;
784  PointerRNA dtar_ptr, dtar2_ptr;
785  uiLayout *col;
786 
787  /* initialize RNA pointer to the target */
788  RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
789  RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr);
790 
791  /* Object 1 */
792  col = uiLayoutColumn(layout, true);
793  uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
794  uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Object 1"), ICON_NONE);
795 
796  if (dtar->id && GS(dtar->id->name) == ID_OB && ob1->pose) {
797  PointerRNA tar_ptr;
798 
799  RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
800  uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
801  }
802 
803  /* Object 2 */
804  col = uiLayoutColumn(layout, true);
805  uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
806  uiItemR(col, &dtar2_ptr, "id", 0, IFACE_("Object 2"), ICON_NONE);
807 
808  if (dtar2->id && GS(dtar2->id->name) == ID_OB && ob2->pose) {
809  PointerRNA tar_ptr;
810 
811  RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
812  uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
813  }
814 }
815 
816 /* settings for 'location difference' driver variable type */
817 static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *dvar)
818 {
819  DriverTarget *dtar = &dvar->targets[0];
820  DriverTarget *dtar2 = &dvar->targets[1];
821  Object *ob1 = (Object *)dtar->id;
822  Object *ob2 = (Object *)dtar2->id;
823  PointerRNA dtar_ptr, dtar2_ptr;
824  uiLayout *col;
825 
826  /* initialize RNA pointer to the target */
827  RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
828  RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr);
829 
830  /* Object 1 */
831  col = uiLayoutColumn(layout, true);
832  uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
833  uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Object 1"), ICON_NONE);
834 
835  if (dtar->id && GS(dtar->id->name) == ID_OB && ob1->pose) {
836  PointerRNA tar_ptr;
837 
838  RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
840  col, &dtar_ptr, "bone_target", &tar_ptr, "bones", IFACE_("Bone"), ICON_BONE_DATA);
841  }
842 
843  /* we can clear it again now - it's only needed when creating the ID/Bone fields */
844  uiLayoutSetRedAlert(col, false);
845 
846  uiItemR(col, &dtar_ptr, "transform_space", 0, NULL, ICON_NONE);
847 
848  /* Object 2 */
849  col = uiLayoutColumn(layout, true);
850  uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
851  uiItemR(col, &dtar2_ptr, "id", 0, IFACE_("Object 2"), ICON_NONE);
852 
853  if (dtar2->id && GS(dtar2->id->name) == ID_OB && ob2->pose) {
854  PointerRNA tar_ptr;
855 
856  RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
858  col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", IFACE_("Bone"), ICON_BONE_DATA);
859  }
860 
861  /* we can clear it again now - it's only needed when creating the ID/Bone fields */
862  uiLayoutSetRedAlert(col, false);
863 
864  uiItemR(col, &dtar2_ptr, "transform_space", 0, NULL, ICON_NONE);
865 }
866 
867 /* settings for 'transform channel' driver variable type */
868 static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar *dvar)
869 {
870  DriverTarget *dtar = &dvar->targets[0];
871  Object *ob = (Object *)dtar->id;
872  PointerRNA dtar_ptr;
873  uiLayout *col, *sub;
874 
875  /* initialize RNA pointer to the target */
876  RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
877 
878  /* properties */
879  col = uiLayoutColumn(layout, true);
880  uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
881  uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Object"), ICON_NONE);
882 
883  if (dtar->id && GS(dtar->id->name) == ID_OB && ob->pose) {
884  PointerRNA tar_ptr;
885 
886  RNA_pointer_create(dtar->id, &RNA_Pose, ob->pose, &tar_ptr);
888  col, &dtar_ptr, "bone_target", &tar_ptr, "bones", IFACE_("Bone"), ICON_BONE_DATA);
889  }
890 
891  sub = uiLayoutColumn(layout, true);
892  uiItemR(sub, &dtar_ptr, "transform_type", 0, NULL, ICON_NONE);
893 
894  if (ELEM(dtar->transChan,
899  uiItemR(sub, &dtar_ptr, "rotation_mode", 0, IFACE_("Mode"), ICON_NONE);
900  }
901 
902  uiItemR(sub, &dtar_ptr, "transform_space", 0, IFACE_("Space"), ICON_NONE);
903 }
904 
905 /* ----------------------------------------------------------------- */
906 
907 /* property driven by the driver - duplicates Active FCurve, but useful for clarity */
908 static void graph_draw_driven_property_panel(uiLayout *layout, ID *id, FCurve *fcu)
909 {
910  PointerRNA fcu_ptr;
911  uiLayout *row;
912  char name[256];
913  int icon = 0;
914 
915  /* F-Curve pointer */
916  RNA_pointer_create(id, &RNA_FCurve, fcu, &fcu_ptr);
917 
918  /* get user-friendly 'name' for F-Curve */
919  icon = getname_anim_fcurve(name, id, fcu);
920 
921  /* panel layout... */
922  row = uiLayoutRow(layout, true);
924 
925  /* -> user friendly 'name' for datablock that owns F-Curve */
926  /* XXX: Actually, we may need the datablock icons only...
927  * (e.g. right now will show bone for bone props). */
928  uiItemL(row, id->name + 2, icon);
929 
930  /* -> user friendly 'name' for F-Curve/driver target */
931  uiItemL(row, "", ICON_RIGHTARROW);
932  uiItemL(row, name, ICON_RNA);
933 }
934 
935 /* UI properties panel layout for driver settings - shared for Drivers Editor and for */
937  ID *id,
938  FCurve *fcu,
939  const bool is_popover)
940 {
941  ChannelDriver *driver = fcu->driver;
942  DriverVar *dvar;
943 
944  PointerRNA driver_ptr;
945  uiLayout *col, *row, *row_outer;
946  uiBlock *block;
947  uiBut *but;
948 
949  /* set event handler for panel */
950  block = uiLayoutGetBlock(layout);
952 
953  /* driver-level settings - type, expressions, and errors */
954  RNA_pointer_create(id, &RNA_Driver, driver, &driver_ptr);
955 
956  col = uiLayoutColumn(layout, true);
957  block = uiLayoutGetBlock(col);
958  uiItemR(col, &driver_ptr, "type", 0, NULL, ICON_NONE);
959 
960  {
961  char valBuf[32];
962 
963  /* value of driver */
964  row = uiLayoutRow(col, true);
965  uiItemL(row, IFACE_("Driver Value:"), ICON_NONE);
966  BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", driver->curval);
967  uiItemL(row, valBuf, ICON_NONE);
968  }
969 
970  uiItemS(layout);
971  uiItemS(layout);
972 
973  /* show expression box if doing scripted drivers,
974  * and/or error messages when invalid drivers exist */
975  if (driver->type == DRIVER_TYPE_PYTHON) {
976  bool bpy_data_expr_error = (strstr(driver->expression, "bpy.data.") != NULL);
977  bool bpy_ctx_expr_error = (strstr(driver->expression, "bpy.context.") != NULL);
978 
979  /* expression */
980  /* TODO: "Show syntax hints" button */
981  col = uiLayoutColumn(layout, true);
982  block = uiLayoutGetBlock(col);
983 
984  uiItemL(col, IFACE_("Expression:"), ICON_NONE);
985  uiItemR(col, &driver_ptr, "expression", 0, "", ICON_NONE);
986  uiItemR(col, &driver_ptr, "use_self", 0, NULL, ICON_NONE);
987 
988  /* errors? */
989  col = uiLayoutColumn(layout, true);
990  block = uiLayoutGetBlock(col);
991 
992  if (driver->flag & DRIVER_FLAG_INVALID) {
993  uiItemL(col, TIP_("ERROR: Invalid Python expression"), ICON_CANCEL);
994  }
995  else if (!BKE_driver_has_simple_expression(driver)) {
996  if ((G.f & G_FLAG_SCRIPT_AUTOEXEC) == 0) {
997  /* TODO: Add button to enable? */
998  uiItemL(col, TIP_("Python restricted for security"), ICON_ERROR);
999  }
1000  else {
1001  uiItemL(col, TIP_("Slow Python expression"), ICON_INFO);
1002  }
1003  }
1004 
1005  /* Explicit bpy-references are evil. Warn about these to prevent errors */
1006  /* TODO: put these in a box? */
1007  if (bpy_data_expr_error || bpy_ctx_expr_error) {
1008  uiItemL(col, TIP_("WARNING: Driver expression may not work correctly"), ICON_HELP);
1009 
1010  if (bpy_data_expr_error) {
1011  uiItemL(col, TIP_("TIP: Use variables instead of bpy.data paths (see below)"), ICON_ERROR);
1012  }
1013  if (bpy_ctx_expr_error) {
1014  uiItemL(col, TIP_("TIP: bpy.context is not safe for renderfarm usage"), ICON_ERROR);
1015  }
1016  }
1017  }
1018  else {
1019  /* errors? */
1020  col = uiLayoutColumn(layout, true);
1021  block = uiLayoutGetBlock(col);
1022 
1023  if (driver->flag & DRIVER_FLAG_INVALID) {
1024  uiItemL(col, TIP_("ERROR: Invalid target channel(s)"), ICON_ERROR);
1025  }
1026 
1027  /* Warnings about a lack of variables
1028  * NOTE: The lack of variables is generally a bad thing, since it indicates
1029  * that the driver doesn't work at all. This particular scenario arises
1030  * primarily when users mistakenly try to use drivers for procedural
1031  * property animation
1032  */
1033  if (BLI_listbase_is_empty(&driver->variables)) {
1034  uiItemL(col, TIP_("ERROR: Driver is useless without any inputs"), ICON_ERROR);
1035 
1036  if (!BLI_listbase_is_empty(&fcu->modifiers)) {
1037  uiItemL(col, TIP_("TIP: Use F-Curves for procedural animation instead"), ICON_INFO);
1038  uiItemL(col, TIP_("F-Modifiers can generate curves for those too"), ICON_INFO);
1039  }
1040  }
1041  }
1042 
1043  uiItemS(layout);
1044 
1045  /* add/copy/paste driver variables */
1046  row_outer = uiLayoutRow(layout, false);
1047 
1048  /* add driver variable - add blank */
1049  row = uiLayoutRow(row_outer, true);
1050  block = uiLayoutGetBlock(row);
1051  but = uiDefIconTextBut(
1052  block,
1053  UI_BTYPE_BUT,
1055  ICON_ADD,
1056  IFACE_("Add Input Variable"),
1057  0,
1058  0,
1059  10 * UI_UNIT_X,
1060  UI_UNIT_Y,
1061  NULL,
1062  0.0,
1063  0.0,
1064  0,
1065  0,
1066  TIP_("Add a Driver Variable to keep track of an input used by the driver"));
1067  UI_but_func_set(but, driver_add_var_cb, driver, NULL);
1068 
1069  if (is_popover) {
1070  /* add driver variable - add using eyedropper */
1071  /* XXX: will this operator work like this? */
1072  uiItemO(row, "", ICON_EYEDROPPER, "UI_OT_eyedropper_driver");
1073  }
1074 
1075  /* copy/paste (as sub-row) */
1076  row = uiLayoutRow(row_outer, true);
1077  block = uiLayoutGetBlock(row);
1078 
1079  uiItemO(row, "", ICON_COPYDOWN, "GRAPH_OT_driver_variables_copy");
1080  uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_driver_variables_paste");
1081 
1082  /* loop over targets, drawing them */
1083  for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
1084  PointerRNA dvar_ptr;
1085  uiLayout *box;
1086  uiLayout *subrow, *sub;
1087 
1088  /* sub-layout column for this variable's settings */
1089  col = uiLayoutColumn(layout, true);
1090 
1091  /* 1) header panel */
1092  box = uiLayoutBox(col);
1093  RNA_pointer_create(id, &RNA_DriverVariable, dvar, &dvar_ptr);
1094 
1095  row = uiLayoutRow(box, false);
1096  block = uiLayoutGetBlock(row);
1097 
1098  /* 1.1) variable type and name */
1099  subrow = uiLayoutRow(row, true);
1100 
1101  /* 1.1.1) variable type */
1102 
1103  /* HACK: special group just for the enum,
1104  * otherwise we get ugly layout with text included too... */
1105  sub = uiLayoutRow(subrow, true);
1106 
1108 
1109  uiItemR(sub, &dvar_ptr, "type", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
1110 
1111  /* 1.1.2) variable name */
1112 
1113  /* HACK: special group to counteract the effects of the previous enum,
1114  * which now pushes everything too far right */
1115  sub = uiLayoutRow(subrow, true);
1116 
1118 
1119  uiItemR(sub, &dvar_ptr, "name", 0, "", ICON_NONE);
1120 
1121  /* 1.2) invalid name? */
1123 
1124  if (dvar->flag & DVAR_FLAG_INVALID_NAME) {
1125  but = uiDefIconBut(block,
1126  UI_BTYPE_BUT,
1128  ICON_ERROR,
1129  290,
1130  0,
1131  UI_UNIT_X,
1132  UI_UNIT_Y,
1133  NULL,
1134  0.0,
1135  0.0,
1136  0.0,
1137  0.0,
1138  TIP_("Invalid variable name, click here for details"));
1139  UI_but_func_set(but, driver_dvar_invalid_name_query_cb, dvar, NULL); /* XXX: reports? */
1140  }
1141 
1142  /* 1.3) remove button */
1143  but = uiDefIconBut(block,
1144  UI_BTYPE_BUT,
1146  ICON_X,
1147  290,
1148  0,
1149  UI_UNIT_X,
1150  UI_UNIT_Y,
1151  NULL,
1152  0.0,
1153  0.0,
1154  0.0,
1155  0.0,
1156  TIP_("Delete target variable"));
1157  UI_but_func_set(but, driver_delete_var_cb, driver, dvar);
1159 
1160  /* 2) variable type settings */
1161  box = uiLayoutBox(col);
1162  /* controls to draw depends on the type of variable */
1163  switch (dvar->type) {
1164  case DVAR_TYPE_SINGLE_PROP: /* single property */
1165  graph_panel_driverVar__singleProp(box, id, dvar);
1166  break;
1167  case DVAR_TYPE_ROT_DIFF: /* rotational difference */
1168  graph_panel_driverVar__rotDiff(box, id, dvar);
1169  break;
1170  case DVAR_TYPE_LOC_DIFF: /* location difference */
1171  graph_panel_driverVar__locDiff(box, id, dvar);
1172  break;
1173  case DVAR_TYPE_TRANSFORM_CHAN: /* transform channel */
1174  graph_panel_driverVar__transChan(box, id, dvar);
1175  break;
1176  }
1177 
1178  /* 3) value of variable */
1179  {
1180  char valBuf[32];
1181 
1182  box = uiLayoutBox(col);
1183  row = uiLayoutRow(box, true);
1184  uiItemL(row, IFACE_("Value:"), ICON_NONE);
1185 
1186  if ((dvar->type == DVAR_TYPE_ROT_DIFF) ||
1187  (dvar->type == DVAR_TYPE_TRANSFORM_CHAN &&
1188  ELEM(dvar->targets[0].transChan,
1194  BLI_snprintf(
1195  valBuf, sizeof(valBuf), "%.3f (%4.1f°)", dvar->curval, RAD2DEGF(dvar->curval));
1196  }
1197  else {
1198  BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", dvar->curval);
1199  }
1200 
1201  uiItemL(row, valBuf, ICON_NONE);
1202  }
1203  }
1204 
1205  uiItemS(layout);
1206  uiItemS(layout);
1207 
1208  /* XXX: This should become redundant. But sometimes the flushing fails,
1209  * so keep this around for a while longer as a "last resort" */
1210  row = uiLayoutRow(layout, true);
1211  block = uiLayoutGetBlock(row);
1212  but = uiDefIconTextBut(
1213  block,
1214  UI_BTYPE_BUT,
1216  ICON_FILE_REFRESH,
1217  IFACE_("Update Dependencies"),
1218  0,
1219  0,
1220  10 * UI_UNIT_X,
1221  UI_UNIT_Y,
1222  NULL,
1223  0.0,
1224  0.0,
1225  0,
1226  0,
1227  TIP_("Force updates of dependencies - Only use this if drivers are not updating correctly"));
1229 }
1230 
1231 /* ----------------------------------------------------------------- */
1232 
1233 /* Panel to show property driven by the driver (in Drivers Editor) - duplicates Active FCurve,
1234  * but useful for clarity. */
1235 static void graph_panel_driven_property(const bContext *C, Panel *panel)
1236 {
1237  bAnimListElem *ale;
1238  FCurve *fcu;
1239 
1240  if (!graph_panel_context(C, &ale, &fcu)) {
1241  return;
1242  }
1243 
1244  graph_draw_driven_property_panel(panel->layout, ale->id, fcu);
1245 
1246  MEM_freeN(ale);
1247 }
1248 
1249 /* driver settings for active F-Curve
1250  * (only for 'Drivers' mode in Graph Editor, i.e. the full "Drivers Editor") */
1251 static void graph_panel_drivers(const bContext *C, Panel *panel)
1252 {
1253  bAnimListElem *ale;
1254  FCurve *fcu;
1255 
1256  /* Get settings from context */
1257  if (!graph_panel_context(C, &ale, &fcu)) {
1258  return;
1259  }
1260 
1261  graph_draw_driver_settings_panel(panel->layout, ale->id, fcu, false);
1262 
1263  /* cleanup */
1264  MEM_freeN(ale);
1265 }
1266 
1267 /* ----------------------------------------------------------------- */
1268 
1269 /* Poll to make this not show up in the graph editor,
1270  * as this is only to be used as a popup elsewhere. */
1272 {
1273  return ED_operator_graphedit_active((bContext *)C) == false;
1274 }
1275 
1276 /* popover panel for driver editing anywhere in ui */
1277 static void graph_panel_drivers_popover(const bContext *C, Panel *panel)
1278 {
1279  uiLayout *layout = panel->layout;
1280 
1281  PointerRNA ptr = {NULL};
1282  PropertyRNA *prop = NULL;
1283  int index = -1;
1284  uiBut *but = NULL;
1285 
1286  /* Get active property to show driver properties for */
1287  but = UI_context_active_but_prop_get((bContext *)C, &ptr, &prop, &index);
1288  if (but) {
1289  FCurve *fcu;
1290  bool driven, special;
1291 
1293  (bContext *)C, &ptr, prop, index, NULL, NULL, &driven, &special);
1294 
1295  /* Hack: Force all buttons in this panel to be able to know the driver button
1296  * this panel is getting spawned from, so that things like the "Open Drivers Editor"
1297  * button will work.
1298  */
1299  uiLayoutSetContextFromBut(layout, but);
1300 
1301  /* Populate Panel - With a combination of the contents of the Driven and Driver panels */
1302  if (fcu && fcu->driver) {
1303  ID *id = ptr.owner_id;
1304 
1305  PointerRNA ptr_fcurve;
1306  RNA_pointer_create(id, &RNA_FCurve, fcu, &ptr_fcurve);
1307  uiLayoutSetContextPointer(layout, "active_editable_fcurve", &ptr_fcurve);
1308 
1309  /* Driven Property Settings */
1310  uiItemL(layout, IFACE_("Driven Property:"), ICON_NONE);
1311  graph_draw_driven_property_panel(panel->layout, id, fcu);
1312  /* TODO: All vs Single */
1313 
1314  uiItemS(layout);
1315  uiItemS(layout);
1316 
1317  /* Drivers Settings */
1318  uiItemL(layout, IFACE_("Driver Settings:"), ICON_NONE);
1319  graph_draw_driver_settings_panel(panel->layout, id, fcu, true);
1320  }
1321  }
1322 
1323  /* Show drivers editor is always visible */
1324  uiItemO(layout, IFACE_("Show in Drivers Editor"), ICON_DRIVER, "SCREEN_OT_drivers_editor_show");
1325 }
1326 
1329 /* -------------------------------------------------------------------- */
1335 #define B_FMODIFIER_REDRAW 20
1337 #define GRAPH_FMODIFIER_PANEL_PREFIX "GRAPH"
1338 
1339 static void graph_fmodifier_panel_id(void *fcm_link, char *r_name)
1340 {
1341  FModifier *fcm = (FModifier *)fcm_link;
1342  eFModifier_Types type = fcm->type;
1344  BLI_snprintf(r_name, BKE_ST_MAXNAME, "%s_PT_%s", GRAPH_FMODIFIER_PANEL_PREFIX, fmi->name);
1345 }
1346 
1347 static void do_graph_region_modifier_buttons(bContext *C, void *UNUSED(arg), int event)
1348 {
1349  switch (event) {
1350  case B_FMODIFIER_REDRAW: /* XXX this should send depsgraph updates too */
1351  /* XXX: need a notifier specially for F-Modifiers */
1353  break;
1354  }
1355 }
1356 
1357 static void graph_panel_modifiers(const bContext *C, Panel *panel)
1358 {
1359  bAnimListElem *ale;
1360  FCurve *fcu;
1361  uiLayout *row;
1362  uiBlock *block;
1363 
1364  if (!graph_panel_context(C, &ale, &fcu)) {
1365  return;
1366  }
1367 
1368  block = uiLayoutGetBlock(panel->layout);
1370 
1371  /* 'add modifier' button at top of panel */
1372  {
1373  row = uiLayoutRow(panel->layout, false);
1374 
1375  /* this is an operator button which calls a 'add modifier' operator...
1376  * a menu might be nicer but would be tricky as we need some custom filtering
1377  */
1379  row, (bContext *)C, "GRAPH_OT_fmodifier_add", "type", IFACE_("Add Modifier"), ICON_NONE);
1380 
1381  /* copy/paste (as sub-row) */
1382  row = uiLayoutRow(row, true);
1383  uiItemO(row, "", ICON_COPYDOWN, "GRAPH_OT_fmodifier_copy");
1384  uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_fmodifier_paste");
1385  }
1386 
1388 
1389  MEM_freeN(ale);
1390 }
1391 
1394 /* -------------------------------------------------------------------- */
1399 {
1400  PanelType *pt;
1401 
1402  pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
1403  strcpy(pt->idname, "GRAPH_PT_properties");
1404  strcpy(pt->label, N_("Active F-Curve"));
1405  strcpy(pt->category, "F-Curve");
1408  pt->poll = graph_panel_poll;
1409  BLI_addtail(&art->paneltypes, pt);
1410 
1411  pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
1412  strcpy(pt->idname, "GRAPH_PT_key_properties");
1413  strcpy(pt->label, N_("Active Keyframe"));
1414  strcpy(pt->category, "F-Curve");
1417  pt->poll = graph_panel_poll;
1418  BLI_addtail(&art->paneltypes, pt);
1419 
1420  pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers driven");
1421  strcpy(pt->idname, "GRAPH_PT_driven_property");
1422  strcpy(pt->label, N_("Driven Property"));
1423  strcpy(pt->category, "Drivers");
1427  BLI_addtail(&art->paneltypes, pt);
1428 
1429  pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers");
1430  strcpy(pt->idname, "GRAPH_PT_drivers");
1431  strcpy(pt->label, N_("Driver"));
1432  strcpy(pt->category, "Drivers");
1434  pt->draw = graph_panel_drivers;
1436  BLI_addtail(&art->paneltypes, pt);
1437 
1438  pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers popover");
1439  strcpy(pt->idname, "GRAPH_PT_drivers_popover");
1440  strcpy(pt->label, N_("Add/Edit Driver"));
1441  strcpy(pt->category, "Drivers");
1445  BLI_addtail(&art->paneltypes, pt);
1446  /* This panel isn't used in this region.
1447  * Add explicitly to global list (so popovers work). */
1448  WM_paneltype_add(pt);
1449 
1450  pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel modifiers");
1451  strcpy(pt->idname, "GRAPH_PT_modifiers");
1452  strcpy(pt->label, N_("Modifiers"));
1453  strcpy(pt->category, "Modifiers");
1455  pt->flag = PANEL_TYPE_NO_HEADER;
1457  pt->poll = graph_panel_poll;
1458  BLI_addtail(&art->paneltypes, pt);
1459 
1462 
1463  pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel view");
1464  strcpy(pt->idname, "GRAPH_PT_view");
1465  strcpy(pt->label, N_("Show Cursor"));
1466  strcpy(pt->category, "View");
1468  pt->draw = graph_panel_cursor;
1470  BLI_addtail(&art->paneltypes, pt);
1471 }
1472 
struct AnimData * BKE_animdata_from_id(const struct ID *id)
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct SpaceGraph * CTX_wm_space_graph(const bContext *C)
Definition: context.c:887
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:733
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
void BKE_nurb_bezt_handle_test(struct BezTriple *bezt, eBezTriple_Flag__Alias sel_flag, bool use_handle, bool use_around_local)
Definition: curve.cc:4049
struct FCurve * BKE_fcurve_find_by_rna_context_ui(struct bContext *C, const struct PointerRNA *ptr, struct PropertyRNA *prop, int rnaindex, struct AnimData **r_animdata, struct bAction **r_action, bool *r_driven, bool *r_special)
const FModifierTypeInfo * get_fmodifier_typeinfo(int type)
Definition: fmodifier.c:1052
void sort_time_fcurve(struct FCurve *fcu)
Definition: fcurve.c:1327
void BKE_fcurve_handles_recalc(struct FCurve *fcu)
Definition: fcurve.c:1303
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:154
@ PANEL_TYPE_NO_HEADER
Definition: BKE_screen.h:280
#define BKE_ST_MAXNAME
Definition: BKE_screen.h:53
@ B_UNIT_NONE
Definition: BKE_unit.h:100
#define BLI_assert(a)
Definition: BLI_assert.h:46
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
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
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:834
@ ID_OB
Definition: DNA_ID_enums.h:47
@ 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:202
@ ANIMTYPE_FCURVE
Definition: ED_anim_api.h:199
bool ED_operator_graphedit_active(struct bContext *C)
Definition: screen_ops.c:329
void ED_undo_push(struct bContext *C, const char *str)
Definition: ed_undo.c:100
_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.
#define RNA_SUBTYPE_UNIT(subtype)
Definition: RNA_types.h:111
#define C
Definition: RandGen.cpp:25
@ UI_LAYOUT_ALIGN_LEFT
@ UI_LAYOUT_ALIGN_EXPAND
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.cc:5623
#define UI_UNIT_Y
void uiLayoutSetActive(uiLayout *layout, bool active)
uiBlock * uiLayoutGetBlock(uiLayout *layout)
@ UI_EMBOSS_NONE
Definition: UI_interface.h:109
@ UI_EMBOSS
Definition: UI_interface.h:108
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.cc:5336
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.cc:5953
void uiItemS(uiLayout *layout)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
@ UI_ITEM_R_ICON_ONLY
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.cc:5258
void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss)
Definition: interface.cc:3629
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.cc:6000
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:330
@ UI_BTYPE_NUM
Definition: UI_interface.h:337
@ UI_BTYPE_MENU
Definition: UI_interface.h:334
void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
void UI_but_unit_type_set(uiBut *but, int unit_type)
Definition: interface.cc:5934
uiPopupMenu * UI_popup_menu_begin(struct bContext *C, const char *title, int icon) ATTR_NONNULL()
#define NC_ANIMATION
Definition: WM_types.h:338
#define NC_SCENE
Definition: WM_types.h:328
#define ND_FRAME
Definition: WM_types.h:382
const bAnimChannelType * ANIM_channel_get_typeinfo(bAnimListElem *ale)
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
Definition: anim_filter.c:379
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:933
void ANIM_modifier_panels_register_graph_and_NLA(ARegionType *region_type, const char *modifier_panel_prefix, PanelTypePollFn poll_function)
Definition: fmodifier_ui.c:921
void ANIM_fmodifier_panels(const bContext *C, ID *owner_id, ListBase *fmodifiers, uiListPanelIDFromDataFunc panel_id_fn)
Definition: fmodifier_ui.c:879
uint col
static bool graph_panel_context(const bContext *C, bAnimListElem **ale, FCurve **fcu)
Definition: graph_buttons.c:63
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)
Definition: graph_buttons.c:96
#define B_REDR
Definition: graph_buttons.c:57
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:81
#define GS(x)
Definition: iris.c:225
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
#define G(x, y, z)
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
Definition: abc_util.cc:92
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:136
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:112
PropertySubType RNA_property_subtype(PropertyRNA *prop)
Definition: rna_access.c:1015
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition: rna_path.cc:531
ListBase paneltypes
Definition: BKE_screen.h:198
bAction * action
bAction * tmpact
uint8_t h1
uint8_t f3
uint8_t f1
uint8_t h2
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:368
char name[66]
Definition: DNA_ID.h:378
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
struct bPose * pose
void(* draw)(const struct bContext *C, struct Panel *panel)
Definition: BKE_screen.h:248
bool(* poll)(const struct bContext *C, struct PanelType *pt)
Definition: BKE_screen.h:242
void(* draw_header)(const struct bContext *C, struct Panel *panel)
Definition: BKE_screen.h:244
char idname[BKE_ST_MAXNAME]
Definition: BKE_screen.h:223
char translation_context[BKE_ST_MAXNAME]
Definition: BKE_screen.h:226
char category[BKE_ST_MAXNAME]
Definition: BKE_screen.h:228
char label[BKE_ST_MAXNAME]
Definition: BKE_screen.h:224
struct uiLayout * layout
struct ID * owner_id
Definition: RNA_types.h:36
void(* name)(bAnimListElem *ale, char *name)
Definition: ED_anim_api.h:596
struct ID * fcurve_owner_id
Definition: ED_anim_api.h:175
struct ID * id
Definition: ED_anim_api.h:160
#define N_(msgid)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition: wm_files.c:3480
bool WM_paneltype_add(PanelType *pt)
Definition: wm_panel_type.c:44