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