Blender  V3.3
anim_channels_edit.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2009 Blender Foundation, Joshua Leung. All rights reserved. */
3 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include "MEM_guardedalloc.h"
13 
14 #include "BLI_blenlib.h"
15 #include "BLI_listbase.h"
16 #include "BLI_utildefines.h"
17 
18 #include "DNA_anim_types.h"
19 #include "DNA_gpencil_types.h"
20 #include "DNA_key_types.h"
21 #include "DNA_mask_types.h"
22 #include "DNA_object_types.h"
23 #include "DNA_scene_types.h"
24 
25 #include "RNA_access.h"
26 #include "RNA_define.h"
27 
28 #include "BKE_action.h"
29 #include "BKE_anim_data.h"
30 #include "BKE_context.h"
31 #include "BKE_fcurve.h"
32 #include "BKE_global.h"
33 #include "BKE_gpencil.h"
34 #include "BKE_lib_id.h"
35 #include "BKE_main.h"
36 #include "BKE_mask.h"
37 #include "BKE_nla.h"
38 #include "BKE_scene.h"
39 #include "BKE_screen.h"
40 
41 #include "DEG_depsgraph.h"
42 #include "DEG_depsgraph_build.h"
43 
44 #include "UI_interface.h"
45 #include "UI_view2d.h"
46 
47 #include "ED_anim_api.h"
48 #include "ED_armature.h"
49 #include "ED_keyframes_edit.h" /* XXX move the select modes out of there! */
50 #include "ED_object.h"
51 #include "ED_screen.h"
52 #include "ED_select_utils.h"
53 
54 #include "WM_api.h"
55 #include "WM_types.h"
56 
57 /* ************************************************************************** */
58 /* CHANNELS API - Exposed API */
59 
60 /* -------------------------- Selection ------------------------------------- */
61 
63  void *data,
64  eAnimCont_Types datatype,
66  void *channel_data,
67  eAnim_ChannelType channel_type)
68 {
69  /* TODO: extend for animdata types. */
70 
71  ListBase anim_data = {NULL, NULL};
72  bAnimListElem *ale;
73 
74  /* try to build list of filtered items */
75  ANIM_animdata_filter(ac, &anim_data, filter, data, datatype);
76  if (BLI_listbase_is_empty(&anim_data)) {
77  return;
78  }
79 
80  /* only clear the 'active' flag for the channels of the same type */
81  for (ale = anim_data.first; ale; ale = ale->next) {
82  /* skip if types don't match */
83  if (channel_type != ale->type) {
84  continue;
85  }
86 
87  /* flag to set depends on type */
88  switch (ale->type) {
89  case ANIMTYPE_GROUP: {
90  bActionGroup *agrp = (bActionGroup *)ale->data;
91 
93  break;
94  }
95  case ANIMTYPE_FCURVE:
96  case ANIMTYPE_NLACURVE: {
97  FCurve *fcu = (FCurve *)ale->data;
98 
100  break;
101  }
102  case ANIMTYPE_NLATRACK: {
103  NlaTrack *nlt = (NlaTrack *)ale->data;
104 
106  break;
107  }
108  case ANIMTYPE_FILLACTD: /* Action Expander */
109  case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
110  case ANIMTYPE_DSLAM:
111  case ANIMTYPE_DSCAM:
113  case ANIMTYPE_DSCUR:
114  case ANIMTYPE_DSSKEY:
115  case ANIMTYPE_DSWOR:
116  case ANIMTYPE_DSPART:
117  case ANIMTYPE_DSMBALL:
118  case ANIMTYPE_DSARM:
119  case ANIMTYPE_DSMESH:
120  case ANIMTYPE_DSTEX:
121  case ANIMTYPE_DSLAT:
123  case ANIMTYPE_DSSPK:
124  case ANIMTYPE_DSGPENCIL:
125  case ANIMTYPE_DSMCLIP:
126  case ANIMTYPE_DSHAIR:
128  case ANIMTYPE_DSVOLUME:
129  case ANIMTYPE_NLAACTION:
130  case ANIMTYPE_DSSIMULATION: {
131  /* need to verify that this data is valid for now */
132  if (ale->adt) {
134  }
135  break;
136  }
137  case ANIMTYPE_GPLAYER: {
138  bGPDlayer *gpl = (bGPDlayer *)ale->data;
139 
141  break;
142  }
143  }
144  }
145 
146  /* set active flag */
147  if (channel_data) {
148  switch (channel_type) {
149  case ANIMTYPE_GROUP: {
150  bActionGroup *agrp = (bActionGroup *)channel_data;
151  agrp->flag |= AGRP_ACTIVE;
152  break;
153  }
154  case ANIMTYPE_FCURVE:
155  case ANIMTYPE_NLACURVE: {
156  FCurve *fcu = (FCurve *)channel_data;
157  fcu->flag |= FCURVE_ACTIVE;
158  break;
159  }
160  case ANIMTYPE_NLATRACK: {
161  NlaTrack *nlt = (NlaTrack *)channel_data;
162  nlt->flag |= NLATRACK_ACTIVE;
163  break;
164  }
165  case ANIMTYPE_FILLACTD: /* Action Expander */
166  case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
167  case ANIMTYPE_DSLAM:
168  case ANIMTYPE_DSCAM:
170  case ANIMTYPE_DSCUR:
171  case ANIMTYPE_DSSKEY:
172  case ANIMTYPE_DSWOR:
173  case ANIMTYPE_DSPART:
174  case ANIMTYPE_DSMBALL:
175  case ANIMTYPE_DSARM:
176  case ANIMTYPE_DSMESH:
177  case ANIMTYPE_DSLAT:
179  case ANIMTYPE_DSSPK:
180  case ANIMTYPE_DSNTREE:
181  case ANIMTYPE_DSTEX:
182  case ANIMTYPE_DSGPENCIL:
183  case ANIMTYPE_DSMCLIP:
184  case ANIMTYPE_DSHAIR:
186  case ANIMTYPE_DSVOLUME:
187  case ANIMTYPE_NLAACTION:
188  case ANIMTYPE_DSSIMULATION: {
189  /* need to verify that this data is valid for now */
190  if (ale && ale->adt) {
191  ale->adt->flag |= ADT_UI_ACTIVE;
192  }
193  break;
194  }
195 
196  case ANIMTYPE_GPLAYER: {
197  bGPDlayer *gpl = (bGPDlayer *)channel_data;
198  gpl->flag |= GP_LAYER_ACTIVE;
199  break;
200  }
201 
202  /* unhandled currently, but may be interesting */
203  case ANIMTYPE_MASKLAYER:
204  case ANIMTYPE_SHAPEKEY:
205  break;
206 
207  /* other types */
208  default:
209  break;
210  }
211  }
212 
213  /* clean up */
214  ANIM_animdata_freelist(&anim_data);
215 }
216 
218 {
219  /* Armatures-Specific Feature:
220  * See mouse_anim_channels() -> ANIMTYPE_GROUP case for more details (T38737)
221  */
222  if ((ac->ads->filterflag & ADS_FILTER_ONLYSEL) == 0) {
223  if ((ale->id) && (GS(ale->id->name) == ID_OB)) {
224  Object *ob = (Object *)ale->id;
225  if (ob->type == OB_ARMATURE) {
226  /* Assume for now that any group with corresponding name is what we want
227  * (i.e. for an armature whose location is animated, things would break
228  * if the user were to add a bone named "Location").
229  *
230  * TODO: check the first F-Curve or so to be sure...
231  */
232  bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name);
233  if (agrp->flag & AGRP_SELECTED) {
234  ED_pose_bone_select(ob, pchan, true);
235  }
236  else {
237  ED_pose_bone_select(ob, pchan, false);
238  }
239  }
240  }
241  }
242 }
243 
244 static ListBase /* bAnimListElem */ anim_channels_for_selection(bAnimContext *ac)
245 {
246  ListBase anim_data = {NULL, NULL};
247 
248  /* filter data */
249  /* NOTE: no list visible, otherwise, we get dangling */
251  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
252 
253  return anim_data;
254 }
255 
257 {
258  /* See if we should be selecting or deselecting. */
259  for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
260  switch (ale->type) {
261  case ANIMTYPE_SCENE:
262  if (ale->flag & SCE_DS_SELECTED) {
263  return ACHANNEL_SETFLAG_CLEAR;
264  }
265  break;
266  case ANIMTYPE_OBJECT:
267 #if 0 /* for now, do not take object selection into account, since it gets too annoying */
268  if (ale->flag & SELECT) {
269  return ACHANNEL_SETFLAG_CLEAR;
270  }
271 #endif
272  break;
273  case ANIMTYPE_GROUP:
274  if (ale->flag & AGRP_SELECTED) {
275  return ACHANNEL_SETFLAG_CLEAR;
276  }
277  break;
278  case ANIMTYPE_FCURVE:
279  case ANIMTYPE_NLACURVE:
280  if (ale->flag & FCURVE_SELECTED) {
281  return ACHANNEL_SETFLAG_CLEAR;
282  }
283  break;
284  case ANIMTYPE_SHAPEKEY:
285  if (ale->flag & KEYBLOCK_SEL) {
286  return ACHANNEL_SETFLAG_CLEAR;
287  }
288  break;
289  case ANIMTYPE_NLATRACK:
290  if (ale->flag & NLATRACK_SELECTED) {
291  return ACHANNEL_SETFLAG_CLEAR;
292  }
293  break;
294 
295  case ANIMTYPE_FILLACTD: /* Action Expander */
296  case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
297  case ANIMTYPE_DSLAM:
298  case ANIMTYPE_DSCAM:
300  case ANIMTYPE_DSCUR:
301  case ANIMTYPE_DSSKEY:
302  case ANIMTYPE_DSWOR:
303  case ANIMTYPE_DSPART:
304  case ANIMTYPE_DSMBALL:
305  case ANIMTYPE_DSARM:
306  case ANIMTYPE_DSMESH:
307  case ANIMTYPE_DSNTREE:
308  case ANIMTYPE_DSTEX:
309  case ANIMTYPE_DSLAT:
311  case ANIMTYPE_DSSPK:
312  case ANIMTYPE_DSGPENCIL:
313  case ANIMTYPE_DSMCLIP:
314  case ANIMTYPE_DSHAIR:
316  case ANIMTYPE_DSVOLUME:
317  case ANIMTYPE_NLAACTION:
318  case ANIMTYPE_DSSIMULATION: {
319  if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) {
320  return ACHANNEL_SETFLAG_CLEAR;
321  }
322  break;
323  }
324  case ANIMTYPE_GPLAYER:
325  if (ale->flag & GP_LAYER_SELECT) {
326  return ACHANNEL_SETFLAG_CLEAR;
327  }
328  break;
329  case ANIMTYPE_MASKLAYER:
330  if (ale->flag & MASK_LAYERFLAG_SELECT) {
331  return ACHANNEL_SETFLAG_CLEAR;
332  }
333  break;
334  }
335  }
336 
337  return ACHANNEL_SETFLAG_ADD;
338 }
339 
341  const ListBase anim_data,
343 {
344  bAnimListElem *ale;
345 
346  for (ale = anim_data.first; ale; ale = ale->next) {
347  switch (ale->type) {
348  case ANIMTYPE_SCENE: {
349  Scene *scene = (Scene *)ale->data;
350 
352 
353  if (scene->adt) {
355  }
356  break;
357  }
358  case ANIMTYPE_OBJECT: {
359 #if 0 /* for now, do not take object selection into account, since it gets too annoying */
360  Base *base = (Base *)ale->data;
361  Object *ob = base->object;
362 
363  ACHANNEL_SET_FLAG(base, sel, SELECT);
364  ACHANNEL_SET_FLAG(ob, sel, SELECT);
365 
366  if (ob->adt) {
368  }
369 #endif
370  break;
371  }
372  case ANIMTYPE_GROUP: {
373  bActionGroup *agrp = (bActionGroup *)ale->data;
374  ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED);
375  select_pchan_for_action_group(ac, agrp, ale);
376  agrp->flag &= ~AGRP_ACTIVE;
377  break;
378  }
379  case ANIMTYPE_FCURVE:
380  case ANIMTYPE_NLACURVE: {
381  FCurve *fcu = (FCurve *)ale->data;
382 
384  if ((fcu->flag & FCURVE_SELECTED) == 0) {
385  /* Only erase the ACTIVE flag when deselecting. This ensures that "select all curves"
386  * retains the currently active curve. */
387  fcu->flag &= ~FCURVE_ACTIVE;
388  }
389  break;
390  }
391  case ANIMTYPE_SHAPEKEY: {
392  KeyBlock *kb = (KeyBlock *)ale->data;
393 
395  break;
396  }
397  case ANIMTYPE_NLATRACK: {
398  NlaTrack *nlt = (NlaTrack *)ale->data;
399 
401  nlt->flag &= ~NLATRACK_ACTIVE;
402  break;
403  }
404  case ANIMTYPE_FILLACTD: /* Action Expander */
405  case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
406  case ANIMTYPE_DSLAM:
407  case ANIMTYPE_DSCAM:
409  case ANIMTYPE_DSCUR:
410  case ANIMTYPE_DSSKEY:
411  case ANIMTYPE_DSWOR:
412  case ANIMTYPE_DSPART:
413  case ANIMTYPE_DSMBALL:
414  case ANIMTYPE_DSARM:
415  case ANIMTYPE_DSMESH:
416  case ANIMTYPE_DSNTREE:
417  case ANIMTYPE_DSTEX:
418  case ANIMTYPE_DSLAT:
420  case ANIMTYPE_DSSPK:
421  case ANIMTYPE_DSGPENCIL:
422  case ANIMTYPE_DSMCLIP:
423  case ANIMTYPE_DSHAIR:
425  case ANIMTYPE_DSVOLUME:
426  case ANIMTYPE_NLAACTION:
427  case ANIMTYPE_DSSIMULATION: {
428  /* need to verify that this data is valid for now */
429  if (ale->adt) {
431  ale->adt->flag &= ~ADT_UI_ACTIVE;
432  }
433  break;
434  }
435  case ANIMTYPE_GPLAYER: {
436  bGPDlayer *gpl = (bGPDlayer *)ale->data;
437 
439  break;
440  }
441  case ANIMTYPE_MASKLAYER: {
442  MaskLayer *masklay = (MaskLayer *)ale->data;
443 
445  break;
446  }
447  }
448  }
449 }
450 
452 {
453  ListBase anim_data = anim_channels_for_selection(ac);
454  anim_channels_select_set(ac, anim_data, sel);
455  ANIM_animdata_freelist(&anim_data);
456 }
457 
459 {
460  ListBase anim_data = anim_channels_for_selection(ac);
462  anim_channels_select_set(ac, anim_data, sel);
463  ANIM_animdata_freelist(&anim_data);
464 }
465 
466 /* ---------------------------- Graph Editor ------------------------------------- */
467 
468 /* Copy a certain channel setting to parents of the modified channel. */
470  const eAnimChannel_Settings setting,
471  const eAnimChannels_SetFlag mode,
472  bAnimListElem *const match,
473  const int matchLevel)
474 {
475  /* flush up?
476  *
477  * For Visibility:
478  * - only flush up if the current state is now enabled (positive 'on' state is default)
479  * (otherwise, it's too much work to force the parents to be inactive too)
480  *
481  * For everything else:
482  * - only flush up if the current state is now disabled (negative 'off' state is default)
483  * (otherwise, it's too much work to force the parents to be active too)
484  */
485  if (setting == ACHANNEL_SETTING_VISIBLE) {
486  if (mode == ACHANNEL_SETFLAG_CLEAR) {
487  return;
488  }
489  }
490  else {
491  if (mode != ACHANNEL_SETFLAG_CLEAR) {
492  return;
493  }
494  }
495 
496  /* Go backwards in the list, until the highest-ranking element
497  * (by indentation has been covered). */
498  int prevLevel = matchLevel;
499  for (bAnimListElem *ale = match->prev; ale; ale = ale->prev) {
501 
502  /* if no channel info was found, skip, since this type might not have any useful info */
503  if (acf == NULL) {
504  continue;
505  }
506 
507  /* Get the level of the current channel traversed
508  * - we define the level as simply being the offset for the start of the channel
509  */
510  const int level = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
511 
512  if (level == prevLevel) {
513  /* Don't influence siblings. */
514  continue;
515  }
516 
517  if (level > prevLevel) {
518  /* If previous level was a base-level (i.e. 0 offset / root of one hierarchy), stop here. */
519  if (prevLevel == 0) {
520  return;
521  }
522 
523  /* Otherwise, this level weaves into another sibling hierarchy to the previous one just
524  * finished, so skip until we get to the parent of this level. */
525  continue;
526  }
527 
528  /* The level is 'less than' (i.e. more important) the level we're matching but also 'less
529  * than' the level just tried (i.e. only the 1st group above grouped F-Curves, when toggling
530  * visibility of F-Curves, gets flushed, which should happen if we don't let prevLevel get
531  * updated below once the first 1st group is found). */
532  ANIM_channel_setting_set(ac, ale, setting, mode);
533 
534  /* store this level as the 'old' level now */
535  prevLevel = level;
536  }
537 }
538 
539 /* Copy a certain channel setting to children of the modified channel. */
541  const eAnimChannel_Settings setting,
542  const eAnimChannels_SetFlag mode,
543  bAnimListElem *const match,
544  const int matchLevel)
545 {
546  /* go forwards in the list, until the lowest-ranking element (by indentation has been covered) */
547  for (bAnimListElem *ale = match->next; ale; ale = ale->next) {
549 
550  /* if no channel info was found, skip, since this type might not have any useful info */
551  if (acf == NULL) {
552  continue;
553  }
554 
555  /* get the level of the current channel traversed
556  * - we define the level as simply being the offset for the start of the channel
557  */
558  const int level = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
559 
560  /* if the level is 'greater than' (i.e. less important) the channel that was changed,
561  * flush the new status...
562  */
563  if (level > matchLevel) {
564  ANIM_channel_setting_set(ac, ale, setting, mode);
565  /* however, if the level is 'less than or equal to' the channel that was changed,
566  * (i.e. the current channel is as important if not more important than the changed
567  * channel) then we should stop, since we've found the last one of the children we should
568  * flush
569  */
570  }
571  else {
572  break;
573  }
574  }
575 }
576 
578  ListBase *anim_data,
579  bAnimListElem *ale_setting,
580  eAnimChannel_Settings setting,
582 {
583  bAnimListElem *ale, *match = NULL;
584  int matchLevel = 0;
585 
586  /* sanity check */
587  if (ELEM(NULL, anim_data, anim_data->first)) {
588  return;
589  }
590 
591  if (setting == ACHANNEL_SETTING_ALWAYS_VISIBLE) {
592  return;
593  }
594 
595  /* find the channel that got changed */
596  for (ale = anim_data->first; ale; ale = ale->next) {
597  /* compare data, and type as main way of identifying the channel */
598  if ((ale->data == ale_setting->data) && (ale->type == ale_setting->type)) {
599  /* We also have to check the ID, this is assigned to,
600  * since a block may have multiple users. */
601  /* TODO: is the owner-data more revealing? */
602  if (ale->id == ale_setting->id) {
603  match = ale;
604  break;
605  }
606  }
607  }
608  if (match == NULL) {
609  printf("ERROR: no channel matching the one changed was found\n");
610  return;
611  }
612 
613  {
614  const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale_setting);
615  if (acf == NULL) {
616  printf("ERROR: no channel info for the changed channel\n");
617  return;
618  }
619 
620  /* get the level of the channel that was affected
621  * - we define the level as simply being the offset for the start of the channel
622  */
623  matchLevel = (acf->get_offset) ? acf->get_offset(ac, ale_setting) : 0;
624  }
625 
626  anim_flush_channel_setting_up(ac, setting, mode, match, matchLevel);
627  anim_flush_channel_setting_down(ac, setting, mode, match, matchLevel);
628 }
629 
630 /* -------------------------- F-Curves ------------------------------------- */
631 
633 {
634  /* - if no AnimData, we've got nowhere to remove the F-Curve from
635  * (this doesn't guarantee that the F-Curve is in there, but at least we tried
636  * - if no F-Curve, there is nothing to remove
637  */
638  if (ELEM(NULL, adt, fcu)) {
639  return;
640  }
641 
642  /* remove from whatever list it came from
643  * - Action Group
644  * - Action
645  * - Drivers
646  * - TODO... some others?
647  */
648  if ((ac) && (ac->datatype == ANIMCONT_DRIVERS)) {
649  /* driver F-Curve */
650  BLI_remlink(&adt->drivers, fcu);
651  }
652  else if (adt->action) {
653  bAction *act = adt->action;
654 
655  /* remove from group or action, whichever one "owns" the F-Curve */
656  if (fcu->grp) {
657  bActionGroup *agrp = fcu->grp;
658 
659  /* remove F-Curve from group+action */
661 
662  /* if group has no more channels, remove it too,
663  * otherwise can have many dangling groups T33541.
664  */
665  if (BLI_listbase_is_empty(&agrp->channels)) {
666  BLI_freelinkN(&act->groups, agrp);
667  }
668  }
669  else {
670  BLI_remlink(&act->curves, fcu);
671  }
672 
673  /* if action has no more F-Curves as a result of this, unlink it from
674  * AnimData if it did not come from a NLA Strip being tweaked.
675  *
676  * This is done so that we don't have dangling Object+Action entries in
677  * channel list that are empty, and linger around long after the data they
678  * are for has disappeared (and probably won't come back).
679  */
681  }
682 
683  /* free the F-Curve itself */
684  BKE_fcurve_free(fcu);
685 }
686 
688 {
689  if (adt->action != NULL) {
690  bAction *act = adt->action;
691 
692  if (BLI_listbase_is_empty(&act->curves) && (adt->flag & ADT_NLA_EDIT_ON) == 0) {
693  id_us_min(&act->id);
694  adt->action = NULL;
695  return true;
696  }
697  }
698 
699  return false;
700 }
701 
702 /* ************************************************************************** */
703 /* OPERATORS */
704 
705 /* ****************** Operator Utilities ********************************** */
706 
707 /* poll callback for being in an Animation Editor channels list region */
709 {
711 
712  /* channels region test */
713  /* TODO: could enhance with actually testing if channels region? */
714  if (ELEM(NULL, area, CTX_wm_region(C))) {
715  return false;
716  }
717  /* animation editor test */
718  if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) {
719  return false;
720  }
721 
722  return true;
723 }
724 
725 /* Poll callback for Animation Editor channels list region + not in NLA-tweak-mode for NLA. */
727 {
730 
731  /* channels region test */
732  /* TODO: could enhance with actually testing if channels region? */
733  if (ELEM(NULL, area, CTX_wm_region(C))) {
734  return false;
735  }
736  /* animation editor test */
737  if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) {
738  return false;
739  }
740 
741  /* NLA tweak-mode test. */
742  if (area->spacetype == SPACE_NLA) {
743  if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON)) {
744  return false;
745  }
746  }
747 
748  return true;
749 }
750 
751 /* ****************** Rearrange Channels Operator ******************* */
752 
753 /* constants for channel rearranging */
754 /* WARNING: don't change existing ones without modifying rearrange func accordingly */
761 
762 /* defines for rearranging channels */
764  {REARRANGE_ANIMCHAN_TOP, "TOP", 0, "To Top", ""},
765  {REARRANGE_ANIMCHAN_UP, "UP", 0, "Up", ""},
766  {REARRANGE_ANIMCHAN_DOWN, "DOWN", 0, "Down", ""},
767  {REARRANGE_ANIMCHAN_BOTTOM, "BOTTOM", 0, "To Bottom", ""},
768  {0, NULL, 0, NULL, NULL},
769 };
770 
771 /* Reordering "Islands" Defines ----------------------------------- */
772 
773 /* Island definition - just a listbase container */
774 typedef struct tReorderChannelIsland {
776 
777  ListBase channels; /* channels within this region with the same state */
778  int flag; /* eReorderIslandFlag */
780 
781 /* flags for channel reordering islands */
782 typedef enum eReorderIslandFlag {
783  REORDER_ISLAND_SELECTED = (1 << 0), /* island is selected */
784  REORDER_ISLAND_UNTOUCHABLE = (1 << 1), /* island should be ignored */
785  REORDER_ISLAND_MOVED = (1 << 2), /* island has already been moved */
786  REORDER_ISLAND_HIDDEN = (1 << 3), /* island is not visible */
788 
789 /* Rearrange Methods --------------------------------------------- */
790 
792 {
793  /* island must not be untouchable */
794  if (island->flag & REORDER_ISLAND_UNTOUCHABLE) {
795  return false;
796  }
797 
798  /* island should be selected to be moved */
799  return (island->flag & REORDER_ISLAND_SELECTED) && !(island->flag & REORDER_ISLAND_MOVED);
800 }
801 
802 /* ............................. */
803 
805 {
806  if (rearrange_island_ok(island)) {
807  /* remove from current position */
808  BLI_remlink(list, island);
809 
810  /* make it first element */
811  BLI_insertlinkbefore(list, list->first, island);
812 
813  return true;
814  }
815 
816  return false;
817 }
818 
820 {
821  if (rearrange_island_ok(island)) {
822  /* moving up = moving before the previous island, otherwise we're in the same place */
823  tReorderChannelIsland *prev = island->prev;
824 
825  /* Skip hidden islands! */
826  while (prev && prev->flag & REORDER_ISLAND_HIDDEN) {
827  prev = prev->prev;
828  }
829 
830  if (prev) {
831  /* remove from current position */
832  BLI_remlink(list, island);
833 
834  /* push it up */
835  BLI_insertlinkbefore(list, prev, island);
836 
837  return true;
838  }
839  }
840 
841  return false;
842 }
843 
845 {
846  if (rearrange_island_ok(island)) {
847  /* moving down = moving after the next island, otherwise we're in the same place */
848  tReorderChannelIsland *next = island->next;
849 
850  /* Skip hidden islands! */
851  while (next && next->flag & REORDER_ISLAND_HIDDEN) {
852  next = next->next;
853  }
854 
855  if (next) {
856  /* can only move past if next is not untouchable (i.e. nothing can go after it) */
857  if ((next->flag & REORDER_ISLAND_UNTOUCHABLE) == 0) {
858  /* remove from current position */
859  BLI_remlink(list, island);
860 
861  /* push it down */
862  BLI_insertlinkafter(list, next, island);
863 
864  return true;
865  }
866  }
867  /* else: no next channel, so we're at the bottom already, so can't move */
868  }
869 
870  return false;
871 }
872 
874 {
875  if (rearrange_island_ok(island)) {
876  tReorderChannelIsland *last = list->last;
877 
878  /* remove island from current position */
879  BLI_remlink(list, island);
880 
881  /* add before or after the last channel? */
882  if ((last->flag & REORDER_ISLAND_UNTOUCHABLE) == 0) {
883  /* can add after it */
884  BLI_addtail(list, island);
885  }
886  else {
887  /* can at most go just before it, since last cannot be moved */
888  BLI_insertlinkbefore(list, last, island);
889  }
890 
891  return true;
892  }
893 
894  return false;
895 }
896 
897 /* ............................. */
898 
907 
908 /* get rearranging function, given 'rearrange' mode */
910 {
911  switch (mode) {
913  return rearrange_island_top;
915  return rearrange_island_up;
917  return rearrange_island_down;
920  default:
921  return NULL;
922  }
923 }
924 
925 /* get rearranging function, given 'rearrange' mode (grease pencil is inverted) */
927 {
928  switch (mode) {
932  return rearrange_island_down;
934  return rearrange_island_up;
936  return rearrange_island_top;
937  default:
938  return NULL;
939  }
940 }
941 
942 /* Rearrange Islands Generics ------------------------------------- */
943 
944 /* add channel into list of islands */
946  ListBase *srcList,
947  Link *channel,
949  const bool is_hidden)
950 {
951  /* always try to add to last island if possible */
952  tReorderChannelIsland *island = islands->last;
953  bool is_sel = false, is_untouchable = false;
954 
955  /* get flags - selected and untouchable from the channel */
956  switch (type) {
957  case ANIMTYPE_GROUP: {
958  bActionGroup *agrp = (bActionGroup *)channel;
959 
960  is_sel = SEL_AGRP(agrp);
961  is_untouchable = (agrp->flag & AGRP_TEMP) != 0;
962  break;
963  }
964  case ANIMTYPE_FCURVE:
965  case ANIMTYPE_NLACURVE: {
966  FCurve *fcu = (FCurve *)channel;
967 
968  is_sel = SEL_FCU(fcu);
969  break;
970  }
971  case ANIMTYPE_NLATRACK: {
972  NlaTrack *nlt = (NlaTrack *)channel;
973 
974  is_sel = SEL_NLT(nlt);
975  break;
976  }
977  case ANIMTYPE_GPLAYER: {
978  bGPDlayer *gpl = (bGPDlayer *)channel;
979 
980  is_sel = SEL_GPL(gpl);
981  break;
982  }
983  default:
984  printf(
985  "rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %u\n",
986  type);
987  return;
988  }
989 
990  /* do we need to add to a new island? */
991  if (/* 1) no islands yet */
992  (island == NULL) ||
993  /* 2) unselected islands have single channels only - to allow up/down movement */
994  ((island->flag & REORDER_ISLAND_SELECTED) == 0) ||
995  /* 3) if channel is unselected, stop existing island
996  * (it was either wrong sel status, or full already) */
997  (is_sel == 0) ||
998  /* 4) hidden status changes */
999  ((island->flag & REORDER_ISLAND_HIDDEN) != is_hidden)) {
1000  /* create a new island now */
1001  island = MEM_callocN(sizeof(tReorderChannelIsland), "tReorderChannelIsland");
1002  BLI_addtail(islands, island);
1003 
1004  if (is_sel) {
1005  island->flag |= REORDER_ISLAND_SELECTED;
1006  }
1007  if (is_untouchable) {
1008  island->flag |= REORDER_ISLAND_UNTOUCHABLE;
1009  }
1010  if (is_hidden) {
1011  island->flag |= REORDER_ISLAND_HIDDEN;
1012  }
1013  }
1014 
1015  /* add channel to island - need to remove it from its existing list first though */
1016  BLI_remlink(srcList, channel);
1017  BLI_addtail(&island->channels, channel);
1018 }
1019 
1020 /* flatten islands out into a single list again */
1022 {
1023  tReorderChannelIsland *island, *isn = NULL;
1024 
1025  /* make sure srcList is empty now */
1027 
1028  /* go through merging islands */
1029  for (island = islands->first; island; island = isn) {
1030  isn = island->next;
1031 
1032  /* merge island channels back to main list, then delete the island */
1033  BLI_movelisttolist(srcList, &island->channels);
1034  BLI_freelinkN(islands, island);
1035  }
1036 }
1037 
1038 /* ............................. */
1039 
1040 /* get a list of all bAnimListElem's of a certain type which are currently visible */
1041 static void rearrange_animchannels_filter_visible(ListBase *anim_data_visible,
1042  bAnimContext *ac,
1044 {
1045  ListBase anim_data = {NULL, NULL};
1048 
1049  /* get all visible channels */
1050  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1051 
1052  /* now, only keep the ones that are of the types we are interested in */
1053  LISTBASE_FOREACH_MUTABLE (bAnimListElem *, ale, &anim_data) {
1054  if (ale->type != type) {
1055  BLI_freelinkN(&anim_data, ale);
1056  continue;
1057  }
1058 
1059  if (type == ANIMTYPE_NLATRACK) {
1060  NlaTrack *nlt = (NlaTrack *)ale->data;
1061 
1063  /* No re-arrangement of non-local tracks of override data. */
1064  BLI_freelinkN(&anim_data, ale);
1065  continue;
1066  }
1067  }
1068  }
1069 
1070  /* return cleaned up list */
1071  *anim_data_visible = anim_data;
1072 }
1073 
1074 /* performing rearranging of channels using islands */
1076  AnimChanRearrangeFp rearrange_func,
1079  ListBase *anim_data_visible)
1080 {
1081  ListBase islands = {NULL, NULL};
1082  Link *channel, *chanNext = NULL;
1083  bool done = false;
1084 
1085  /* don't waste effort on an empty list */
1086  if (BLI_listbase_is_empty(list)) {
1087  return false;
1088  }
1089 
1090  /* group channels into islands */
1091  for (channel = list->first; channel; channel = chanNext) {
1092  /* find out whether this channel is present in anim_data_visible or not! */
1093  const bool is_hidden =
1094  (BLI_findptr(anim_data_visible, channel, offsetof(bAnimListElem, data)) == NULL);
1095  chanNext = channel->next;
1096  rearrange_animchannel_add_to_islands(&islands, list, channel, type, is_hidden);
1097  }
1098 
1099  /* Perform moving of selected islands now, but only if there is more than one of them
1100  * so that something will happen:
1101  *
1102  * - Scanning of the list is performed in the opposite direction
1103  * to the direction we're moving things,
1104  * so that we shouldn't need to encounter items we've moved already.
1105  */
1106  if (islands.first != islands.last) {
1107  tReorderChannelIsland *first = (mode > 0) ? islands.last : islands.first;
1108  tReorderChannelIsland *island, *isn = NULL;
1109 
1110  for (island = first; island; island = isn) {
1111  isn = (mode > 0) ? island->prev : island->next;
1112 
1113  /* perform rearranging */
1114  if (rearrange_func(&islands, island)) {
1115  island->flag |= REORDER_ISLAND_MOVED;
1116  done = true;
1117  }
1118  }
1119  }
1120 
1121  /* ungroup islands */
1122  rearrange_animchannel_flatten_islands(&islands, list);
1123 
1124  /* did we do anything? */
1125  return done;
1126 }
1127 
1128 /* NLA Specific Stuff ----------------------------------------------------- */
1129 
1130 /* Change the order NLA Tracks within NLA Stack
1131  * ! NLA tracks are displayed in opposite order, so directions need care
1132  * mode: REARRANGE_ANIMCHAN_*
1133  */
1135 {
1136  AnimChanRearrangeFp rearrange_func;
1137  ListBase anim_data_visible = {NULL, NULL};
1138  const bool is_liboverride = (ac->obact != NULL) ? ID_IS_OVERRIDE_LIBRARY(ac->obact) : false;
1139 
1140  /* hack: invert mode so that functions will work in right order */
1141  mode *= -1;
1142 
1143  /* get rearranging function */
1144  rearrange_func = rearrange_get_mode_func(mode);
1145  if (rearrange_func == NULL) {
1146  return;
1147  }
1148 
1149  /* In liboverride case, we need to extract non-local NLA tracks from current anim data before we
1150  * can perform the move, and add then back afterwards. It's the only way to prevent them from
1151  * being affected by the reordering.
1152  *
1153  * Note that both override apply code for NLA tracks collection, and NLA editing code, are
1154  * responsible to ensure that non-local tracks always remain first in the list. */
1155  ListBase extracted_nonlocal_nla_tracks = {NULL, NULL};
1156  if (is_liboverride) {
1157  NlaTrack *nla_track;
1158  for (nla_track = adt->nla_tracks.first; nla_track != NULL; nla_track = nla_track->next) {
1159  if (!BKE_nlatrack_is_nonlocal_in_liboverride(&ac->obact->id, nla_track)) {
1160  break;
1161  }
1162  }
1163  if (nla_track != NULL && nla_track->prev != NULL) {
1164  extracted_nonlocal_nla_tracks.first = adt->nla_tracks.first;
1165  extracted_nonlocal_nla_tracks.last = nla_track->prev;
1166  adt->nla_tracks.first = nla_track;
1167  nla_track->prev->next = NULL;
1168  nla_track->prev = NULL;
1169  }
1170  }
1171 
1172  /* Filter visible data. */
1174 
1175  /* perform rearranging on tracks list */
1177  &adt->nla_tracks, rearrange_func, mode, ANIMTYPE_NLATRACK, &anim_data_visible);
1178 
1179  /* Add back non-local NLA tracks at the beginning of the animation data's list. */
1180  if (!BLI_listbase_is_empty(&extracted_nonlocal_nla_tracks)) {
1181  BLI_assert(is_liboverride);
1182  ((NlaTrack *)extracted_nonlocal_nla_tracks.last)->next = adt->nla_tracks.first;
1183  ((NlaTrack *)adt->nla_tracks.first)->prev = extracted_nonlocal_nla_tracks.last;
1184  adt->nla_tracks.first = extracted_nonlocal_nla_tracks.first;
1185  }
1186 
1187  /* free temp data */
1188  BLI_freelistN(&anim_data_visible);
1189 }
1190 
1191 /* Drivers Specific Stuff ------------------------------------------------- */
1192 
1193 /* Change the order drivers within AnimData block
1194  * mode: REARRANGE_ANIMCHAN_*
1195  */
1197  AnimData *adt,
1199 {
1200  /* get rearranging function */
1201  AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
1202  ListBase anim_data_visible = {NULL, NULL};
1203 
1204  if (rearrange_func == NULL) {
1205  return;
1206  }
1207 
1208  /* only consider drivers if they're accessible */
1209  if (EXPANDED_DRVD(adt) == 0) {
1210  return;
1211  }
1212 
1213  /* Filter visible data. */
1214  rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_FCURVE);
1215 
1216  /* perform rearranging on drivers list (drivers are really just F-Curves) */
1218  &adt->drivers, rearrange_func, mode, ANIMTYPE_FCURVE, &anim_data_visible);
1219 
1220  /* free temp data */
1221  BLI_freelistN(&anim_data_visible);
1222 }
1223 
1224 /* Action Specific Stuff ------------------------------------------------- */
1225 
1226 /* make sure all action-channels belong to a group (and clear action's list) */
1228 {
1229  FCurve *fcu;
1230 
1231  if (act == NULL) {
1232  return;
1233  }
1234 
1235  /* Separate F-Curves into lists per group */
1236  LISTBASE_FOREACH (bActionGroup *, agrp, &act->groups) {
1237  FCurve *const group_fcurves_first = agrp->channels.first;
1238  FCurve *const group_fcurves_last = agrp->channels.last;
1239  if (group_fcurves_first == NULL) {
1240  /* Empty group. */
1241  continue;
1242  }
1243 
1244  if (group_fcurves_first == act->curves.first) {
1245  /* First of the action curves, update the start of the action curves. */
1246  BLI_assert(group_fcurves_first->prev == NULL);
1247  act->curves.first = group_fcurves_last->next;
1248  }
1249  else {
1250  group_fcurves_first->prev->next = group_fcurves_last->next;
1251  }
1252 
1253  if (group_fcurves_last == act->curves.last) {
1254  /* Last of the action curves, update the end of the action curves. */
1255  BLI_assert(group_fcurves_last->next == NULL);
1256  act->curves.last = group_fcurves_first->prev;
1257  }
1258  else {
1259  group_fcurves_last->next->prev = group_fcurves_first->prev;
1260  }
1261 
1262  /* Clear links pointing outside the per-group list. */
1263  group_fcurves_first->prev = group_fcurves_last->next = NULL;
1264  }
1265 
1266  /* Initialize memory for temp-group */
1267  memset(tgrp, 0, sizeof(bActionGroup));
1268  tgrp->flag |= (AGRP_EXPANDED | AGRP_TEMP);
1269  BLI_strncpy(tgrp->name, "#TempGroup", sizeof(tgrp->name));
1270 
1271  /* Move any action-channels not already moved, to the temp group */
1272  if (act->curves.first) {
1273  /* start of list */
1274  fcu = act->curves.first;
1275  fcu->prev = NULL;
1276  tgrp->channels.first = fcu;
1277  act->curves.first = NULL;
1278 
1279  /* end of list */
1280  fcu = act->curves.last;
1281  fcu->next = NULL;
1282  tgrp->channels.last = fcu;
1283  act->curves.last = NULL;
1284 
1285  /* ensure that all of these get their group set to this temp group
1286  * (so that visibility filtering works)
1287  */
1288  for (fcu = tgrp->channels.first; fcu; fcu = fcu->next) {
1289  fcu->grp = tgrp;
1290  }
1291  }
1292 
1293  /* Add temp-group to list */
1294  BLI_addtail(&act->groups, tgrp);
1295 }
1296 
1297 /* link lists of channels that groups have */
1299 {
1300  bActionGroup *agrp;
1301 
1302  for (agrp = act->groups.first; agrp; agrp = agrp->next) {
1303  /* add list of channels to action's channels */
1304  const ListBase group_channels = agrp->channels;
1305  BLI_movelisttolist(&act->curves, &agrp->channels);
1306  agrp->channels = group_channels;
1307 
1308  /* clear moved flag */
1309  agrp->flag &= ~AGRP_MOVED;
1310 
1311  /* if group was temporary one:
1312  * - unassign all FCurves which were temporarily added to it
1313  * - remove from list (but don't free as it's on the stack!)
1314  */
1315  if (agrp->flag & AGRP_TEMP) {
1316  LISTBASE_FOREACH (FCurve *, fcu, &agrp->channels) {
1317  fcu->grp = NULL;
1318  }
1319 
1320  BLI_remlink(&act->groups, agrp);
1321  break;
1322  }
1323  }
1324 }
1325 
1326 /* Change the order of anim-channels within action
1327  * mode: REARRANGE_ANIMCHAN_*
1328  */
1330 {
1331  bActionGroup tgrp;
1332  ListBase anim_data_visible = {NULL, NULL};
1333  bool do_channels;
1334 
1335  /* get rearranging function */
1336  AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
1337 
1338  if (rearrange_func == NULL) {
1339  return;
1340  }
1341 
1342  /* make sure we're only operating with groups (vs a mixture of groups+curves) */
1343  split_groups_action_temp(act, &tgrp);
1344 
1345  /* Filter visible data. */
1346  rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_GROUP);
1347 
1348  /* Rearrange groups first:
1349  * - The group's channels will only get considered
1350  * if nothing happened when rearranging the groups
1351  * i.e. the rearrange function returned 0.
1352  */
1353  do_channels = (rearrange_animchannel_islands(
1354  &act->groups, rearrange_func, mode, ANIMTYPE_GROUP, &anim_data_visible) == 0);
1355 
1356  /* free temp data */
1357  BLI_freelistN(&anim_data_visible);
1358 
1359  if (do_channels) {
1360  bActionGroup *agrp;
1361 
1362  /* Filter visible data. */
1363  rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_FCURVE);
1364 
1365  for (agrp = act->groups.first; agrp; agrp = agrp->next) {
1366  /* only consider F-Curves if they're visible (group expanded) */
1367  if (EXPANDED_AGRP(ac, agrp)) {
1369  &agrp->channels, rearrange_func, mode, ANIMTYPE_FCURVE, &anim_data_visible);
1370  }
1371  }
1372 
1373  /* free temp data */
1374  BLI_freelistN(&anim_data_visible);
1375  }
1376 
1377  /* assemble lists into one list (and clear moved tags) */
1379 }
1380 
1381 /* ------------------- */
1382 
1384  AnimData *adt,
1386 {
1387  ListBase anim_data_visible = {NULL, NULL};
1388 
1389  NlaTrack *nlt;
1390  NlaStrip *strip;
1391 
1392  /* get rearranging function */
1393  AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
1394 
1395  if (rearrange_func == NULL) {
1396  return;
1397  }
1398 
1399  /* skip if these curves aren't being shown */
1400  if (adt->flag & ADT_NLA_SKEYS_COLLAPSED) {
1401  return;
1402  }
1403 
1404  /* Filter visible data. */
1406 
1407  /* we cannot rearrange between strips, but within each strip, we can rearrange those curves */
1408  for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1409  for (strip = nlt->strips.first; strip; strip = strip->next) {
1411  &strip->fcurves, rearrange_func, mode, ANIMTYPE_NLACURVE, &anim_data_visible);
1412  }
1413  }
1414 
1415  /* free temp data */
1416  BLI_freelistN(&anim_data_visible);
1417 }
1418 
1419 /* ------------------- */
1420 
1422 {
1423  ListBase anim_data = {NULL, NULL};
1424  bAnimListElem *ale;
1425  int filter;
1426 
1427  /* get rearranging function */
1429 
1430  if (rearrange_func == NULL) {
1431  return;
1432  }
1433 
1434  /* get Grease Pencil datablocks */
1436  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1437 
1438  for (ale = anim_data.first; ale; ale = ale->next) {
1439  ListBase anim_data_visible = {NULL, NULL};
1440  bGPdata *gpd = ale->data;
1441 
1442  /* only consider layers if this datablock is open */
1444  if ((gpd->flag & GP_DATA_EXPAND) == 0) {
1445  continue;
1446  }
1447 
1448  /* Filter visible data. */
1450 
1451  /* rearrange datablock's layers */
1453  &gpd->layers, rearrange_func, mode, ANIMTYPE_GPLAYER, &anim_data_visible);
1454 
1455  /* free visible layers data */
1456  BLI_freelistN(&anim_data_visible);
1457 
1458  /* Tag to recalc geometry */
1460  }
1461 
1462  /* free GPD channel data */
1463  ANIM_animdata_freelist(&anim_data);
1464 
1466 }
1467 
1468 /* ------------------- */
1469 
1471 {
1472  bAnimContext ac;
1474 
1475  /* get editor data */
1476  if (ANIM_animdata_get_context(C, &ac) == 0) {
1477  return OPERATOR_CANCELLED;
1478  }
1479 
1480  /* get mode */
1481  mode = RNA_enum_get(op->ptr, "direction");
1482 
1483  /* method to move channels depends on the editor */
1484  if (ac.datatype == ANIMCONT_GPENCIL) {
1485  /* Grease Pencil channels */
1486  rearrange_gpencil_channels(&ac, mode);
1487  }
1488  else if (ac.datatype == ANIMCONT_MASK) {
1489  /* Grease Pencil channels */
1490  printf("Mask does not supported for moving yet\n");
1491  }
1492  else if (ac.datatype == ANIMCONT_ACTION) {
1493  /* Directly rearrange action's channels */
1494  rearrange_action_channels(&ac, ac.data, mode);
1495  }
1496  else {
1497  ListBase anim_data = {NULL, NULL};
1498  bAnimListElem *ale;
1499  int filter;
1500 
1501  /* get animdata blocks */
1504  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1505 
1506  for (ale = anim_data.first; ale; ale = ale->next) {
1507  AnimData *adt = ale->data;
1508 
1509  switch (ac.datatype) {
1510  case ANIMCONT_NLA: /* NLA-tracks only */
1511  rearrange_nla_channels(&ac, adt, mode);
1513  break;
1514 
1515  case ANIMCONT_DRIVERS: /* Drivers list only */
1516  rearrange_driver_channels(&ac, adt, mode);
1517  break;
1518 
1519  case ANIMCONT_ACTION: /* Single Action only... */
1520  case ANIMCONT_SHAPEKEY: /* DOUBLE CHECK ME... */
1521  {
1522  if (adt->action) {
1523  rearrange_action_channels(&ac, adt->action, mode);
1524  }
1525  else if (G.debug & G_DEBUG) {
1526  printf("Animdata has no action\n");
1527  }
1528  break;
1529  }
1530 
1531  default: /* DopeSheet/Graph Editor - Some Actions + NLA Control Curves */
1532  {
1533  /* NLA Control Curves */
1534  if (adt->nla_tracks.first) {
1535  rearrange_nla_control_channels(&ac, adt, mode);
1536  }
1537 
1538  /* Action */
1539  if (adt->action) {
1540  rearrange_action_channels(&ac, adt->action, mode);
1541  }
1542  else if (G.debug & G_DEBUG) {
1543  printf("Animdata has no action\n");
1544  }
1545  break;
1546  }
1547  }
1548  }
1549 
1550  /* free temp data */
1551  ANIM_animdata_freelist(&anim_data);
1552  }
1553 
1554  /* send notifier that things have changed */
1557 
1558  return OPERATOR_FINISHED;
1559 }
1560 
1562 {
1563  /* identifiers */
1564  ot->name = "Move Channels";
1565  ot->idname = "ANIM_OT_channels_move";
1566  ot->description = "Rearrange selected animation channels";
1567 
1568  /* api callbacks */
1571 
1572  /* flags */
1574 
1575  /* props */
1576  ot->prop = RNA_def_enum(ot->srna,
1577  "direction",
1580  "Direction",
1581  "");
1582 }
1583 
1584 /* ******************** Group Channel Operator ************************ */
1585 
1587 {
1588  ScrArea *area = CTX_wm_area(C);
1589  SpaceLink *sl;
1590 
1591  /* channels region test */
1592  /* TODO: could enhance with actually testing if channels region? */
1593  if (ELEM(NULL, area, CTX_wm_region(C))) {
1594  return false;
1595  }
1596 
1597  /* animation editor test - must be suitable modes only */
1598  sl = CTX_wm_space_data(C);
1599 
1600  switch (area->spacetype) {
1601  /* supported... */
1602  case SPACE_ACTION: {
1603  SpaceAction *saction = (SpaceAction *)sl;
1604 
1605  /* dopesheet and action only - all others are for other datatypes or have no groups */
1606  if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_DOPESHEET) == 0) {
1607  return false;
1608  }
1609 
1610  break;
1611  }
1612  case SPACE_GRAPH: {
1613  SpaceGraph *sipo = (SpaceGraph *)sl;
1614 
1615  /* drivers can't have groups... */
1616  if (sipo->mode != SIPO_MODE_ANIMATION) {
1617  return false;
1618  }
1619 
1620  break;
1621  }
1622  /* unsupported... */
1623  default:
1624  return false;
1625  }
1626 
1627  return true;
1628 }
1629 
1630 /* ----------------------------------------------------------- */
1631 
1633  bAnimListElem *adt_ref,
1634  const char name[])
1635 {
1636  AnimData *adt = adt_ref->adt;
1637  bAction *act = adt->action;
1638 
1639  if (act) {
1640  ListBase anim_data = {NULL, NULL};
1641  int filter;
1642 
1643  /* find selected F-Curves to re-group */
1646  ANIM_animdata_filter(ac, &anim_data, filter, adt_ref, ANIMCONT_CHANNEL);
1647 
1648  if (anim_data.first) {
1649  bActionGroup *agrp;
1650  bAnimListElem *ale;
1651 
1652  /* create new group, which should now be part of the action */
1653  agrp = action_groups_add_new(act, name);
1654  BLI_assert(agrp != NULL);
1655 
1656  /* Transfer selected F-Curves across to new group. */
1657  for (ale = anim_data.first; ale; ale = ale->next) {
1658  FCurve *fcu = (FCurve *)ale->data;
1659  bActionGroup *grp = fcu->grp;
1660 
1661  /* remove F-Curve from group, then group too if it is now empty */
1662  action_groups_remove_channel(act, fcu);
1663 
1664  if ((grp) && BLI_listbase_is_empty(&grp->channels)) {
1665  BLI_freelinkN(&act->groups, grp);
1666  }
1667 
1668  /* add F-Curve to group */
1669  action_groups_add_channel(act, agrp, fcu);
1670  }
1671  }
1672 
1673  /* cleanup */
1674  ANIM_animdata_freelist(&anim_data);
1675  }
1676 }
1677 
1679 {
1680  bAnimContext ac;
1681  char name[MAX_NAME];
1682 
1683  /* get editor data */
1684  if (ANIM_animdata_get_context(C, &ac) == 0) {
1685  return OPERATOR_CANCELLED;
1686  }
1687 
1688  /* get name for new group */
1689  RNA_string_get(op->ptr, "name", name);
1690 
1691  /* XXX: name for group should never be empty... */
1692  if (name[0]) {
1693  ListBase anim_data = {NULL, NULL};
1694  bAnimListElem *ale;
1695  int filter;
1696 
1697  /* Handle each animdata block separately, so that the regrouping doesn't flow into blocks. */
1700  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1701 
1702  for (ale = anim_data.first; ale; ale = ale->next) {
1703  animchannels_group_channels(&ac, ale, name);
1704  }
1705 
1706  /* free temp data */
1707  ANIM_animdata_freelist(&anim_data);
1708 
1709  /* Updates. */
1711  }
1712 
1713  return OPERATOR_FINISHED;
1714 }
1715 
1717 {
1718  /* identifiers */
1719  ot->name = "Group Channels";
1720  ot->idname = "ANIM_OT_channels_group";
1721  ot->description = "Add selected F-Curves to a new group";
1722 
1723  /* callbacks */
1727 
1728  /* flags */
1730 
1731  /* props */
1733  "name",
1734  "New Group",
1735  sizeof(((bActionGroup *)NULL)->name),
1736  "Name",
1737  "Name of newly created group");
1738  /* XXX: still not too sure about this - keeping same text is confusing... */
1739  // RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
1740 }
1741 
1742 /* ----------------------------------------------------------- */
1743 
1745 {
1746  bAnimContext ac;
1747 
1748  ListBase anim_data = {NULL, NULL};
1749  bAnimListElem *ale;
1750  int filter;
1751 
1752  /* get editor data */
1753  if (ANIM_animdata_get_context(C, &ac) == 0) {
1754  return OPERATOR_CANCELLED;
1755  }
1756 
1757  /* just selected F-Curves... */
1760  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1761 
1762  for (ale = anim_data.first; ale; ale = ale->next) {
1763  /* find action for this F-Curve... */
1764  if (ale->adt && ale->adt->action) {
1765  FCurve *fcu = (FCurve *)ale->data;
1766  bAction *act = ale->adt->action;
1767 
1768  /* only proceed to remove if F-Curve is in a group... */
1769  if (fcu->grp) {
1770  bActionGroup *agrp = fcu->grp;
1771 
1772  /* remove F-Curve from group and add at tail (ungrouped) */
1773  action_groups_remove_channel(act, fcu);
1774  BLI_addtail(&act->curves, fcu);
1775 
1776  /* delete group if it is now empty */
1777  if (BLI_listbase_is_empty(&agrp->channels)) {
1778  BLI_freelinkN(&act->groups, agrp);
1779  }
1780  }
1781  }
1782  }
1783 
1784  /* cleanup */
1785  ANIM_animdata_freelist(&anim_data);
1786 
1787  /* updates */
1789 
1790  return OPERATOR_FINISHED;
1791 }
1792 
1794 {
1795  /* identifiers */
1796  ot->name = "Ungroup Channels";
1797  ot->idname = "ANIM_OT_channels_ungroup";
1798  ot->description = "Remove selected F-Curves from their current groups";
1799 
1800  /* callbacks */
1803 
1804  /* flags */
1806 }
1807 
1808 /* ******************** Delete Channel Operator *********************** */
1809 
1811 {
1812  ID *id = ale->id;
1813  AnimData *adt = BKE_animdata_from_id(id);
1814  /* TODO(sergey): Technically, if the animation element is being deleted
1815  * from a driver we don't have to tag action. This is something we can check
1816  * for in the future. For now just do most reliable tag which was always happening. */
1817  if (adt != NULL) {
1819  if (adt->action != NULL) {
1821  }
1822  }
1823  /* Deals with NLA and drivers.
1824  * Doesn't cause overhead for action updates, since object will receive
1825  * animation update after dependency graph flushes update from action to
1826  * all its users. */
1828 }
1829 
1831 {
1832  bAnimContext ac;
1833  ListBase anim_data = {NULL, NULL};
1834  bAnimListElem *ale;
1835  int filter;
1836 
1837  /* get editor data */
1838  if (ANIM_animdata_get_context(C, &ac) == 0) {
1839  return OPERATOR_CANCELLED;
1840  }
1841 
1842  /* cannot delete in shapekey */
1843  if (ac.datatype == ANIMCONT_SHAPEKEY) {
1844  return OPERATOR_CANCELLED;
1845  }
1846 
1847  /* do groups only first (unless in Drivers mode, where there are none) */
1848  if (ac.datatype != ANIMCONT_DRIVERS) {
1849  /* filter data */
1852  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1853 
1854  /* delete selected groups and their associated channels */
1855  for (ale = anim_data.first; ale; ale = ale->next) {
1856  /* only groups - don't check other types yet, since they may no-longer exist */
1857  if (ale->type == ANIMTYPE_GROUP) {
1858  bActionGroup *agrp = (bActionGroup *)ale->data;
1859  AnimData *adt = ale->adt;
1860  FCurve *fcu, *fcn;
1861 
1862  /* skip this group if no AnimData available, as we can't safely remove the F-Curves */
1863  if (adt == NULL) {
1864  continue;
1865  }
1866 
1867  /* delete all of the Group's F-Curves, but no others */
1868  for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcn) {
1869  fcn = fcu->next;
1870 
1871  /* remove from group and action, then free */
1872  action_groups_remove_channel(adt->action, fcu);
1873  BKE_fcurve_free(fcu);
1874  }
1875 
1876  /* free the group itself */
1877  if (adt->action) {
1878  BLI_freelinkN(&adt->action->groups, agrp);
1880  }
1881  else {
1882  MEM_freeN(agrp);
1883  }
1884  }
1885  }
1886 
1887  /* cleanup */
1888  ANIM_animdata_freelist(&anim_data);
1889  }
1890 
1891  /* filter data */
1894  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1895 
1896  /* delete selected data channels */
1897  for (ale = anim_data.first; ale; ale = ale->next) {
1898  switch (ale->type) {
1899  case ANIMTYPE_FCURVE: {
1900  /* F-Curves if we can identify its parent */
1901  AnimData *adt = ale->adt;
1902  FCurve *fcu = (FCurve *)ale->data;
1903 
1904  /* try to free F-Curve */
1905  ANIM_fcurve_delete_from_animdata(&ac, adt, fcu);
1907  break;
1908  }
1909  case ANIMTYPE_NLACURVE: {
1910  /* NLA Control Curve - Deleting it should disable the corresponding setting... */
1911  NlaStrip *strip = (NlaStrip *)ale->owner;
1912  FCurve *fcu = (FCurve *)ale->data;
1913 
1914  if (STREQ(fcu->rna_path, "strip_time")) {
1915  strip->flag &= ~NLASTRIP_FLAG_USR_TIME;
1916  }
1917  else if (STREQ(fcu->rna_path, "influence")) {
1918  strip->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE;
1919  }
1920  else {
1921  printf("ERROR: Trying to delete NLA Control Curve for unknown property '%s'\n",
1922  fcu->rna_path);
1923  }
1924 
1925  /* unlink and free the F-Curve */
1926  BLI_remlink(&strip->fcurves, fcu);
1927  BKE_fcurve_free(fcu);
1929  break;
1930  }
1931  case ANIMTYPE_GPLAYER: {
1932  /* Grease Pencil layer */
1933  bGPdata *gpd = (bGPdata *)ale->id;
1934  bGPDlayer *gpl = (bGPDlayer *)ale->data;
1935 
1936  /* try to delete the layer's data and the layer itself */
1937  BKE_gpencil_layer_delete(gpd, gpl);
1938  ale->update = ANIM_UPDATE_DEPS;
1939 
1940  /* Free Grease Pencil data block when last annotation layer is removed, see: #112683. */
1941  if (gpd->flag & GP_DATA_ANNOTATIONS && gpd->layers.first == NULL) {
1942  BKE_gpencil_free_data(gpd, true);
1943 
1945  scene->gpd = NULL;
1946 
1947  Main *bmain = CTX_data_main(C);
1948  BKE_id_free_us(bmain, gpd);
1949  }
1950  break;
1951  }
1952  case ANIMTYPE_MASKLAYER: {
1953  /* Mask layer */
1954  Mask *mask = (Mask *)ale->id;
1955  MaskLayer *masklay = (MaskLayer *)ale->data;
1956 
1957  /* try to delete the layer's data and the layer itself */
1958  BKE_mask_layer_remove(mask, masklay);
1959  break;
1960  }
1961  }
1962  }
1963 
1964  ANIM_animdata_update(&ac, &anim_data);
1965  ANIM_animdata_freelist(&anim_data);
1966 
1967  /* send notifier that things have changed */
1971 
1972  return OPERATOR_FINISHED;
1973 }
1974 
1976 {
1977  /* identifiers */
1978  ot->name = "Delete Channels";
1979  ot->idname = "ANIM_OT_channels_delete";
1980  ot->description = "Delete all selected animation channels";
1981 
1982  /* api callbacks */
1985 
1986  /* flags */
1988 }
1989 
1990 /* ********************** Set Flags Operator *********************** */
1991 
1992 /* defines for setting animation-channel flags */
1994  {ACHANNEL_SETFLAG_TOGGLE, "TOGGLE", 0, "Toggle", ""},
1995  {ACHANNEL_SETFLAG_CLEAR, "DISABLE", 0, "Disable", ""},
1996  {ACHANNEL_SETFLAG_ADD, "ENABLE", 0, "Enable", ""},
1997  {ACHANNEL_SETFLAG_INVERT, "INVERT", 0, "Invert", ""},
1998  {0, NULL, 0, NULL, NULL},
1999 };
2000 
2001 /* defines for set animation-channel settings */
2002 /* TODO: could add some more types, but those are really quite dependent on the mode... */
2004  {ACHANNEL_SETTING_PROTECT, "PROTECT", 0, "Protect", ""},
2005  {ACHANNEL_SETTING_MUTE, "MUTE", 0, "Mute", ""},
2006  {0, NULL, 0, NULL, NULL},
2007 };
2008 
2009 /* ------------------- */
2010 
2020  eAnimChannel_Settings setting,
2021  eAnimChannels_SetFlag mode,
2022  bool onlysel,
2023  bool flush)
2024 {
2025  ListBase anim_data = {NULL, NULL};
2026  ListBase all_data = {NULL, NULL};
2027  bAnimListElem *ale;
2028  int filter;
2029 
2030  /* filter data that we need if flush is on */
2031  if (flush) {
2032  /* get list of all channels that selection may need to be flushed to
2033  * - hierarchy visibility needs to be ignored so that settings can get flushed
2034  * "down" inside closed containers
2035  */
2037  ANIM_animdata_filter(ac, &all_data, filter, ac->data, ac->datatype);
2038  }
2039 
2040  /* filter data that we're working on
2041  * - hierarchy matters if we're doing this from the channels region
2042  * since we only want to apply this to channels we can "see",
2043  * and have these affect their relatives
2044  * - but for Graph Editor, this gets used also from main region
2045  * where hierarchy doesn't apply T21276.
2046  */
2047  if ((ac->spacetype == SPACE_GRAPH) && (ac->regiontype != RGN_TYPE_CHANNELS)) {
2048  /* graph editor (case 2) */
2051  }
2052  else {
2053  /* standard case */
2056  }
2057  if (onlysel) {
2059  }
2060  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
2061 
2062  /* if toggling, check if disable or enable */
2063  if (mode == ACHANNEL_SETFLAG_TOGGLE) {
2064  /* default to turn all on, unless we encounter one that's on... */
2065  mode = ACHANNEL_SETFLAG_ADD;
2066 
2067  /* see if we should turn off instead... */
2068  for (ale = anim_data.first; ale; ale = ale->next) {
2069  /* set the setting in the appropriate way (if available) */
2070  if (ANIM_channel_setting_get(ac, ale, setting) > 0) {
2071  mode = ACHANNEL_SETFLAG_CLEAR;
2072  break;
2073  }
2074  }
2075  }
2076 
2077  /* apply the setting */
2078  for (ale = anim_data.first; ale; ale = ale->next) {
2079  /* skip channel if setting is not available */
2080  if (ANIM_channel_setting_get(ac, ale, setting) == -1) {
2081  continue;
2082  }
2083 
2084  /* set the setting in the appropriate way */
2085  ANIM_channel_setting_set(ac, ale, setting, mode);
2087 
2088  /* if flush status... */
2089  if (flush) {
2090  ANIM_flush_setting_anim_channels(ac, &all_data, ale, setting, mode);
2091  }
2092  }
2093 
2094  ANIM_animdata_freelist(&anim_data);
2095  BLI_freelistN(&all_data);
2096 }
2097 
2098 /* ------------------- */
2099 
2101 {
2102  bAnimContext ac;
2103  eAnimChannel_Settings setting;
2104  eAnimChannels_SetFlag mode;
2105  bool flush = true;
2106 
2107  /* get editor data */
2108  if (ANIM_animdata_get_context(C, &ac) == 0) {
2109  return OPERATOR_CANCELLED;
2110  }
2111 
2112  /* mode (eAnimChannels_SetFlag), setting (eAnimChannel_Settings) */
2113  mode = RNA_enum_get(op->ptr, "mode");
2114  setting = RNA_enum_get(op->ptr, "type");
2115 
2116  /* check if setting is flushable */
2117  if (setting == ACHANNEL_SETTING_EXPAND) {
2118  flush = false;
2119  }
2120 
2121  /* modify setting
2122  * - only selected channels are affected
2123  */
2124  setflag_anim_channels(&ac, setting, mode, true, flush);
2125 
2126  /* send notifier that things have changed */
2128 
2129  return OPERATOR_FINISHED;
2130 }
2131 
2132 /* duplicate of 'ANIM_OT_channels_setting_toggle' for menu title only, weak! */
2134 {
2135  PropertyRNA *prop;
2136 
2137  /* identifiers */
2138  ot->name = "Enable Channel Setting";
2139  ot->idname = "ANIM_OT_channels_setting_enable";
2140  ot->description = "Enable specified setting on all selected animation channels";
2141 
2142  /* api callbacks */
2146 
2147  /* flags */
2149 
2150  /* props */
2151  /* flag-setting mode */
2152  prop = RNA_def_enum(
2155  /* setting to set */
2156  ot->prop = RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
2157 }
2158 /* duplicate of 'ANIM_OT_channels_setting_toggle' for menu title only, weak! */
2160 {
2161  PropertyRNA *prop;
2162 
2163  /* identifiers */
2164  ot->name = "Disable Channel Setting";
2165  ot->idname = "ANIM_OT_channels_setting_disable";
2166  ot->description = "Disable specified setting on all selected animation channels";
2167 
2168  /* api callbacks */
2172 
2173  /* flags */
2175 
2176  /* props */
2177  /* flag-setting mode */
2178  prop = RNA_def_enum(
2180  RNA_def_property_flag(prop, PROP_HIDDEN); /* internal hack - don't expose */
2181  /* setting to set */
2182  ot->prop = RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
2183 }
2184 
2186 {
2187  PropertyRNA *prop;
2188 
2189  /* identifiers */
2190  ot->name = "Toggle Channel Setting";
2191  ot->idname = "ANIM_OT_channels_setting_toggle";
2192  ot->description = "Toggle specified setting on all selected animation channels";
2193 
2194  /* api callbacks */
2198 
2199  /* flags */
2201 
2202  /* props */
2203  /* flag-setting mode */
2204  prop = RNA_def_enum(
2206  RNA_def_property_flag(prop, PROP_HIDDEN); /* internal hack - don't expose */
2207  /* setting to set */
2208  ot->prop = RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
2209 }
2210 
2212 {
2213  PropertyRNA *prop;
2214 
2215  /* identifiers */
2216  ot->name = "Toggle Channel Editability";
2217  ot->idname = "ANIM_OT_channels_editable_toggle";
2218  ot->description = "Toggle editability of selected channels";
2219 
2220  /* api callbacks */
2223 
2224  /* flags */
2226 
2227  /* props */
2228  /* flag-setting mode */
2229  RNA_def_enum(
2231  /* setting to set */
2232  prop = RNA_def_enum(
2234  RNA_def_property_flag(prop, PROP_HIDDEN); /* internal hack - don't expose */
2235 }
2236 
2237 /* ********************** Expand Channels Operator *********************** */
2238 
2240 {
2241  bAnimContext ac;
2242  bool onlysel = true;
2243 
2244  /* get editor data */
2245  if (ANIM_animdata_get_context(C, &ac) == 0) {
2246  return OPERATOR_CANCELLED;
2247  }
2248 
2249  /* only affect selected channels? */
2250  if (RNA_boolean_get(op->ptr, "all")) {
2251  onlysel = false;
2252  }
2253 
2254  /* modify setting */
2256 
2257  /* send notifier that things have changed */
2259 
2260  return OPERATOR_FINISHED;
2261 }
2262 
2264 {
2265  /* identifiers */
2266  ot->name = "Expand Channels";
2267  ot->idname = "ANIM_OT_channels_expand";
2268  ot->description = "Expand (open) all selected expandable animation channels";
2269 
2270  /* api callbacks */
2273 
2274  /* flags */
2276 
2277  /* props */
2278  ot->prop = RNA_def_boolean(
2279  ot->srna, "all", 1, "All", "Expand all channels (not just selected ones)");
2280 }
2281 
2282 /* ********************** Collapse Channels Operator *********************** */
2283 
2285 {
2286  bAnimContext ac;
2287  bool onlysel = true;
2288 
2289  /* get editor data */
2290  if (ANIM_animdata_get_context(C, &ac) == 0) {
2291  return OPERATOR_CANCELLED;
2292  }
2293 
2294  /* only affect selected channels? */
2295  if (RNA_boolean_get(op->ptr, "all")) {
2296  onlysel = false;
2297  }
2298 
2299  /* modify setting */
2301 
2302  /* send notifier that things have changed */
2304 
2305  return OPERATOR_FINISHED;
2306 }
2307 
2309 {
2310  /* identifiers */
2311  ot->name = "Collapse Channels";
2312  ot->idname = "ANIM_OT_channels_collapse";
2313  ot->description = "Collapse (close) all selected expandable animation channels";
2314 
2315  /* api callbacks */
2318 
2319  /* flags */
2321 
2322  /* props */
2323  ot->prop = RNA_def_boolean(
2324  ot->srna, "all", true, "All", "Collapse all channels (not just selected ones)");
2325 }
2326 
2327 /* ************ Remove All "Empty" AnimData Blocks Operator ********* */
2328 /* We define "empty" AnimData blocks here as those which have all 3 of criteria:
2329  * 1) No active action OR that active actions are empty
2330  * Assuming that all legitimate entries will have an action,
2331  * and that empty actions
2332  * 2) No NLA Tracks + NLA Strips
2333  * Assuming that users haven't set up any of these as "placeholders"
2334  * for convenience sake, and that most that exist were either unintentional
2335  * or are no longer wanted
2336  * 3) No drivers
2337  */
2338 
2340 {
2341  bAnimContext ac;
2342 
2343  ListBase anim_data = {NULL, NULL};
2344  bAnimListElem *ale;
2345  int filter;
2346 
2347  /* get editor data */
2348  if (ANIM_animdata_get_context(C, &ac) == 0) {
2349  return OPERATOR_CANCELLED;
2350  }
2351 
2352  /* get animdata blocks */
2355  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2356 
2357  for (ale = anim_data.first; ale; ale = ale->next) {
2358  ID *id = ale->id;
2359  AnimData *adt = ale->data;
2360 
2361  bool action_empty = false;
2362  bool nla_empty = false;
2363  bool drivers_empty = false;
2364 
2365  /* sanity checks */
2366  BLI_assert((id != NULL) && (adt != NULL));
2367 
2368  /* check if this is "empty" and can be deleted */
2369  /* (For now, there are only these 3 criteria) */
2370 
2371  /* 1) Active Action is missing or empty */
2372  if (ELEM(NULL, adt->action, adt->action->curves.first)) {
2373  action_empty = true;
2374  }
2375  else {
2376  /* TODO: check for keyframe + fmodifier data on these too */
2377  }
2378 
2379  /* 2) No NLA Tracks and/or NLA Strips */
2380  if (adt->nla_tracks.first == NULL) {
2381  nla_empty = true;
2382  }
2383  else {
2384  NlaTrack *nlt;
2385 
2386  /* empty tracks? */
2387  for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
2388  if (nlt->strips.first) {
2389  /* stop searching, as we found one that actually had stuff we don't want lost
2390  * NOTE: nla_empty gets reset to false, as a previous track may have been empty
2391  */
2392  nla_empty = false;
2393  break;
2394  }
2395  if (nlt->strips.first == NULL) {
2396  /* this track is empty, but another one may still have stuff in it, so can't break yet */
2397  nla_empty = true;
2398  }
2399  }
2400  }
2401 
2402  /* 3) Drivers */
2403  drivers_empty = (adt->drivers.first == NULL);
2404 
2405  /* remove AnimData? */
2406  if (action_empty && nla_empty && drivers_empty) {
2407  BKE_animdata_free(id, true);
2408  }
2409  }
2410 
2411  /* free temp data */
2412  ANIM_animdata_freelist(&anim_data);
2413 
2414  /* send notifier that things have changed */
2417 
2418  return OPERATOR_FINISHED;
2419 }
2420 
2422 {
2423  /* identifiers */
2424  ot->name = "Remove Empty Animation Data";
2425  ot->idname = "ANIM_OT_channels_clean_empty";
2426  ot->description = "Delete all empty animation data containers from visible data-blocks";
2427 
2428  /* api callbacks */
2431 
2432  /* flags */
2434 }
2435 
2436 /* ******************* Reenable Disabled Operator ******************* */
2437 
2439 {
2440  ScrArea *area = CTX_wm_area(C);
2441 
2442  /* channels region test */
2443  /* TODO: could enhance with actually testing if channels region? */
2444  if (ELEM(NULL, area, CTX_wm_region(C))) {
2445  return false;
2446  }
2447 
2448  /* animation editor test - Action/Dopesheet/etc. and Graph only */
2449  if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH) == 0) {
2450  return false;
2451  }
2452 
2453  return true;
2454 }
2455 
2457 {
2458  bAnimContext ac;
2459 
2460  ListBase anim_data = {NULL, NULL};
2461  bAnimListElem *ale;
2462  int filter;
2463 
2464  /* get editor data */
2465  if (ANIM_animdata_get_context(C, &ac) == 0) {
2466  return OPERATOR_CANCELLED;
2467  }
2468 
2469  /* filter data */
2471  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2472 
2473  /* loop through filtered data and clean curves */
2474  for (ale = anim_data.first; ale; ale = ale->next) {
2475  FCurve *fcu = (FCurve *)ale->data;
2476 
2477  /* remove disabled flags from F-Curves */
2478  fcu->flag &= ~FCURVE_DISABLED;
2479 
2480  /* for drivers, let's do the same too */
2481  if (fcu->driver) {
2482  fcu->driver->flag &= ~DRIVER_FLAG_INVALID;
2483  }
2484 
2485  /* tag everything for updates - in particular, this is needed to get drivers working again */
2486  ale->update |= ANIM_UPDATE_DEPS;
2487  }
2488 
2489  ANIM_animdata_update(&ac, &anim_data);
2490  ANIM_animdata_freelist(&anim_data);
2491 
2492  /* send notifier that things have changed */
2494 
2495  return OPERATOR_FINISHED;
2496 }
2497 
2499 {
2500  /* identifiers */
2501  ot->name = "Revive Disabled F-Curves";
2502  ot->idname = "ANIM_OT_channels_fcurves_enable";
2503  ot->description = "Clears 'disabled' tag from all F-Curves to get broken F-Curves working again";
2504 
2505  /* api callbacks */
2508 
2509  /* flags */
2511 }
2512 
2513 /* ****************** Select Filter Textbox Operator ******************** */
2514 
2515 /* XXX: make this generic? */
2517 {
2518  ScrArea *area = CTX_wm_area(C);
2519 
2520  if (area == NULL) {
2521  return false;
2522  }
2523 
2524  /* animation editor with dopesheet */
2525  return ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA);
2526 }
2527 
2529  struct wmOperator *op,
2530  const struct wmEvent *UNUSED(event))
2531 {
2532  ScrArea *area = CTX_wm_area(C);
2533  ARegion *region_ctx = CTX_wm_region(C);
2535 
2536  CTX_wm_region_set(C, region_channels);
2537 
2538  /* Show the channel region if it's hidden. This means that direct activation of the input field
2539  * is impossible, as it may not exist yet. For that reason, the actual activation is deferred to
2540  * the modal callback function; by the time it runs, the screen has been redrawn and the UI
2541  * element is there to activate. */
2542  if (region_channels->flag & RGN_FLAG_HIDDEN) {
2543  ED_region_toggle_hidden(C, region_channels);
2544  ED_region_tag_redraw(region_channels);
2545  }
2546 
2548 
2549  CTX_wm_region_set(C, region_ctx);
2550  return OPERATOR_RUNNING_MODAL;
2551 }
2552 
2554  wmOperator *UNUSED(op),
2555  const wmEvent *UNUSED(event))
2556 {
2557  bAnimContext ac;
2558  if (ANIM_animdata_get_context(C, &ac) == 0) {
2559  return OPERATOR_CANCELLED;
2560  }
2561 
2562  ARegion *region = CTX_wm_region(C);
2563  if (UI_textbutton_activate_rna(C, region, ac.ads, "filter_text")) {
2564  /* Redraw to make sure it shows the cursor after activating */
2566  }
2567 
2568  return OPERATOR_FINISHED;
2569 }
2570 
2572 {
2573  /* identifiers */
2574  ot->name = "Filter Channels";
2575  ot->idname = "ANIM_OT_channels_select_filter";
2576  ot->description =
2577  "Start entering text which filters the set of channels shown to only include those with "
2578  "matching names";
2579 
2580  /* callbacks */
2584 }
2585 
2586 /* ********************** Select All Operator *********************** */
2587 
2589 {
2590  bAnimContext ac;
2591 
2592  /* get editor data */
2593  if (ANIM_animdata_get_context(C, &ac) == 0) {
2594  return OPERATOR_CANCELLED;
2595  }
2596 
2597  /* 'standard' behavior - check if selected, then apply relevant selection */
2598  const int action = RNA_enum_get(op->ptr, "action");
2599  switch (action) {
2600  case SEL_TOGGLE:
2602  break;
2603  case SEL_SELECT:
2605  break;
2606  case SEL_DESELECT:
2608  break;
2609  case SEL_INVERT:
2611  break;
2612  default:
2613  BLI_assert(0);
2614  break;
2615  }
2616 
2617  /* send notifier that things have changed */
2619 
2620  return OPERATOR_FINISHED;
2621 }
2622 
2624 {
2625  /* identifiers */
2626  ot->name = "Select All";
2627  ot->idname = "ANIM_OT_channels_select_all";
2628  ot->description = "Toggle selection of all animation channels";
2629 
2630  /* api callbacks */
2633 
2634  /* flags */
2636 
2637  /* properties */
2639 }
2640 
2641 /* ******************** Box Select Operator *********************** */
2642 
2643 static void box_select_anim_channels(bAnimContext *ac, rcti *rect, short selectmode)
2644 {
2645  ListBase anim_data = {NULL, NULL};
2646  bAnimListElem *ale;
2647  int filter;
2648 
2649  SpaceNla *snla = (SpaceNla *)ac->sl;
2650  View2D *v2d = &ac->region->v2d;
2651  rctf rectf;
2652 
2653  /* convert border-region to view coordinates */
2654  UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin + 2, &rectf.xmin, &rectf.ymin);
2655  UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax - 2, &rectf.xmax, &rectf.ymax);
2656 
2657  /* filter data */
2659  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
2660 
2661  float ymax;
2662  if (ac->datatype == ANIMCONT_NLA) {
2663  ymax = NLACHANNEL_FIRST_TOP(ac);
2664  }
2665  else {
2666  ymax = ACHANNEL_FIRST_TOP(ac);
2667  }
2668 
2669  /* loop over data, doing box select */
2670  for (ale = anim_data.first; ale; ale = ale->next) {
2671  float ymin;
2672 
2673  if (ale->type == ANIMTYPE_GPDATABLOCK) {
2674  ymax -= ACHANNEL_STEP(ac);
2675  continue;
2676  }
2677 
2678  if (ac->datatype == ANIMCONT_NLA) {
2679  ymin = ymax - NLACHANNEL_STEP(snla);
2680  }
2681  else {
2682  ymin = ymax - ACHANNEL_STEP(ac);
2683  }
2684 
2685  /* if channel is within border-select region, alter it */
2686  if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
2687  /* set selection flags only */
2688  ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, selectmode);
2689 
2690  /* type specific actions */
2691  switch (ale->type) {
2692  case ANIMTYPE_GROUP: {
2693  bActionGroup *agrp = (bActionGroup *)ale->data;
2694  select_pchan_for_action_group(ac, agrp, ale);
2695  /* always clear active flag after doing this */
2696  agrp->flag &= ~AGRP_ACTIVE;
2697  break;
2698  }
2699  case ANIMTYPE_NLATRACK: {
2700  NlaTrack *nlt = (NlaTrack *)ale->data;
2701 
2702  /* for now, it's easier just to do this here manually, as defining a new type
2703  * currently adds complications when doing other stuff
2704  */
2705  ACHANNEL_SET_FLAG(nlt, selectmode, NLATRACK_SELECTED);
2706  break;
2707  }
2708  }
2709  }
2710 
2711  /* set minimum extent to be the maximum of the next channel */
2712  ymax = ymin;
2713  }
2714 
2715  /* cleanup */
2716  ANIM_animdata_freelist(&anim_data);
2717 }
2718 
2719 /* ------------------- */
2720 
2722 {
2723  bAnimContext ac;
2724  rcti rect;
2725  short selectmode = 0;
2726  const bool select = !RNA_boolean_get(op->ptr, "deselect");
2727  const bool extend = RNA_boolean_get(op->ptr, "extend");
2728 
2729  /* get editor data */
2730  if (ANIM_animdata_get_context(C, &ac) == 0) {
2731  return OPERATOR_CANCELLED;
2732  }
2733 
2734  /* get settings from operator */
2736 
2737  if (!extend) {
2739  }
2740 
2741  if (select) {
2742  selectmode = ACHANNEL_SETFLAG_ADD;
2743  }
2744  else {
2745  selectmode = ACHANNEL_SETFLAG_CLEAR;
2746  }
2747 
2748  /* apply box_select animation channels */
2749  box_select_anim_channels(&ac, &rect, selectmode);
2750 
2751  /* send notifier that things have changed */
2753 
2754  return OPERATOR_FINISHED;
2755 }
2756 
2758 {
2759  /* identifiers */
2760  ot->name = "Box Select";
2761  ot->idname = "ANIM_OT_channels_select_box";
2762  ot->description = "Select all animation channels within the specified region";
2763 
2764  /* api callbacks */
2769 
2771 
2772  /* flags */
2774 
2775  /* rna */
2777 }
2778 
2779 /* ******************* Rename Operator ***************************** */
2780 /* Allow renaming some channels by clicking on them */
2781 
2782 static bool rename_anim_channels(bAnimContext *ac, int channel_index)
2783 {
2784  ListBase anim_data = {NULL, NULL};
2785  const bAnimChannelType *acf;
2786  bAnimListElem *ale;
2787  int filter;
2788  bool success = false;
2789 
2790  /* Filter relevant channels (note that greasepencil/annotations are not displayed in Graph
2791  * Editor). */
2795  }
2796  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
2797 
2798  /* Get channel that was clicked on from index. */
2799  ale = BLI_findlink(&anim_data, channel_index);
2800  if (ale == NULL) {
2801  /* channel not found */
2802  if (G.debug & G_DEBUG) {
2803  printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n",
2804  channel_index);
2805  }
2806 
2807  ANIM_animdata_freelist(&anim_data);
2808  return false;
2809  }
2810 
2811  /* Don't allow renaming linked/liboverride channels. */
2812  if (ale->fcurve_owner_id != NULL &&
2814  ANIM_animdata_freelist(&anim_data);
2815  return false;
2816  }
2817  if (ale->id != NULL) {
2818  if (ID_IS_LINKED(ale->id)) {
2819  ANIM_animdata_freelist(&anim_data);
2820  return false;
2821  }
2822  /* There is one exception to not allowing renaming on liboverride channels: locally-inserted
2823  * NLA tracks. */
2824  if (ID_IS_OVERRIDE_LIBRARY(ale->id)) {
2825  switch (ale->type) {
2826  case ANIMTYPE_NLATRACK: {
2827  NlaTrack *nlt = (NlaTrack *)ale->data;
2828  if ((nlt->flag & NLATRACK_OVERRIDELIBRARY_LOCAL) == 0) {
2829  ANIM_animdata_freelist(&anim_data);
2830  return false;
2831  }
2832  break;
2833  }
2834  default:
2835  ANIM_animdata_freelist(&anim_data);
2836  return false;
2837  }
2838  }
2839  }
2840 
2841  /* check that channel can be renamed */
2842  acf = ANIM_channel_get_typeinfo(ale);
2843  if (acf && acf->name_prop) {
2844  PointerRNA ptr;
2845  PropertyRNA *prop;
2846 
2847  /* ok if we can get name property to edit from this channel */
2848  if (acf->name_prop(ale, &ptr, &prop)) {
2849  /* Actually showing the rename text-field is done on redraw,
2850  * so here we just store the index of this channel in the
2851  * dope-sheet data, which will get utilized when drawing the channel.
2852  *
2853  * +1 factor is for backwards compatibility issues. */
2854  if (ac->ads) {
2855  ac->ads->renameIndex = channel_index + 1;
2856  success = true;
2857  }
2858  }
2859  }
2860 
2861  /* free temp data and tag for refresh */
2862  ANIM_animdata_freelist(&anim_data);
2864  return success;
2865 }
2866 
2867 static int animchannels_channel_get(bAnimContext *ac, const int mval[2])
2868 {
2869  ARegion *region;
2870  View2D *v2d;
2871  int channel_index;
2872  float x, y;
2873 
2874  /* get useful pointers from animation context data */
2875  region = ac->region;
2876  v2d = &region->v2d;
2877 
2878  /* Figure out which channel user clicked in. */
2879  UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
2880 
2881  if (ac->datatype == ANIMCONT_NLA) {
2882  SpaceNla *snla = (SpaceNla *)ac->sl;
2884  NLACHANNEL_STEP(snla),
2885  0,
2887  x,
2888  y,
2889  NULL,
2890  &channel_index);
2891  }
2892  else {
2894  ACHANNEL_STEP(ac),
2895  0,
2896  ACHANNEL_FIRST_TOP(ac),
2897  x,
2898  y,
2899  NULL,
2900  &channel_index);
2901  }
2902 
2903  return channel_index;
2904 }
2905 
2907 {
2908  bAnimContext ac;
2909  int channel_index;
2910 
2911  /* get editor data */
2912  if (ANIM_animdata_get_context(C, &ac) == 0) {
2913  return OPERATOR_CANCELLED;
2914  }
2915 
2916  channel_index = animchannels_channel_get(&ac, event->mval);
2917 
2918  /* handle click */
2919  if (rename_anim_channels(&ac, channel_index)) {
2921  return OPERATOR_FINISHED;
2922  }
2923 
2924  /* allow event to be handled by selectall operator */
2925  return OPERATOR_PASS_THROUGH;
2926 }
2927 
2929 {
2930  /* identifiers */
2931  ot->name = "Rename Channels";
2932  ot->idname = "ANIM_OT_channels_rename";
2933  ot->description = "Rename animation channel under mouse";
2934 
2935  /* api callbacks */
2938 }
2939 
2940 /* ******************** Mouse-Click Operator *********************** */
2941 /* Handle selection changes due to clicking on channels. Settings will get caught by UI code... */
2942 
2944  const short /* eEditKeyframes_Select or -1 */ selectmode)
2945 {
2946  Scene *sce = (Scene *)ale->data;
2947  AnimData *adt = sce->adt;
2948 
2949  /* set selection status */
2950  if (selectmode == SELECT_INVERT) {
2951  /* swap select */
2952  sce->flag ^= SCE_DS_SELECTED;
2953  if (adt) {
2954  adt->flag ^= ADT_UI_SELECTED;
2955  }
2956  }
2957  else {
2958  sce->flag |= SCE_DS_SELECTED;
2959  if (adt) {
2960  adt->flag |= ADT_UI_SELECTED;
2961  }
2962  }
2963  return (ND_ANIMCHAN | NA_SELECTED);
2964 }
2965 
2967  bAnimContext *ac,
2968  bAnimListElem *ale,
2969  const short /* eEditKeyframes_Select or -1 */ selectmode)
2970 {
2971  ViewLayer *view_layer = ac->view_layer;
2972  Base *base = (Base *)ale->data;
2973  Object *ob = base->object;
2974  AnimData *adt = ob->adt;
2975 
2976  if ((base->flag & BASE_SELECTABLE) == 0) {
2977  return 0;
2978  }
2979 
2980  if (selectmode == SELECT_INVERT) {
2981  /* swap select */
2983 
2984  if (adt) {
2985  adt->flag ^= ADT_UI_SELECTED;
2986  }
2987  }
2988  else {
2989  Base *b;
2990 
2991  /* deselect all */
2992  /* TODO: should this deselect all other types of channels too? */
2993  for (b = view_layer->object_bases.first; b; b = b->next) {
2995  if (b->object->adt) {
2996  b->object->adt->flag &= ~(ADT_UI_SELECTED | ADT_UI_ACTIVE);
2997  }
2998  }
2999 
3000  /* select object now */
3002  if (adt) {
3003  adt->flag |= ADT_UI_SELECTED;
3004  }
3005  }
3006 
3007  /* Change active object - regardless of whether it is now selected, see: T37883.
3008  *
3009  * Ensure we exit edit-mode on whatever object was active before
3010  * to avoid getting stuck there, see: T48747. */
3011  ED_object_base_activate_with_mode_exit_if_needed(C, base); /* adds notifier */
3012 
3013  if ((adt) && (adt->flag & ADT_UI_SELECTED)) {
3014  adt->flag |= ADT_UI_ACTIVE;
3015  }
3016 
3017  return (ND_ANIMCHAN | NA_SELECTED);
3018 }
3019 
3021  bAnimListElem *ale,
3022  const short /* eEditKeyframes_Select or -1 */ selectmode)
3023 {
3024  if (ale->adt == NULL) {
3025  return 0;
3026  }
3027 
3028  /* select/deselect */
3029  if (selectmode == SELECT_INVERT) {
3030  /* inverse selection status of this AnimData block only */
3031  ale->adt->flag ^= ADT_UI_SELECTED;
3032  }
3033  else {
3034  /* select AnimData block by itself */
3036  ale->adt->flag |= ADT_UI_SELECTED;
3037  }
3038 
3039  /* set active? */
3040  if (ale->adt->flag & ADT_UI_SELECTED) {
3041  ale->adt->flag |= ADT_UI_ACTIVE;
3042  }
3043 
3044  return (ND_ANIMCHAN | NA_SELECTED);
3045 }
3046 
3048  bAnimListElem *ale,
3049  const short /* eEditKeyframes_Select or -1 */ selectmode,
3050  const int filter)
3051 {
3052  bActionGroup *agrp = (bActionGroup *)ale->data;
3053  Object *ob = NULL;
3054  bPoseChannel *pchan = NULL;
3055 
3056  /* Armatures-Specific Feature:
3057  * Since groups are used to collect F-Curves of the same Bone by default
3058  * (via Keying Sets) so that they can be managed better, we try to make
3059  * things here easier for animators by mapping group selection to bone
3060  * selection.
3061  *
3062  * Only do this if "Only Selected" dopesheet filter is not active, or else it
3063  * becomes too unpredictable/tricky to manage
3064  */
3065  if ((ac->ads->filterflag & ADS_FILTER_ONLYSEL) == 0) {
3066  if ((ale->id) && (GS(ale->id->name) == ID_OB)) {
3067  ob = (Object *)ale->id;
3068 
3069  if (ob->type == OB_ARMATURE) {
3070  /* Assume for now that any group with corresponding name is what we want
3071  * (i.e. for an armature whose location is animated, things would break
3072  * if the user were to add a bone named "Location").
3073  *
3074  * TODO: check the first F-Curve or so to be sure...
3075  */
3076  pchan = BKE_pose_channel_find_name(ob->pose, agrp->name);
3077  }
3078  }
3079  }
3080 
3081  /* select/deselect group */
3082  if (selectmode == SELECT_INVERT) {
3083  /* inverse selection status of this group only */
3084  agrp->flag ^= AGRP_SELECTED;
3085  }
3086  else if (selectmode == -1) {
3087  /* select all in group (and deselect everything else) */
3088  FCurve *fcu;
3089 
3090  /* deselect all other channels */
3092  if (pchan) {
3093  ED_pose_deselect_all(ob, SEL_DESELECT, false);
3094  }
3095 
3096  /* only select channels in group and group itself */
3097  for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) {
3098  fcu->flag |= FCURVE_SELECTED;
3099  }
3100  agrp->flag |= AGRP_SELECTED;
3101  }
3102  else {
3103  /* select group by itself */
3105  if (pchan) {
3106  ED_pose_deselect_all(ob, SEL_DESELECT, false);
3107  }
3108 
3109  agrp->flag |= AGRP_SELECTED;
3110  }
3111 
3112  /* if group is selected now, make group the 'active' one in the visible list */
3113  if (agrp->flag & AGRP_SELECTED) {
3115  if (pchan) {
3116  ED_pose_bone_select(ob, pchan, true);
3117  }
3118  }
3119  else {
3121  if (pchan) {
3122  ED_pose_bone_select(ob, pchan, false);
3123  }
3124  }
3125 
3126  return (ND_ANIMCHAN | NA_SELECTED);
3127 }
3128 
3130  bAnimListElem *ale,
3131  const short /* eEditKeyframes_Select or -1 */ selectmode,
3132  const int filter)
3133 {
3134  FCurve *fcu = (FCurve *)ale->data;
3135 
3136  /* select/deselect */
3137  if (selectmode == SELECT_INVERT) {
3138  /* inverse selection status of this F-Curve only */
3139  fcu->flag ^= FCURVE_SELECTED;
3140  }
3141  else {
3142  /* select F-Curve by itself */
3144  fcu->flag |= FCURVE_SELECTED;
3145  }
3146 
3147  /* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */
3148  if (fcu->flag & FCURVE_SELECTED) {
3149  ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
3150  }
3151 
3152  return (ND_ANIMCHAN | NA_SELECTED);
3153 }
3154 
3156  bAnimListElem *ale,
3157  const short /* eEditKeyframes_Select or -1 */ selectmode)
3158 {
3159  KeyBlock *kb = (KeyBlock *)ale->data;
3160 
3161  /* select/deselect */
3162  if (selectmode == SELECT_INVERT) {
3163  /* inverse selection status of this ShapeKey only */
3164  kb->flag ^= KEYBLOCK_SEL;
3165  }
3166  else {
3167  /* select ShapeKey by itself */
3169  kb->flag |= KEYBLOCK_SEL;
3170  }
3171 
3172  return (ND_ANIMCHAN | NA_SELECTED);
3173 }
3174 
3176 {
3177  AnimData *adt = (AnimData *)ale->data;
3178 
3179  /* Toggle expand:
3180  * - Although the triangle widget already allows this,
3181  * since there's nothing else that can be done here now,
3182  * let's just use it for easier expand/collapse for now.
3183  */
3184  adt->flag ^= ADT_NLA_SKEYS_COLLAPSED;
3185 
3187 }
3188 
3190 {
3191  bGPdata *gpd = (bGPdata *)ale->data;
3192 
3193  /* Toggle expand:
3194  * - Although the triangle widget already allows this,
3195  * the whole channel can also be used for this purpose.
3196  */
3197  gpd->flag ^= GP_DATA_EXPAND;
3198 
3200 }
3201 
3203  bAnimContext *ac,
3204  bAnimListElem *ale,
3205  const short /* eEditKeyframes_Select or -1 */ selectmode,
3206  const int filter)
3207 {
3208  bGPdata *gpd = (bGPdata *)ale->id;
3209  bGPDlayer *gpl = (bGPDlayer *)ale->data;
3210 
3211  /* select/deselect */
3212  if (selectmode == SELECT_INVERT) {
3213  /* invert selection status of this layer only */
3214  gpl->flag ^= GP_LAYER_SELECT;
3215  }
3216  else {
3217  /* select layer by itself */
3219  gpl->flag |= GP_LAYER_SELECT;
3220  }
3221 
3222  /* change active layer, if this is selected (since we must always have an active layer) */
3223  if (gpl->flag & GP_LAYER_SELECT) {
3225  /* update other layer status */
3226  BKE_gpencil_layer_active_set(gpd, gpl);
3227  BKE_gpencil_layer_autolock_set(gpd, false);
3229  }
3230 
3231  /* Grease Pencil updates */
3233  return (ND_ANIMCHAN | NA_EDITED); /* Animation Editors updates */
3234 }
3235 
3237 {
3238  Mask *mask = (Mask *)ale->data;
3239 
3240  /* Toggle expand
3241  * - Although the triangle widget already allows this,
3242  * the whole channel can also be used for this purpose.
3243  */
3244  mask->flag ^= MASK_ANIMF_EXPAND;
3245 
3247 }
3248 
3250  bAnimListElem *ale,
3251  const short /* eEditKeyframes_Select or -1 */ selectmode)
3252 {
3253  MaskLayer *masklay = (MaskLayer *)ale->data;
3254 
3255  /* select/deselect */
3256  if (selectmode == SELECT_INVERT) {
3257  /* invert selection status of this layer only */
3258  masklay->flag ^= MASK_LAYERFLAG_SELECT;
3259  }
3260  else {
3261  /* select layer by itself */
3263  masklay->flag |= MASK_LAYERFLAG_SELECT;
3264  }
3265 
3266  return (ND_ANIMCHAN | NA_EDITED);
3267 }
3268 
3270  bAnimContext *ac,
3271  const int channel_index,
3272  const short /* eEditKeyframes_Select or -1 */ selectmode)
3273 {
3274  ListBase anim_data = {NULL, NULL};
3275  bAnimListElem *ale;
3276  int filter;
3277  int notifierFlags = 0;
3278  ScrArea *area = CTX_wm_area(C);
3279 
3280  /* get the channel that was clicked on */
3281  /* filter channels */
3283  if (ELEM(area->spacetype, SPACE_NLA, SPACE_GRAPH)) {
3285  }
3286  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
3287 
3288  /* get channel from index */
3289  ale = BLI_findlink(&anim_data, channel_index);
3290  if (ale == NULL) {
3291  /* channel not found */
3292  if (G.debug & G_DEBUG) {
3293  printf("Error: animation channel (index = %d) not found in mouse_anim_channels()\n",
3294  channel_index);
3295  }
3296 
3297  ANIM_animdata_freelist(&anim_data);
3298  return 0;
3299  }
3300 
3301  /* selectmode -1 is a special case for ActionGroups only,
3302  * which selects all of the channels underneath it only. */
3303  /* TODO: should this feature be extended to work with other channel types too? */
3304  if ((selectmode == -1) && (ale->type != ANIMTYPE_GROUP)) {
3305  /* normal channels should not behave normally in this case */
3306  ANIM_animdata_freelist(&anim_data);
3307  return 0;
3308  }
3309 
3310  /* action to take depends on what channel we've got */
3311  /* WARNING: must keep this in sync with the equivalent function in nla_channels.c */
3312  switch (ale->type) {
3313  case ANIMTYPE_SCENE:
3314  notifierFlags |= click_select_channel_scene(ale, selectmode);
3315  break;
3316  case ANIMTYPE_OBJECT:
3317  notifierFlags |= click_select_channel_object(C, ac, ale, selectmode);
3318  break;
3319  case ANIMTYPE_FILLACTD: /* Action Expander */
3320  case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
3321  case ANIMTYPE_DSLAM:
3322  case ANIMTYPE_DSCAM:
3323  case ANIMTYPE_DSCACHEFILE:
3324  case ANIMTYPE_DSCUR:
3325  case ANIMTYPE_DSSKEY:
3326  case ANIMTYPE_DSWOR:
3327  case ANIMTYPE_DSPART:
3328  case ANIMTYPE_DSMBALL:
3329  case ANIMTYPE_DSARM:
3330  case ANIMTYPE_DSMESH:
3331  case ANIMTYPE_DSNTREE:
3332  case ANIMTYPE_DSTEX:
3333  case ANIMTYPE_DSLAT:
3334  case ANIMTYPE_DSLINESTYLE:
3335  case ANIMTYPE_DSSPK:
3336  case ANIMTYPE_DSGPENCIL:
3337  case ANIMTYPE_DSMCLIP:
3338  case ANIMTYPE_DSHAIR:
3339  case ANIMTYPE_DSPOINTCLOUD:
3340  case ANIMTYPE_DSVOLUME:
3341  case ANIMTYPE_DSSIMULATION:
3342  notifierFlags |= click_select_channel_dummy(ac, ale, selectmode);
3343  break;
3344  case ANIMTYPE_GROUP:
3345  notifierFlags |= click_select_channel_group(ac, ale, selectmode, filter);
3346  break;
3347  case ANIMTYPE_FCURVE:
3348  case ANIMTYPE_NLACURVE:
3349  notifierFlags |= click_select_channel_fcurve(ac, ale, selectmode, filter);
3350  break;
3351  case ANIMTYPE_SHAPEKEY:
3352  notifierFlags |= click_select_channel_shapekey(ac, ale, selectmode);
3353  break;
3354  case ANIMTYPE_NLACONTROLS:
3355  notifierFlags |= click_select_channel_nlacontrols(ale);
3356  break;
3357  case ANIMTYPE_GPDATABLOCK:
3358  notifierFlags |= click_select_channel_gpdatablock(ale);
3359  break;
3360  case ANIMTYPE_GPLAYER:
3361  notifierFlags |= click_select_channel_gplayer(C, ac, ale, selectmode, filter);
3362  break;
3364  notifierFlags |= click_select_channel_maskdatablock(ale);
3365  break;
3366  case ANIMTYPE_MASKLAYER:
3367  notifierFlags |= click_select_channel_masklayer(ac, ale, selectmode);
3368  break;
3369  default:
3370  if (G.debug & G_DEBUG) {
3371  printf("Error: Invalid channel type in mouse_anim_channels()\n");
3372  }
3373  break;
3374  }
3375 
3376  /* free channels */
3377  ANIM_animdata_freelist(&anim_data);
3378 
3379  /* return notifier flags */
3380  return notifierFlags;
3381 }
3382 
3383 /* ------------------- */
3384 
3385 /* handle clicking */
3387 {
3388  bAnimContext ac;
3389  ARegion *region;
3390  View2D *v2d;
3391  int channel_index;
3392  int notifierFlags = 0;
3393  short selectmode;
3394  float x, y;
3395 
3396  /* get editor data */
3397  if (ANIM_animdata_get_context(C, &ac) == 0) {
3398  return OPERATOR_CANCELLED;
3399  }
3400 
3401  /* get useful pointers from animation context data */
3402  region = ac.region;
3403  v2d = &region->v2d;
3404 
3405  /* select mode is either replace (deselect all, then add) or add/extend */
3406  if (RNA_boolean_get(op->ptr, "extend")) {
3407  selectmode = SELECT_INVERT;
3408  }
3409  else if (RNA_boolean_get(op->ptr, "children_only")) {
3410  /* this is a bit of a special case for ActionGroups only...
3411  * should it be removed or extended to all instead? */
3412  selectmode = -1;
3413  }
3414  else {
3415  selectmode = SELECT_REPLACE;
3416  }
3417 
3418  /* figure out which channel user clicked in */
3419  UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
3421  ACHANNEL_STEP(&ac),
3422  0,
3423  ACHANNEL_FIRST_TOP(&ac),
3424  x,
3425  y,
3426  NULL,
3427  &channel_index);
3428 
3429  /* handle mouse-click in the relevant channel then */
3430  notifierFlags = mouse_anim_channels(C, &ac, channel_index, selectmode);
3431 
3432  /* set notifier that things have changed */
3433  WM_event_add_notifier(C, NC_ANIMATION | notifierFlags, NULL);
3434 
3436  event);
3437 }
3438 
3440 {
3441  PropertyRNA *prop;
3442 
3443  /* identifiers */
3444  ot->name = "Mouse Click on Channels";
3445  ot->idname = "ANIM_OT_channels_click";
3446  ot->description = "Handle mouse clicks over animation channels";
3447 
3448  /* api callbacks */
3451 
3452  /* flags */
3453  ot->flag = OPTYPE_UNDO;
3454 
3455  /* properties */
3456  /* NOTE: don't save settings, otherwise, can end up with some weird behavior (sticky extend)
3457  *
3458  * Key-map: Enable with `Shift`. */
3459  prop = RNA_def_boolean(ot->srna, "extend", false, "Extend Select", "");
3461 
3462  /* Key-map: Enable with `Ctrl-Shift`. */
3463  prop = RNA_def_boolean(ot->srna, "children_only", false, "Select Children Only", "");
3465 }
3466 
3467 static bool select_anim_channel_keys(bAnimContext *ac, int channel_index, bool extend)
3468 {
3469  ListBase anim_data = {NULL, NULL};
3470  bAnimListElem *ale;
3471  int filter;
3472  bool success = false;
3473  FCurve *fcu;
3474  int i;
3475 
3476  /* get the channel that was clicked on */
3477  /* filter channels */
3480  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
3481 
3482  /* get channel from index */
3483  ale = BLI_findlink(&anim_data, channel_index);
3484  if (ale == NULL) {
3485  /* channel not found */
3486  if (G.debug & G_DEBUG) {
3487  printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n",
3488  channel_index);
3489  }
3490 
3491  ANIM_animdata_freelist(&anim_data);
3492  return false;
3493  }
3494 
3495  /* Only FCuves can have their keys selected. */
3496  if (ale->datatype != ALE_FCURVE) {
3497  ANIM_animdata_freelist(&anim_data);
3498  return false;
3499  }
3500 
3501  fcu = (FCurve *)ale->key_data;
3502  success = (fcu != NULL);
3503 
3504  ANIM_animdata_freelist(&anim_data);
3505 
3506  /* F-Curve may not have any keyframes */
3507  if (fcu && fcu->bezt) {
3508  BezTriple *bezt;
3509 
3510  if (!extend) {
3512  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
3513  for (ale = anim_data.first; ale; ale = ale->next) {
3514  FCurve *fcu_inner = (FCurve *)ale->key_data;
3515 
3516  if (fcu_inner != NULL && fcu_inner->bezt != NULL) {
3517  for (i = 0, bezt = fcu_inner->bezt; i < fcu_inner->totvert; i++, bezt++) {
3518  bezt->f2 = bezt->f1 = bezt->f3 = 0;
3519  }
3520  }
3521  }
3522 
3523  ANIM_animdata_freelist(&anim_data);
3524  }
3525 
3526  for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
3527  bezt->f2 = bezt->f1 = bezt->f3 = SELECT;
3528  }
3529  }
3530 
3531  /* free temp data and tag for refresh */
3533  return success;
3534 }
3535 
3537  wmOperator *op,
3538  const wmEvent *event)
3539 {
3540  bAnimContext ac;
3541  int channel_index;
3542  bool extend = RNA_boolean_get(op->ptr, "extend");
3543 
3544  /* get editor data */
3545  if (ANIM_animdata_get_context(C, &ac) == 0) {
3546  return OPERATOR_CANCELLED;
3547  }
3548 
3549  channel_index = animchannels_channel_get(&ac, event->mval);
3550 
3551  /* handle click */
3552  if (select_anim_channel_keys(&ac, channel_index, extend)) {
3554  return OPERATOR_FINISHED;
3555  }
3556 
3557  /* allow event to be handled by selectall operator */
3558  return OPERATOR_PASS_THROUGH;
3559 }
3560 
3562 {
3563  PropertyRNA *prop;
3564 
3565  /* identifiers */
3566  ot->name = "Select Channel Keyframes";
3567  ot->idname = "ANIM_OT_channel_select_keys";
3568  ot->description = "Select all keyframes of channel under mouse";
3569 
3570  /* api callbacks */
3573 
3574  prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection");
3576 }
3577 
3578 /* ************************************************************************** */
3579 /* Operator Registration */
3580 
3582 {
3585 
3589 
3591 
3595 
3597 
3598  /* XXX does this need to be a separate operator? */
3600 
3602 
3605 
3607 
3609 
3612 }
3613 
3614 /* TODO: check on a poll callback for this, to get hotkeys into menus */
3616 {
3617  WM_keymap_ensure(keyconf, "Animation Channels", 0, 0);
3618 }
3619 
3620 /* ************************************************************************** */
Blender kernel action and pose functionality.
struct bActionGroup * action_groups_add_new(struct bAction *act, const char name[])
Definition: action.c:410
struct bPoseChannel * BKE_pose_channel_find_name(const struct bPose *pose, const char *name)
void action_groups_remove_channel(struct bAction *act, struct FCurve *fcu)
Definition: action.c:542
void action_groups_add_channel(struct bAction *act, struct bActionGroup *agrp, struct FCurve *fcurve)
Definition: action.c:435
void BKE_animdata_free(struct ID *id, bool do_id_user)
Definition: anim_data.c:197
struct AnimData * BKE_animdata_from_id(const struct ID *id)
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:738
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
void CTX_wm_region_set(bContext *C, struct ARegion *region)
Definition: context.c:1009
struct SpaceLink * CTX_wm_space_data(const bContext *C)
Definition: context.c:743
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_fcurve_free(struct FCurve *fcu)
Definition: fcurve.c:65
@ G_DEBUG
Definition: BKE_global.h:174
void BKE_gpencil_layer_active_set(struct bGPdata *gpd, struct bGPDlayer *active)
Definition: gpencil.c:1601
void BKE_gpencil_free_data(struct bGPdata *gpd, bool free_all)
Definition: gpencil.c:479
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl)
Definition: gpencil.c:1653
void BKE_gpencil_layer_autolock_set(struct bGPdata *gpd, bool unlock)
Definition: gpencil.c:1623
void id_us_min(struct ID *id)
Definition: lib_id.c:313
void BKE_id_free_us(struct Main *bmain, void *idv) ATTR_NONNULL()
void BKE_mask_layer_remove(struct Mask *mask, struct MaskLayer *masklay)
Definition: mask.c:371
bool BKE_nlatrack_is_nonlocal_in_liboverride(const struct ID *id, const struct NlaTrack *nlt)
struct ARegion * BKE_area_find_region_type(const struct ScrArea *area, int type)
#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
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:239
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:354
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:301
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:466
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:340
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_findptr(const struct ListBase *listbase, const void *ptr, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
#define UNUSED(x)
#define ELEM(...)
#define STREQ(a, b)
void DEG_id_tag_update_ex(struct Main *bmain, struct ID *id, int flag)
void DEG_id_tag_update(struct ID *id, int flag)
void DEG_relations_tag_update(struct Main *bmain)
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:771
@ ID_RECALC_ANIMATION
Definition: DNA_ID.h:794
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:566
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition: DNA_ID.h:588
@ ID_OB
Definition: DNA_ID_enums.h:47
@ ADS_FILTER_ONLYSEL
@ AGRP_TEMP
@ AGRP_ACTIVE
@ AGRP_SELECTED
@ AGRP_EXPANDED
@ AGRP_MOVED
@ SACTCONT_ACTION
@ SACTCONT_DOPESHEET
@ NLASTRIP_FLAG_USR_INFLUENCE
@ NLASTRIP_FLAG_USR_TIME
@ ADT_NLA_SKEYS_COLLAPSED
@ ADT_UI_ACTIVE
@ ADT_UI_SELECTED
@ ADT_NLA_EDIT_ON
@ DRIVER_FLAG_INVALID
@ FCURVE_DISABLED
@ FCURVE_ACTIVE
@ FCURVE_SELECTED
@ NLATRACK_ACTIVE
@ NLATRACK_SELECTED
@ NLATRACK_OVERRIDELIBRARY_LOCAL
#define MAX_NAME
Definition: DNA_defs.h:48
@ GP_LAYER_ACTIVE
@ GP_LAYER_SELECT
@ GP_DATA_EXPAND
@ GP_DATA_ANNOTATIONS
@ KEYBLOCK_SEL
@ BASE_SELECTABLE
@ MASK_LAYERFLAG_SELECT
@ MASK_ANIMF_EXPAND
Object is a sort of wrapper for general info.
@ OB_ARMATURE
#define SCE_NLA_EDIT_ON
#define SCE_DS_SELECTED
@ RGN_FLAG_HIDDEN
@ RGN_TYPE_CHANNELS
@ SPACE_ACTION
@ SPACE_NLA
@ SPACE_GRAPH
@ SIPO_MODE_ANIMATION
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
eAnimChannels_SetFlag
Definition: ED_anim_api.h:548
@ ACHANNEL_SETFLAG_TOGGLE
Definition: ED_anim_api.h:556
@ ACHANNEL_SETFLAG_ADD
Definition: ED_anim_api.h:552
@ ACHANNEL_SETFLAG_INVERT
Definition: ED_anim_api.h:554
@ ACHANNEL_SETFLAG_CLEAR
Definition: ED_anim_api.h:550
#define ACHANNEL_NAMEWIDTH
Definition: ED_anim_api.h:448
eAnim_ChannelType
Definition: ED_anim_api.h:189
@ ANIMTYPE_DSSPK
Definition: ED_anim_api.h:222
@ ANIMTYPE_DSTEX
Definition: ED_anim_api.h:219
@ ANIMTYPE_DSNTREE
Definition: ED_anim_api.h:214
@ ANIMTYPE_NLACURVE
Definition: ED_anim_api.h:202
@ ANIMTYPE_SHAPEKEY
Definition: ED_anim_api.h:230
@ ANIMTYPE_DSMBALL
Definition: ED_anim_api.h:216
@ ANIMTYPE_DSCAM
Definition: ED_anim_api.h:209
@ ANIMTYPE_DSPOINTCLOUD
Definition: ED_anim_api.h:226
@ ANIMTYPE_DSPART
Definition: ED_anim_api.h:215
@ ANIMTYPE_DSLINESTYLE
Definition: ED_anim_api.h:221
@ ANIMTYPE_GROUP
Definition: ED_anim_api.h:198
@ ANIMTYPE_DSCUR
Definition: ED_anim_api.h:211
@ ANIMTYPE_SCENE
Definition: ED_anim_api.h:196
@ ANIMTYPE_DSARM
Definition: ED_anim_api.h:217
@ ANIMTYPE_NLACONTROLS
Definition: ED_anim_api.h:201
@ ANIMTYPE_GPLAYER
Definition: ED_anim_api.h:233
@ ANIMTYPE_MASKDATABLOCK
Definition: ED_anim_api.h:235
@ ANIMTYPE_MASKLAYER
Definition: ED_anim_api.h:236
@ ANIMTYPE_DSSIMULATION
Definition: ED_anim_api.h:228
@ ANIMTYPE_DSGPENCIL
Definition: ED_anim_api.h:223
@ ANIMTYPE_DSLAT
Definition: ED_anim_api.h:220
@ ANIMTYPE_NLAACTION
Definition: ED_anim_api.h:239
@ ANIMTYPE_DSMCLIP
Definition: ED_anim_api.h:224
@ ANIMTYPE_DSMAT
Definition: ED_anim_api.h:207
@ ANIMTYPE_DSCACHEFILE
Definition: ED_anim_api.h:210
@ ANIMTYPE_DSVOLUME
Definition: ED_anim_api.h:227
@ ANIMTYPE_FCURVE
Definition: ED_anim_api.h:199
@ ANIMTYPE_DSLAM
Definition: ED_anim_api.h:208
@ ANIMTYPE_GPDATABLOCK
Definition: ED_anim_api.h:232
@ ANIMTYPE_FILLACTD
Definition: ED_anim_api.h:204
@ ANIMTYPE_OBJECT
Definition: ED_anim_api.h:197
@ ANIMTYPE_DSMESH
Definition: ED_anim_api.h:218
@ ANIMTYPE_NLATRACK
Definition: ED_anim_api.h:238
@ ANIMTYPE_DSWOR
Definition: ED_anim_api.h:213
@ ANIMTYPE_DSSKEY
Definition: ED_anim_api.h:212
@ ANIMTYPE_DSHAIR
Definition: ED_anim_api.h:225
#define SEL_AGRP(agrp)
Definition: ED_anim_api.h:395
#define ACHANNEL_FIRST_TOP(ac)
Definition: ED_anim_api.h:438
#define NLACHANNEL_STEP(snla)
Definition: ED_anim_api.h:466
#define SEL_GPL(gpl)
Definition: ED_anim_api.h:409
#define NLACHANNEL_NAMEWIDTH
Definition: ED_anim_api.h:472
#define EXPANDED_AGRP(ac, agrp)
Definition: ED_anim_api.h:392
@ ALE_FCURVE
Definition: ED_anim_api.h:250
@ ANIM_UPDATE_DEPS
Definition: ED_anim_api.h:268
eAnimCont_Types
Definition: ED_anim_api.h:102
@ ANIMCONT_DRIVERS
Definition: ED_anim_api.h:109
@ ANIMCONT_FCURVES
Definition: ED_anim_api.h:108
@ ANIMCONT_NLA
Definition: ED_anim_api.h:110
@ ANIMCONT_MASK
Definition: ED_anim_api.h:112
@ ANIMCONT_SHAPEKEY
Definition: ED_anim_api.h:105
@ ANIMCONT_ACTION
Definition: ED_anim_api.h:104
@ ANIMCONT_GPENCIL
Definition: ED_anim_api.h:106
@ ANIMCONT_CHANNEL
Definition: ED_anim_api.h:111
#define SEL_FCU(fcu)
Definition: ED_anim_api.h:398
#define NLACHANNEL_FIRST_TOP(ac)
Definition: ED_anim_api.h:460
eAnimChannel_Settings
Definition: ED_anim_api.h:560
@ ACHANNEL_SETTING_ALWAYS_VISIBLE
Definition: ED_anim_api.h:574
@ ACHANNEL_SETTING_MUTE
Definition: ED_anim_api.h:564
@ ACHANNEL_SETTING_PROTECT
Definition: ED_anim_api.h:563
@ ACHANNEL_SETTING_VISIBLE
Definition: ED_anim_api.h:567
@ ACHANNEL_SETTING_EXPAND
Definition: ED_anim_api.h:565
@ ACHANNEL_SETTING_SELECT
Definition: ED_anim_api.h:561
#define ACHANNEL_STEP(ac)
Definition: ED_anim_api.h:442
#define ACHANNEL_SET_FLAG(channel, smode, sflag)
Definition: ED_anim_api.h:977
#define EXPANDED_DRVD(adt)
Definition: ED_anim_api.h:387
#define SEL_NLT(nlt)
Definition: ED_anim_api.h:419
eAnimFilter_Flags
Definition: ED_anim_api.h:284
@ ANIMFILTER_FOREDIT
Definition: ED_anim_api.h:312
@ ANIMFILTER_ANIMDATA
Definition: ED_anim_api.h:322
@ ANIMFILTER_DATA_VISIBLE
Definition: ED_anim_api.h:292
@ ANIMFILTER_CURVE_VISIBLE
Definition: ED_anim_api.h:297
@ ANIMFILTER_LIST_VISIBLE
Definition: ED_anim_api.h:295
@ ANIMFILTER_LIST_CHANNELS
Definition: ED_anim_api.h:300
@ ANIMFILTER_NODUPLIS
Definition: ED_anim_api.h:325
@ ANIMFILTER_FCURVESONLY
Definition: ED_anim_api.h:328
@ ANIMFILTER_SEL
Definition: ED_anim_api.h:308
@ SELECT_INVERT
@ SELECT_REPLACE
void ED_object_base_activate_with_mode_exit_if_needed(struct bContext *C, struct Base *base)
void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode)
Definition: object_select.c:76
@ BA_DESELECT
Definition: ED_object.h:154
@ BA_INVERT
Definition: ED_object.h:156
@ BA_SELECT
Definition: ED_object.h:155
void ED_region_toggle_hidden(struct bContext *C, struct ARegion *region)
Definition: area.c:2117
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_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.
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
@ PROP_HIDDEN
Definition: RNA_types.h:216
#define C
Definition: RandGen.cpp:25
bool UI_textbutton_activate_rna(const struct bContext *C, struct ARegion *region, const void *rna_poin_data, const char *rna_prop_id)
void UI_view2d_listview_view_to_cell(float columnwidth, float rowheight, float startx, float starty, float viewx, float viewy, int *r_column, int *r_row)
Definition: view2d.cc:1619
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define ND_DATA
Definition: WM_types.h:456
#define NC_ANIMATION
Definition: WM_types.h:338
#define ND_SPACE_PROPERTIES
Definition: WM_types.h:472
#define NA_EDITED
Definition: WM_types.h:523
#define NA_REMOVED
Definition: WM_types.h:526
#define ND_NLA_ORDER
Definition: WM_types.h:448
#define NC_GPENCIL
Definition: WM_types.h:349
#define ND_NLA
Definition: WM_types.h:445
#define NA_RENAME
Definition: WM_types.h:527
#define ND_KEYFRAME
Definition: WM_types.h:442
#define ND_ANIMCHAN
Definition: WM_types.h:444
#define NA_SELECTED
Definition: WM_types.h:528
void ANIM_channel_setting_set(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode)
short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
const bAnimChannelType * ANIM_channel_get_typeinfo(bAnimListElem *ale)
static int animchannels_select_filter_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *UNUSED(event))
static int animchannels_expand_exec(bContext *C, wmOperator *op)
static int animchannels_collapse_exec(bContext *C, wmOperator *op)
static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
static void rearrange_gpencil_channels(bAnimContext *ac, eRearrangeAnimChan_Mode mode)
void ED_operatortypes_animchannels(void)
static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
static void anim_flush_channel_setting_down(bAnimContext *ac, const eAnimChannel_Settings setting, const eAnimChannels_SetFlag mode, bAnimListElem *const match, const int matchLevel)
static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode)
void ANIM_anim_channels_select_set(bAnimContext *ac, eAnimChannels_SetFlag sel)
static bool animchannels_enable_poll(bContext *C)
static void join_groups_action_temp(bAction *act)
static void tag_update_animation_element(bAnimListElem *ale)
static void ANIM_OT_channel_select_keys(wmOperatorType *ot)
eReorderIslandFlag
@ REORDER_ISLAND_UNTOUCHABLE
@ REORDER_ISLAND_MOVED
@ REORDER_ISLAND_SELECTED
@ REORDER_ISLAND_HIDDEN
void ED_keymap_animchannels(wmKeyConfig *keyconf)
static void split_groups_action_temp(bAction *act, bActionGroup *tgrp)
static bool animchannels_select_filter_poll(bContext *C)
static const EnumPropertyItem prop_animchannel_rearrange_types[]
static void setflag_anim_channels(bAnimContext *ac, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode, bool onlysel, bool flush)
static void ANIM_OT_channels_clean_empty(wmOperatorType *ot)
static bool rearrange_island_bottom(ListBase *list, tReorderChannelIsland *island)
static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *srcList, Link *channel, eAnim_ChannelType type, const bool is_hidden)
static void box_select_anim_channels(bAnimContext *ac, rcti *rect, short selectmode)
static bool rearrange_island_up(ListBase *list, tReorderChannelIsland *island)
static int animchannels_group_exec(bContext *C, wmOperator *op)
static bool select_anim_channel_keys(bAnimContext *ac, int channel_index, bool extend)
static int click_select_channel_maskdatablock(bAnimListElem *ale)
static int click_select_channel_object(bContext *C, bAnimContext *ac, bAnimListElem *ale, const short selectmode)
static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
static void anim_flush_channel_setting_up(bAnimContext *ac, const eAnimChannel_Settings setting, const eAnimChannels_SetFlag mode, bAnimListElem *const match, const int matchLevel)
static void ANIM_OT_channels_delete(wmOperatorType *ot)
static int animchannels_channel_get(bAnimContext *ac, const int mval[2])
static int click_select_channel_group(bAnimContext *ac, bAnimListElem *ale, const short selectmode, const int filter)
bool(* AnimChanRearrangeFp)(ListBase *list, tReorderChannelIsland *island)
static void rearrange_driver_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
static void rearrange_animchannel_flatten_islands(ListBase *islands, ListBase *srcList)
static const EnumPropertyItem prop_animchannel_settings_types[]
bool ANIM_remove_empty_action_from_animdata(struct AnimData *adt)
static bool animedit_poll_channels_active(bContext *C)
static int animchannels_ungroup_exec(bContext *C, wmOperator *UNUSED(op))
static ListBase anim_channels_for_selection(bAnimContext *ac)
static void ANIM_OT_channels_expand(wmOperatorType *ot)
static void ANIM_OT_channels_rename(wmOperatorType *ot)
static int click_select_channel_shapekey(bAnimContext *ac, bAnimListElem *ale, const short selectmode)
static bool animedit_poll_channels_nla_tweakmode_off(bContext *C)
void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datatype, eAnimFilter_Flags filter, void *channel_data, eAnim_ChannelType channel_type)
static int click_select_channel_gpdatablock(bAnimListElem *ale)
static void animchannels_group_channels(bAnimContext *ac, bAnimListElem *adt_ref, const char name[])
static bool rename_anim_channels(bAnimContext *ac, int channel_index)
static int animchannels_select_filter_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
static int click_select_channel_nlacontrols(bAnimListElem *ale)
static bool rearrange_island_down(ListBase *list, tReorderChannelIsland *island)
static void ANIM_OT_channels_select_box(wmOperatorType *ot)
static void ANIM_OT_channels_editable_toggle(wmOperatorType *ot)
static bool rearrange_island_top(ListBase *list, tReorderChannelIsland *island)
static int animchannels_enable_exec(bContext *C, wmOperator *UNUSED(op))
static int animchannels_selectall_exec(bContext *C, wmOperator *op)
static void ANIM_OT_channels_fcurves_enable(wmOperatorType *ot)
static void ANIM_OT_channels_ungroup(wmOperatorType *ot)
static void rearrange_action_channels(bAnimContext *ac, bAction *act, eRearrangeAnimChan_Mode mode)
static int click_select_channel_gplayer(bContext *C, bAnimContext *ac, bAnimListElem *ale, const short selectmode, const int filter)
static bool rearrange_animchannel_islands(ListBase *list, AnimChanRearrangeFp rearrange_func, eRearrangeAnimChan_Mode mode, eAnim_ChannelType type, ListBase *anim_data_visible)
static void ANIM_OT_channels_setting_enable(wmOperatorType *ot)
static void ANIM_OT_channels_setting_toggle(wmOperatorType *ot)
static bool animchannels_grouping_poll(bContext *C)
static void ANIM_OT_channels_move(wmOperatorType *ot)
static int animchannels_channel_select_keys_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static AnimChanRearrangeFp rearrange_get_mode_func(eRearrangeAnimChan_Mode mode)
void ANIM_anim_channels_select_toggle(bAnimContext *ac)
static void rearrange_nla_control_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
static int mouse_anim_channels(bContext *C, bAnimContext *ac, const int channel_index, const short selectmode)
static AnimChanRearrangeFp rearrange_gpencil_get_mode_func(eRearrangeAnimChan_Mode mode)
static bool rearrange_island_ok(tReorderChannelIsland *island)
static void ANIM_OT_channels_group(wmOperatorType *ot)
static void ANIM_OT_channels_select_filter(wmOperatorType *ot)
static int click_select_channel_dummy(bAnimContext *ac, bAnimListElem *ale, const short selectmode)
static void anim_channels_select_set(bAnimContext *ac, const ListBase anim_data, eAnimChannels_SetFlag sel)
static void ANIM_OT_channels_setting_disable(wmOperatorType *ot)
static void ANIM_OT_channels_click(wmOperatorType *ot)
struct tReorderChannelIsland tReorderChannelIsland
static eAnimChannels_SetFlag anim_channels_selection_flag_for_toggle(const ListBase anim_data)
static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int animchannels_box_select_exec(bContext *C, wmOperator *op)
static int click_select_channel_scene(bAnimListElem *ale, const short selectmode)
static const EnumPropertyItem prop_animchannel_setflag_types[]
static int animchannels_setflag_exec(bContext *C, wmOperator *op)
static void select_pchan_for_action_group(bAnimContext *ac, bActionGroup *agrp, bAnimListElem *ale)
eRearrangeAnimChan_Mode
@ REARRANGE_ANIMCHAN_DOWN
@ REARRANGE_ANIMCHAN_UP
@ REARRANGE_ANIMCHAN_BOTTOM
@ REARRANGE_ANIMCHAN_TOP
static int click_select_channel_masklayer(bAnimContext *ac, bAnimListElem *ale, const short selectmode)
static int click_select_channel_fcurve(bAnimContext *ac, bAnimListElem *ale, const short selectmode, const int filter)
static void rearrange_animchannels_filter_visible(ListBase *anim_data_visible, bAnimContext *ac, eAnim_ChannelType type)
static void ANIM_OT_channels_collapse(wmOperatorType *ot)
static void ANIM_OT_channels_select_all(wmOperatorType *ot)
static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op))
void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, AnimData *adt, FCurve *fcu)
void ANIM_animdata_freelist(ListBase *anim_data)
Definition: anim_deps.c:397
void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
Definition: anim_deps.c:302
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
Definition: anim_filter.c:379
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_Flags filter_mode, void *data, eAnimCont_Types datatype)
Definition: anim_filter.c:3447
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
return(oflags[bm->toolflag_index].f &oflag) !=0
#define SELECT
Scene scene
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
#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
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
static ulong * next
#define G(x, y, z)
static void area(int d1, int d2, int e1, int e2, float weights[2])
SymEdge< T > * prev(const SymEdge< T > *se)
Definition: delaunay_2d.cc:105
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
bool ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibility)
Definition: pose_select.c:315
void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
Definition: pose_select.c:95
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
Definition: rna_access.c:5116
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, int maxlen, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3687
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3783
bAction * action
ListBase drivers
ListBase nla_tracks
short flag
struct Object * object
uint8_t f3
uint8_t f1
uint8_t f2
struct FCurve * next
bActionGroup * grp
ChannelDriver * driver
BezTriple * bezt
struct FCurve * prev
short flag
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
short flag
Definition: DNA_key_types.h:42
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
struct NlaStrip * next
ListBase fcurves
ListBase strips
struct NlaTrack * next
struct NlaTrack * prev
struct bPose * pose
short flag
struct bGPdata * gpd
struct AnimData * adt
ListBase object_bases
struct bActionGroup * next
ListBase curves
ListBase groups
short(* get_offset)(bAnimContext *ac, bAnimListElem *ale)
Definition: ED_anim_api.h:593
bool(* name_prop)(bAnimListElem *ale, struct PointerRNA *ptr, struct PropertyRNA **prop)
Definition: ED_anim_api.h:598
struct ARegion * region
Definition: ED_anim_api.h:76
short spacetype
Definition: ED_anim_api.h:67
struct bDopeSheet * ads
Definition: ED_anim_api.h:79
short datatype
Definition: ED_anim_api.h:62
void * data
Definition: ED_anim_api.h:60
struct Object * obact
Definition: ED_anim_api.h:90
short regiontype
Definition: ED_anim_api.h:69
struct ViewLayer * view_layer
Definition: ED_anim_api.h:86
struct SpaceLink * sl
Definition: ED_anim_api.h:74
struct ID * fcurve_owner_id
Definition: ED_anim_api.h:175
struct bAnimListElem * next
Definition: ED_anim_api.h:127
void * key_data
Definition: ED_anim_api.h:146
struct AnimData * adt
Definition: ED_anim_api.h:162
struct bAnimListElem * prev
Definition: ED_anim_api.h:127
struct ID * id
Definition: ED_anim_api.h:160
ListBase layers
int ymin
Definition: DNA_vec_types.h:64
int ymax
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
int xmax
Definition: DNA_vec_types.h:63
struct tReorderChannelIsland * next
struct tReorderChannelIsland * prev
int mval[2]
Definition: WM_types.h:684
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:927
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
PropertyRNA * prop
Definition: WM_types.h:981
struct PointerRNA * ptr
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition: wm_files.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
Definition: wm_keymap.c:852
void WM_operator_properties_border_to_rcti(struct wmOperator *op, rcti *rect)
void WM_operator_properties_gesture_box_select(wmOperatorType *ot)
void WM_operator_properties_select_all(wmOperatorType *ot)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
int WM_operator_flag_only_pass_through_on_press(int retval, const struct wmEvent *event)
int WM_operator_props_popup(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))