2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
19 * All rights reserved.
21 * Contributor(s): Joshua Leung
23 * ***** END GPL LICENSE BLOCK *****
26 /** \file blender/editors/animation/anim_channels_edit.c
27 * \ingroup edanimation
35 #include "MEM_guardedalloc.h"
37 #include "BLI_blenlib.h"
38 #include "BLI_utildefines.h"
39 #include "BKE_library.h"
41 #include "DNA_anim_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_key_types.h"
45 #include "DNA_gpencil_types.h"
47 #include "RNA_access.h"
48 #include "RNA_define.h"
50 #include "BKE_action.h"
51 #include "BKE_fcurve.h"
52 #include "BKE_gpencil.h"
53 #include "BKE_context.h"
54 #include "BKE_global.h"
56 #include "UI_view2d.h"
58 #include "ED_anim_api.h"
59 #include "ED_keyframes_edit.h" // XXX move the select modes out of there!
60 #include "ED_screen.h"
65 /* ************************************************************************** */
66 /* CHANNELS API - Exposed API */
68 /* -------------------------- Selection ------------------------------------- */
70 /* Set the given animation-channel as the active one for the active context */
71 // TODO: extend for animdata types...
72 void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type)
74 ListBase anim_data = {NULL, NULL};
77 /* try to build list of filtered items */
78 ANIM_animdata_filter(ac, &anim_data, filter, data, datatype);
79 if (anim_data.first == NULL)
82 /* only clear the 'active' flag for the channels of the same type */
83 for (ale= anim_data.first; ale; ale= ale->next) {
84 /* skip if types don't match */
85 if (channel_type != ale->type)
88 /* flag to set depends on type */
92 bActionGroup *agrp= (bActionGroup *)ale->data;
94 ACHANNEL_SET_FLAG(agrp, ACHANNEL_SETFLAG_CLEAR, AGRP_ACTIVE);
99 FCurve *fcu= (FCurve *)ale->data;
101 ACHANNEL_SET_FLAG(fcu, ACHANNEL_SETFLAG_CLEAR, FCURVE_ACTIVE);
104 case ANIMTYPE_NLATRACK:
106 NlaTrack *nlt= (NlaTrack *)ale->data;
108 ACHANNEL_SET_FLAG(nlt, ACHANNEL_SETFLAG_CLEAR, NLATRACK_ACTIVE);
112 case ANIMTYPE_FILLACTD: /* Action Expander */
113 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
117 case ANIMTYPE_DSSKEY:
119 case ANIMTYPE_DSPART:
120 case ANIMTYPE_DSMBALL:
122 case ANIMTYPE_DSMESH:
127 /* need to verify that this data is valid for now */
129 ACHANNEL_SET_FLAG(ale->adt, ACHANNEL_SETFLAG_CLEAR, ADT_UI_ACTIVE);
136 /* set active flag */
138 switch (channel_type) {
141 bActionGroup *agrp= (bActionGroup *)channel_data;
142 agrp->flag |= AGRP_ACTIVE;
145 case ANIMTYPE_FCURVE:
147 FCurve *fcu= (FCurve *)channel_data;
148 fcu->flag |= FCURVE_ACTIVE;
151 case ANIMTYPE_NLATRACK:
153 NlaTrack *nlt= (NlaTrack *)channel_data;
154 nlt->flag |= NLATRACK_ACTIVE;
158 case ANIMTYPE_FILLACTD: /* Action Expander */
159 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
163 case ANIMTYPE_DSSKEY:
165 case ANIMTYPE_DSPART:
166 case ANIMTYPE_DSMBALL:
168 case ANIMTYPE_DSMESH:
172 /* need to verify that this data is valid for now */
173 if (ale && ale->adt) {
174 ale->adt->flag |= ADT_UI_ACTIVE;
182 BLI_freelistN(&anim_data);
185 /* Deselect all animation channels
186 * - data: pointer to datatype, as contained in bAnimContext
187 * - datatype: the type of data that 'data' represents (eAnimCont_Types)
188 * - test: check if deselecting instead of selecting
189 * - sel: eAnimChannels_SetFlag;
191 void ANIM_deselect_anim_channels (bAnimContext *ac, void *data, short datatype, short test, short sel)
193 ListBase anim_data = {NULL, NULL};
198 /* NOTE: no list visible, otherwise, we get dangling */
199 filter= ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS;
200 ANIM_animdata_filter(ac, &anim_data, filter, data, datatype);
202 /* See if we should be selecting or deselecting */
204 for (ale= anim_data.first; ale; ale= ale->next) {
210 if (ale->flag & SCE_DS_SELECTED)
211 sel= ACHANNEL_SETFLAG_CLEAR;
213 case ANIMTYPE_OBJECT:
214 #if 0 /* for now, do not take object selection into account, since it gets too annoying */
215 if (ale->flag & SELECT)
216 sel= ACHANNEL_SETFLAG_CLEAR;
220 if (ale->flag & AGRP_SELECTED)
221 sel= ACHANNEL_SETFLAG_CLEAR;
223 case ANIMTYPE_FCURVE:
224 if (ale->flag & FCURVE_SELECTED)
225 sel= ACHANNEL_SETFLAG_CLEAR;
227 case ANIMTYPE_SHAPEKEY:
228 if (ale->flag & KEYBLOCK_SEL)
229 sel= ACHANNEL_SETFLAG_CLEAR;
231 case ANIMTYPE_NLATRACK:
232 if (ale->flag & NLATRACK_SELECTED)
233 sel= ACHANNEL_SETFLAG_CLEAR;
236 case ANIMTYPE_FILLACTD: /* Action Expander */
237 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
241 case ANIMTYPE_DSSKEY:
243 case ANIMTYPE_DSPART:
244 case ANIMTYPE_DSMBALL:
246 case ANIMTYPE_DSMESH:
247 case ANIMTYPE_DSNTREE:
252 if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
253 sel= ACHANNEL_SETFLAG_CLEAR;
257 case ANIMTYPE_GPLAYER:
258 if (ale->flag & GP_LAYER_SELECT)
259 sel= ACHANNEL_SETFLAG_CLEAR;
265 /* Now set the flags */
266 for (ale= anim_data.first; ale; ale= ale->next) {
270 Scene *scene= (Scene *)ale->data;
272 ACHANNEL_SET_FLAG(scene, sel, SCE_DS_SELECTED);
275 ACHANNEL_SET_FLAG(scene, sel, ADT_UI_SELECTED);
279 case ANIMTYPE_OBJECT:
280 #if 0 /* for now, do not take object selection into account, since it gets too annoying */
282 Base *base= (Base *)ale->data;
283 Object *ob= base->object;
285 ACHANNEL_SET_FLAG(base, sel, SELECT);
286 ACHANNEL_SET_FLAG(ob, sel, SELECT);
289 ACHANNEL_SET_FLAG(ob, sel, ADT_UI_SELECTED);
296 bActionGroup *agrp= (bActionGroup *)ale->data;
298 ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED);
299 agrp->flag &= ~AGRP_ACTIVE;
302 case ANIMTYPE_FCURVE:
304 FCurve *fcu= (FCurve *)ale->data;
306 ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED);
307 fcu->flag &= ~FCURVE_ACTIVE;
310 case ANIMTYPE_SHAPEKEY:
312 KeyBlock *kb= (KeyBlock *)ale->data;
314 ACHANNEL_SET_FLAG(kb, sel, KEYBLOCK_SEL);
317 case ANIMTYPE_NLATRACK:
319 NlaTrack *nlt= (NlaTrack *)ale->data;
321 ACHANNEL_SET_FLAG(nlt, sel, NLATRACK_SELECTED);
322 nlt->flag &= ~NLATRACK_ACTIVE;
326 case ANIMTYPE_FILLACTD: /* Action Expander */
327 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
331 case ANIMTYPE_DSSKEY:
333 case ANIMTYPE_DSPART:
334 case ANIMTYPE_DSMBALL:
336 case ANIMTYPE_DSMESH:
337 case ANIMTYPE_DSNTREE:
342 /* need to verify that this data is valid for now */
344 ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED);
345 ale->adt->flag &= ~ADT_UI_ACTIVE;
350 case ANIMTYPE_GPLAYER:
352 bGPDlayer *gpl = (bGPDlayer *)ale->data;
354 ACHANNEL_SET_FLAG(gpl, sel, GP_LAYER_SELECT);
361 BLI_freelistN(&anim_data);
364 /* ---------------------------- Graph Editor ------------------------------------- */
366 /* Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting
367 * - anim_data: list of the all the anim channels that can be chosen
368 * -> filtered using ANIMFILTER_CHANNELS only, since if we took VISIBLE too,
369 * then the channels under closed expanders get ignored...
370 * - ale_setting: the anim channel (not in the anim_data list directly, though occuring there)
371 * with the new state of the setting that we want flushed up/down the hierarchy
372 * - setting: type of setting to set
373 * - on: whether the visibility setting has been enabled or disabled
375 void ANIM_flush_setting_anim_channels (bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, int setting, short on)
377 bAnimListElem *ale, *match=NULL;
378 int prevLevel=0, matchLevel=0;
381 if (ELEM(NULL, anim_data, anim_data->first))
384 /* find the channel that got changed */
385 for (ale= anim_data->first; ale; ale= ale->next) {
386 /* compare data, and type as main way of identifying the channel */
387 if ((ale->data == ale_setting->data) && (ale->type == ale_setting->type)) {
388 /* we also have to check the ID, this is assigned to, since a block may have multiple users */
389 // TODO: is the owner-data more revealing?
390 if (ale->id == ale_setting->id) {
397 printf("ERROR: no channel matching the one changed was found \n");
401 bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale_setting);
404 printf("ERROR: no channel info for the changed channel \n");
408 /* get the level of the channel that was affected
409 * - we define the level as simply being the offset for the start of the channel
411 matchLevel= (acf->get_offset)? acf->get_offset(ac, ale_setting) : 0;
412 prevLevel= matchLevel;
418 * - only flush up if the current state is now enabled (positive 'on' state is default)
419 * (otherwise, it's too much work to force the parents to be inactive too)
421 * For everything else:
422 * - only flush up if the current state is now disabled (negative 'off' state is default)
423 * (otherwise, it's too much work to force the parents to be active too)
425 if ( ((setting == ACHANNEL_SETTING_VISIBLE) && on) ||
426 ((setting != ACHANNEL_SETTING_VISIBLE) && on==0) )
428 /* go backwards in the list, until the highest-ranking element (by indention has been covered) */
429 for (ale= match->prev; ale; ale= ale->prev) {
430 bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale);
433 /* if no channel info was found, skip, since this type might not have any useful info */
437 /* get the level of the current channel traversed
438 * - we define the level as simply being the offset for the start of the channel
440 level= (acf->get_offset)? acf->get_offset(ac, ale) : 0;
442 /* if the level is 'less than' (i.e. more important) the level we're matching
443 * but also 'less than' the level just tried (i.e. only the 1st group above grouped F-Curves,
444 * when toggling visibility of F-Curves, gets flushed, which should happen if we don't let prevLevel
445 * get updated below once the first 1st group is found)...
447 if (level < prevLevel) {
448 /* flush the new status... */
449 ANIM_channel_setting_set(ac, ale, setting, on);
451 /* store this level as the 'old' level now */
454 /* if the level is 'greater than' (i.e. less important) than the previous level... */
455 else if (level > prevLevel) {
456 /* if previous level was a base-level (i.e. 0 offset / root of one hierarchy),
461 /* otherwise, this level weaves into another sibling hierarchy to the previous one just
462 * finished, so skip until we get to the parent of this level
470 /* flush down (always) */
472 /* go forwards in the list, until the lowest-ranking element (by indention has been covered) */
473 for (ale= match->next; ale; ale= ale->next) {
474 bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale);
477 /* if no channel info was found, skip, since this type might not have any useful info */
481 /* get the level of the current channel traversed
482 * - we define the level as simply being the offset for the start of the channel
484 level= (acf->get_offset)? acf->get_offset(ac, ale) : 0;
486 /* if the level is 'greater than' (i.e. less important) the channel that was changed,
487 * flush the new status...
489 if (level > matchLevel)
490 ANIM_channel_setting_set(ac, ale, setting, on);
491 /* however, if the level is 'less than or equal to' the channel that was changed,
492 * (i.e. the current channel is as important if not more important than the changed channel)
493 * then we should stop, since we've found the last one of the children we should flush
498 /* store this level as the 'old' level now */
499 prevLevel= level; // XXX: prevLevel is unused
504 /* -------------------------- F-Curves ------------------------------------- */
506 /* Delete the given F-Curve from its AnimData block */
507 void ANIM_fcurve_delete_from_animdata (bAnimContext *ac, AnimData *adt, FCurve *fcu)
509 /* - if no AnimData, we've got nowhere to remove the F-Curve from
510 * (this doesn't guarantee that the F-Curve is in there, but at least we tried
511 * - if no F-Curve, there is nothing to remove
513 if (ELEM(NULL, adt, fcu))
516 /* remove from whatever list it came from
520 * - TODO... some others?
522 if ((ac) && (ac->datatype == ANIMCONT_DRIVERS)) {
524 BLI_remlink(&adt->drivers, fcu);
526 else if (adt->action) {
527 /* remove from group or action, whichever one "owns" the F-Curve */
529 action_groups_remove_channel(adt->action, fcu);
531 BLI_remlink(&adt->action->curves, fcu);
533 /* if action has no more F-Curves as a result of this, unlink it from
534 * AnimData if it did not come from a NLA Strip being tweaked.
536 * This is done so that we don't have dangling Object+Action entries in
537 * channel list that are empty, and linger around long after the data they
538 * are for has disappeared (and probably won't come back).
540 // XXX: does everybody always want this?
541 /* XXX: there's a problem where many actions could build up in the file if multiple
542 * full add/delete cycles are performed on the same objects, but assume that this is rare
544 if ((adt->action->curves.first == NULL) && (adt->flag & ADT_NLA_EDIT_ON)==0)
546 id_us_min(&adt->action->id);
551 /* free the F-Curve itself */
555 /* ************************************************************************** */
558 /* ****************** Operator Utilities ********************************** */
560 /* poll callback for being in an Animation Editor channels list region */
561 static int animedit_poll_channels_active (bContext *C)
563 ScrArea *sa= CTX_wm_area(C);
565 /* channels region test */
566 // TODO: could enhance with actually testing if channels region?
567 if (ELEM(NULL, sa, CTX_wm_region(C)))
569 /* animation editor test */
570 if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
576 /* poll callback for Animation Editor channels list region + not in NLA-tweakmode for NLA */
577 static int animedit_poll_channels_nla_tweakmode_off (bContext *C)
579 ScrArea *sa= CTX_wm_area(C);
580 Scene *scene = CTX_data_scene(C);
582 /* channels region test */
583 // TODO: could enhance with actually testing if channels region?
584 if (ELEM(NULL, sa, CTX_wm_region(C)))
586 /* animation editor test */
587 if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
590 /* NLA TweakMode test */
591 if (sa->spacetype == SPACE_NLA) {
592 if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON))
599 /* ****************** Rearrange Channels Operator ******************* */
601 /* constants for channel rearranging */
602 /* WARNING: don't change exising ones without modifying rearrange func accordingly */
604 REARRANGE_ANIMCHAN_TOP= -2,
605 REARRANGE_ANIMCHAN_UP= -1,
606 REARRANGE_ANIMCHAN_DOWN= 1,
607 REARRANGE_ANIMCHAN_BOTTOM= 2
610 /* defines for rearranging channels */
611 static EnumPropertyItem prop_animchannel_rearrange_types[] = {
612 {REARRANGE_ANIMCHAN_TOP, "TOP", 0, "To Top", ""},
613 {REARRANGE_ANIMCHAN_UP, "UP", 0, "Up", ""},
614 {REARRANGE_ANIMCHAN_DOWN, "DOWN", 0, "Down", ""},
615 {REARRANGE_ANIMCHAN_BOTTOM, "BOTTOM", 0, "To Bottom", ""},
616 {0, NULL, 0, NULL, NULL}
619 /* Reordering "Islands" Defines ----------------------------------- */
621 /* Island definition - just a listbase container */
622 typedef struct tReorderChannelIsland {
623 struct tReorderChannelIsland *next, *prev;
625 ListBase channels; /* channels within this region with the same state */
626 int flag; /* eReorderIslandFlag */
627 } tReorderChannelIsland;
629 /* flags for channel reordering islands */
630 typedef enum eReorderIslandFlag {
631 REORDER_ISLAND_SELECTED = (1<<0), /* island is selected */
632 REORDER_ISLAND_UNTOUCHABLE = (1<<1), /* island should be ignored */
633 REORDER_ISLAND_MOVED = (1<<2) /* island has already been moved */
634 } eReorderIslandFlag;
637 /* Rearrange Methods --------------------------------------------- */
639 static short rearrange_island_ok (tReorderChannelIsland *island)
641 /* island must not be untouchable */
642 if (island->flag & REORDER_ISLAND_UNTOUCHABLE)
645 /* island should be selected to be moved */
646 return (island->flag & REORDER_ISLAND_SELECTED) && !(island->flag & REORDER_ISLAND_MOVED);
649 /* ............................. */
651 static short rearrange_island_top (ListBase *list, tReorderChannelIsland *island)
653 if (rearrange_island_ok(island)) {
654 /* remove from current position */
655 BLI_remlink(list, island);
657 /* make it first element */
658 BLI_insertlinkbefore(list, list->first, island);
666 static short rearrange_island_up (ListBase *list, tReorderChannelIsland *island)
668 if (rearrange_island_ok(island)) {
669 /* moving up = moving before the previous island, otherwise we're in the same place */
670 tReorderChannelIsland *prev= island->prev;
673 /* remove from current position */
674 BLI_remlink(list, island);
677 BLI_insertlinkbefore(list, prev, island);
686 static short rearrange_island_down (ListBase *list, tReorderChannelIsland *island)
688 if (rearrange_island_ok(island)) {
689 /* moving down = moving after the next island, otherwise we're in the same place */
690 tReorderChannelIsland *next = island->next;
693 /* can only move past if next is not untouchable (i.e. nothing can go after it) */
694 if ((next->flag & REORDER_ISLAND_UNTOUCHABLE)==0) {
695 /* remove from current position */
696 BLI_remlink(list, island);
699 BLI_insertlinkafter(list, next, island);
704 /* else: no next channel, so we're at the bottom already, so can't move */
710 static short rearrange_island_bottom (ListBase *list, tReorderChannelIsland *island)
712 if (rearrange_island_ok(island)) {
713 tReorderChannelIsland *last = list->last;
715 /* remove island from current position */
716 BLI_remlink(list, island);
718 /* add before or after the last channel? */
719 if ((last->flag & REORDER_ISLAND_UNTOUCHABLE)==0) {
720 /* can add after it */
721 BLI_addtail(list, island);
724 /* can at most go just before it, since last cannot be moved */
725 BLI_insertlinkbefore(list, last, island);
735 /* ............................. */
737 /* typedef for channel rearranging function
738 * < list: list that channels belong to
739 * < island: island to be moved
740 * > return[0]: whether operation was a success
742 typedef short (*AnimChanRearrangeFp)(ListBase *list, tReorderChannelIsland *island);
744 /* get rearranging function, given 'rearrange' mode */
745 static AnimChanRearrangeFp rearrange_get_mode_func (short mode)
748 case REARRANGE_ANIMCHAN_TOP:
749 return rearrange_island_top;
750 case REARRANGE_ANIMCHAN_UP:
751 return rearrange_island_up;
752 case REARRANGE_ANIMCHAN_DOWN:
753 return rearrange_island_down;
754 case REARRANGE_ANIMCHAN_BOTTOM:
755 return rearrange_island_bottom;
761 /* Rearrange Islands Generics ------------------------------------- */
763 /* add channel into list of islands */
764 static void rearrange_animchannel_add_to_islands (ListBase *islands, ListBase *srcList, Link *channel, short type)
766 tReorderChannelIsland *island = islands->last; /* always try to add to last island if possible */
767 short is_sel=0, is_untouchable=0;
769 /* get flags - selected and untouchable from the channel */
773 bActionGroup *agrp= (bActionGroup *)channel;
775 is_sel= SEL_AGRP(agrp);
776 is_untouchable= (agrp->flag & AGRP_TEMP) != 0;
779 case ANIMTYPE_FCURVE:
781 FCurve *fcu= (FCurve *)channel;
783 is_sel= SEL_FCU(fcu);
786 case ANIMTYPE_NLATRACK:
788 NlaTrack *nlt= (NlaTrack *)channel;
790 is_sel= SEL_NLT(nlt);
795 printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %d\n", type);
799 /* do we need to add to a new island? */
800 if ((island == NULL) || /* 1) no islands yet */
801 ((island->flag & REORDER_ISLAND_SELECTED) == 0) || /* 2) unselected islands have single channels only - to allow up/down movement */
802 (is_sel == 0)) /* 3) if channel is unselected, stop existing island (it was either wrong sel status, or full already) */
804 /* create a new island now */
805 island = MEM_callocN(sizeof(tReorderChannelIsland), "tReorderChannelIsland");
806 BLI_addtail(islands, island);
809 island->flag |= REORDER_ISLAND_SELECTED;
811 island->flag |= REORDER_ISLAND_UNTOUCHABLE;
814 /* add channel to island - need to remove it from its existing list first though */
815 BLI_remlink(srcList, channel);
816 BLI_addtail(&island->channels, channel);
819 /* flatten islands out into a single list again */
820 static void rearrange_animchannel_flatten_islands (ListBase *islands, ListBase *srcList)
822 tReorderChannelIsland *island, *isn=NULL;
824 /* make sure srcList is empty now */
825 BLI_assert(srcList->first == NULL);
827 /* go through merging islands */
828 for (island = islands->first; island; island = isn) {
831 /* merge island channels back to main list, then delete the island */
832 BLI_movelisttolist(srcList, &island->channels);
833 BLI_freelinkN(islands, island);
837 /* ............................. */
839 /* performing rearranging of channels using islands */
840 static short rearrange_animchannel_islands (ListBase *list, AnimChanRearrangeFp rearrange_func, short mode, short type)
842 ListBase islands = {NULL, NULL};
843 Link *channel, *chanNext=NULL;
846 /* don't waste effort on an empty list */
847 if (list->first == NULL)
850 /* group channels into islands */
851 for (channel = list->first; channel; channel = chanNext) {
852 chanNext = channel->next;
853 rearrange_animchannel_add_to_islands(&islands, list, channel, type);
856 /* perform moving of selected islands now, but only if there is more than one of 'em so that something will happen
857 * - scanning of the list is performed in the opposite direction to the direction we're moving things, so that we
858 * shouldn't need to encounter items we've moved already
860 if (islands.first != islands.last) {
861 tReorderChannelIsland *first = (mode > 0) ? islands.last : islands.first;
862 tReorderChannelIsland *island, *isn=NULL;
864 for (island = first; island; island = isn) {
865 isn = (mode > 0) ? island->prev : island->next;
867 /* perform rearranging */
868 if (rearrange_func(&islands, island)) {
869 island->flag |= REORDER_ISLAND_MOVED;
875 /* ungroup islands */
876 rearrange_animchannel_flatten_islands(&islands, list);
878 /* did we do anything? */
882 /* NLA Specific Stuff ----------------------------------------------------- */
884 /* Change the order NLA Tracks within NLA Stack
885 * ! NLA tracks are displayed in opposite order, so directions need care
886 * mode: REARRANGE_ANIMCHAN_*
888 static void rearrange_nla_channels (bAnimContext *UNUSED(ac), AnimData *adt, short mode)
890 AnimChanRearrangeFp rearrange_func;
892 /* hack: invert mode so that functions will work in right order */
895 /* get rearranging function */
896 rearrange_func = rearrange_get_mode_func(mode);
897 if (rearrange_func == NULL)
900 /* only consider NLA data if it's accessible */
901 //if (EXPANDED_DRVD(adt) == 0)
904 /* perform rearranging on tracks list */
905 rearrange_animchannel_islands(&adt->nla_tracks, rearrange_func, mode, ANIMTYPE_NLATRACK);
908 /* Drivers Specific Stuff ------------------------------------------------- */
910 /* Change the order drivers within AnimData block
911 * mode: REARRANGE_ANIMCHAN_*
913 static void rearrange_driver_channels (bAnimContext *UNUSED(ac), AnimData *adt, short mode)
915 /* get rearranging function */
916 AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
918 if (rearrange_func == NULL)
921 /* only consider drivers if they're accessible */
922 if (EXPANDED_DRVD(adt) == 0)
925 /* perform rearranging on drivers list (drivers are really just F-Curves) */
926 rearrange_animchannel_islands(&adt->drivers, rearrange_func, mode, ANIMTYPE_FCURVE);
929 /* Action Specific Stuff ------------------------------------------------- */
931 /* make sure all action-channels belong to a group (and clear action's list) */
932 static void split_groups_action_temp (bAction *act, bActionGroup *tgrp)
940 /* Separate F-Curves into lists per group */
941 for (agrp= act->groups.first; agrp; agrp= agrp->next) {
942 if (agrp->channels.first) {
943 fcu= agrp->channels.last;
944 act->curves.first= fcu->next;
946 fcu= agrp->channels.first;
949 fcu= agrp->channels.last;
954 /* Initialise memory for temp-group */
955 memset(tgrp, 0, sizeof(bActionGroup));
956 tgrp->flag |= (AGRP_EXPANDED|AGRP_TEMP);
957 BLI_strncpy(tgrp->name, "#TempGroup", sizeof(tgrp->name));
959 /* Move any action-channels not already moved, to the temp group */
960 if (act->curves.first) {
962 fcu= act->curves.first;
964 tgrp->channels.first= fcu;
965 act->curves.first= NULL;
968 fcu= act->curves.last;
970 tgrp->channels.last= fcu;
971 act->curves.last= NULL;
974 /* Add temp-group to list */
975 BLI_addtail(&act->groups, tgrp);
978 /* link lists of channels that groups have */
979 static void join_groups_action_temp (bAction *act)
983 for (agrp= act->groups.first; agrp; agrp= agrp->next) {
986 /* add list of channels to action's channels */
987 tempGroup= agrp->channels;
988 BLI_movelisttolist(&act->curves, &agrp->channels);
989 agrp->channels= tempGroup;
991 /* clear moved flag */
992 agrp->flag &= ~AGRP_MOVED;
994 /* if temp-group... remove from list (but don't free as it's on the stack!) */
995 if (agrp->flag & AGRP_TEMP) {
996 BLI_remlink(&act->groups, agrp);
1002 /* Change the order of anim-channels within action
1003 * mode: REARRANGE_ANIMCHAN_*
1005 static void rearrange_action_channels (bAnimContext *ac, bAction *act, short mode)
1010 /* get rearranging function */
1011 AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
1013 if (rearrange_func == NULL)
1016 /* make sure we're only operating with groups (vs a mixture of groups+curves) */
1017 split_groups_action_temp(act, &tgrp);
1019 /* rearrange groups first
1020 * - the group's channels will only get considered if nothing happened when rearranging the groups
1021 * i.e. the rearrange function returned 0
1023 do_channels = rearrange_animchannel_islands(&act->groups, rearrange_func, mode, ANIMTYPE_GROUP) == 0;
1028 for (agrp= act->groups.first; agrp; agrp= agrp->next) {
1029 /* only consider F-Curves if they're visible (group expanded) */
1030 if (EXPANDED_AGRP(ac, agrp)) {
1031 rearrange_animchannel_islands(&agrp->channels, rearrange_func, mode, ANIMTYPE_FCURVE);
1036 /* assemble lists into one list (and clear moved tags) */
1037 join_groups_action_temp(act);
1040 /* ------------------- */
1042 static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
1047 /* get editor data */
1048 if (ANIM_animdata_get_context(C, &ac) == 0)
1049 return OPERATOR_CANCELLED;
1052 mode= RNA_enum_get(op->ptr, "direction");
1054 /* method to move channels depends on the editor */
1055 if (ac.datatype == ANIMCONT_GPENCIL) {
1056 /* Grease Pencil channels */
1057 printf("Grease Pencil not supported for moving yet\n");
1059 else if (ac.datatype == ANIMCONT_ACTION) {
1060 /* Directly rearrange action's channels */
1061 rearrange_action_channels(&ac, ac.data, mode);
1064 ListBase anim_data = {NULL, NULL};
1068 /* get animdata blocks */
1069 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA);
1070 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1072 for (ale = anim_data.first; ale; ale = ale->next) {
1073 AnimData *adt= ale->data;
1075 switch (ac.datatype) {
1076 case ANIMCONT_NLA: /* NLA-tracks only */
1077 rearrange_nla_channels(&ac, adt, mode);
1080 case ANIMCONT_DRIVERS: /* Drivers list only */
1081 rearrange_driver_channels(&ac, adt, mode);
1084 case ANIMCONT_SHAPEKEY: // DOUBLE CHECK ME...
1086 default: /* some collection of actions */
1088 rearrange_action_channels(&ac, adt->action, mode);
1089 else if (G.f & G_DEBUG)
1090 printf("Animdata has no action\n");
1095 /* free temp data */
1096 BLI_freelistN(&anim_data);
1099 /* send notifier that things have changed */
1100 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1102 return OPERATOR_FINISHED;
1105 static void ANIM_OT_channels_move (wmOperatorType *ot)
1108 ot->name= "Move Channels";
1109 ot->idname= "ANIM_OT_channels_move";
1110 ot->description = "Rearrange selected animation channels";
1113 ot->exec= animchannels_rearrange_exec;
1114 ot->poll= animedit_poll_channels_nla_tweakmode_off;
1117 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1120 ot->prop= RNA_def_enum(ot->srna, "direction", prop_animchannel_rearrange_types, REARRANGE_ANIMCHAN_DOWN, "Direction", "");
1123 /* ******************** Delete Channel Operator *********************** */
1125 static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
1128 ListBase anim_data = {NULL, NULL};
1132 /* get editor data */
1133 if (ANIM_animdata_get_context(C, &ac) == 0)
1134 return OPERATOR_CANCELLED;
1136 /* cannot delete in shapekey */
1137 if (ac.datatype == ANIMCONT_SHAPEKEY)
1138 return OPERATOR_CANCELLED;
1141 /* do groups only first (unless in Drivers mode, where there are none) */
1142 if (ac.datatype != ANIMCONT_DRIVERS) {
1144 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
1145 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1147 /* delete selected groups and their associated channels */
1148 for (ale= anim_data.first; ale; ale= ale->next) {
1149 /* only groups - don't check other types yet, since they may no-longer exist */
1150 if (ale->type == ANIMTYPE_GROUP) {
1151 bActionGroup *agrp= (bActionGroup *)ale->data;
1152 AnimData *adt= ale->adt;
1155 /* skip this group if no AnimData available, as we can't safely remove the F-Curves */
1159 /* delete all of the Group's F-Curves, but no others */
1160 for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcn) {
1163 /* remove from group and action, then free */
1164 action_groups_remove_channel(adt->action, fcu);
1168 /* free the group itself */
1170 BLI_freelinkN(&adt->action->groups, agrp);
1177 BLI_freelistN(&anim_data);
1181 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
1182 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1184 /* delete selected data channels */
1185 for (ale= anim_data.first; ale; ale= ale->next) {
1186 switch (ale->type) {
1187 case ANIMTYPE_FCURVE:
1189 /* F-Curves if we can identify its parent */
1190 AnimData *adt= ale->adt;
1191 FCurve *fcu= (FCurve *)ale->data;
1193 /* try to free F-Curve */
1194 ANIM_fcurve_delete_from_animdata(&ac, adt, fcu);
1198 case ANIMTYPE_GPLAYER:
1200 /* Grease Pencil layer */
1201 bGPdata *gpd= (bGPdata *)ale->id;
1202 bGPDlayer *gpl= (bGPDlayer *)ale->data;
1204 /* try to delete the layer's data and the layer itself */
1205 free_gpencil_frames(gpl);
1206 BLI_freelinkN(&gpd->layers, gpl);
1213 BLI_freelistN(&anim_data);
1215 /* send notifier that things have changed */
1216 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1218 return OPERATOR_FINISHED;
1221 static void ANIM_OT_channels_delete (wmOperatorType *ot)
1224 ot->name= "Delete Channels";
1225 ot->idname= "ANIM_OT_channels_delete";
1226 ot->description= "Delete all selected animation channels";
1229 ot->exec= animchannels_delete_exec;
1230 ot->poll= animedit_poll_channels_active;
1233 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1236 /* ******************** Set Channel Visibility Operator *********************** */
1237 /* NOTE: this operator is only valid in the Graph Editor channels region */
1239 static int animchannels_visibility_set_exec(bContext *C, wmOperator *UNUSED(op))
1242 ListBase anim_data = {NULL, NULL};
1243 ListBase all_data = {NULL, NULL};
1247 /* get editor data */
1248 if (ANIM_animdata_get_context(C, &ac) == 0)
1249 return OPERATOR_CANCELLED;
1251 /* get list of all channels that selection may need to be flushed to
1252 * - hierarchy mustn't affect what we have access to here...
1254 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
1255 ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
1257 /* hide all channels not selected
1258 * - hierarchy matters if we're doing this from the channels region
1259 * since we only want to apply this to channels we can "see",
1260 * and have these affect their relatives
1261 * - but for Graph Editor, this gets used also from main region
1262 * where hierarchy doesn't apply, as for [#21276]
1264 if ((ac.spacetype == SPACE_IPO) && (ac.regiontype != RGN_TYPE_CHANNELS)) {
1265 /* graph editor (case 2) */
1266 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_UNSEL | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
1270 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_UNSEL | ANIMFILTER_NODUPLIS);
1272 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1274 for (ale= anim_data.first; ale; ale= ale->next) {
1275 /* clear setting first */
1276 ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_CLEAR);
1278 /* now also flush selection status as appropriate
1279 * NOTE: in some cases, this may result in repeat flushing being performed
1281 ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 0);
1284 BLI_freelistN(&anim_data);
1286 /* make all the selected channels visible */
1287 filter= (ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
1288 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1290 for (ale= anim_data.first; ale; ale= ale->next) {
1291 /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
1292 // TODO: find out why this is the case, and fix that
1293 if (ale->type == ANIMTYPE_OBJECT)
1296 /* enable the setting */
1297 ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD);
1299 /* now, also flush selection status up/down as appropriate */
1300 ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 1);
1303 BLI_freelistN(&anim_data);
1304 BLI_freelistN(&all_data);
1307 /* send notifier that things have changed */
1308 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1310 return OPERATOR_FINISHED;
1313 static void ANIM_OT_channels_visibility_set (wmOperatorType *ot)
1316 ot->name= "Set Visibility";
1317 ot->idname= "ANIM_OT_channels_visibility_set";
1318 ot->description= "Make only the selected animation channels visible in the Graph Editor";
1321 ot->exec= animchannels_visibility_set_exec;
1322 ot->poll= ED_operator_graphedit_active;
1325 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1329 /* ******************** Toggle Channel Visibility Operator *********************** */
1330 /* NOTE: this operator is only valid in the Graph Editor channels region */
1332 static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *UNUSED(op))
1335 ListBase anim_data = {NULL, NULL};
1336 ListBase all_data = {NULL, NULL};
1339 short vis= ACHANNEL_SETFLAG_ADD;
1341 /* get editor data */
1342 if (ANIM_animdata_get_context(C, &ac) == 0)
1343 return OPERATOR_CANCELLED;
1345 /* get list of all channels that selection may need to be flushed to
1346 * - hierarchy mustn't affect what we have access to here...
1348 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
1349 ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
1352 * - restrict this to only applying on settings we can get to in the list
1354 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
1355 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1357 /* See if we should be making showing all selected or hiding */
1358 for (ale= anim_data.first; ale; ale= ale->next) {
1359 /* set the setting in the appropriate way (if available) */
1360 if (ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_VISIBLE)) {
1361 vis= ACHANNEL_SETFLAG_CLEAR;
1366 /* Now set the flags */
1367 for (ale= anim_data.first; ale; ale= ale->next) {
1368 /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
1369 // TODO: find out why this is the case, and fix that
1370 if (ale->type == ANIMTYPE_OBJECT)
1373 /* change the setting */
1374 ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, vis);
1376 /* now, also flush selection status up/down as appropriate */
1377 ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, (vis == ACHANNEL_SETFLAG_ADD));
1381 BLI_freelistN(&anim_data);
1382 BLI_freelistN(&all_data);
1384 /* send notifier that things have changed */
1385 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1387 return OPERATOR_FINISHED;
1390 static void ANIM_OT_channels_visibility_toggle (wmOperatorType *ot)
1393 ot->name= "Toggle Visibility";
1394 ot->idname= "ANIM_OT_channels_visibility_toggle";
1395 ot->description= "Toggle visibility in Graph Editor of all selected animation channels";
1398 ot->exec= animchannels_visibility_toggle_exec;
1399 ot->poll= ED_operator_graphedit_active;
1402 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1405 /* ********************** Set Flags Operator *********************** */
1407 /* defines for setting animation-channel flags */
1408 static EnumPropertyItem prop_animchannel_setflag_types[] = {
1409 {ACHANNEL_SETFLAG_TOGGLE, "TOGGLE", 0, "Toggle", ""},
1410 {ACHANNEL_SETFLAG_CLEAR, "DISABLE", 0, "Disable", ""},
1411 {ACHANNEL_SETFLAG_ADD, "ENABLE", 0, "Enable", ""},
1412 {ACHANNEL_SETFLAG_INVERT, "INVERT", 0, "Invert", ""},
1413 {0, NULL, 0, NULL, NULL}
1416 /* defines for set animation-channel settings */
1417 // TODO: could add some more types, but those are really quite dependent on the mode...
1418 static EnumPropertyItem prop_animchannel_settings_types[] = {
1419 {ACHANNEL_SETTING_PROTECT, "PROTECT", 0, "Protect", ""},
1420 {ACHANNEL_SETTING_MUTE, "MUTE", 0, "Mute", ""},
1421 {0, NULL, 0, NULL, NULL}
1425 /* ------------------- */
1427 /* Set/clear a particular flag (setting) for all selected + visible channels
1428 * setting: the setting to modify
1429 * mode: eAnimChannels_SetFlag
1430 * onlysel: only selected channels get the flag set
1432 // TODO: enable a setting which turns flushing on/off?
1433 static void setflag_anim_channels (bAnimContext *ac, short setting, short mode, short onlysel, short flush)
1435 ListBase anim_data = {NULL, NULL};
1436 ListBase all_data = {NULL, NULL};
1440 /* filter data that we need if flush is on */
1442 /* get list of all channels that selection may need to be flushed to
1443 * - hierarchy visibility needs to be ignored so that settings can get flushed
1444 * "down" inside closed containers
1446 filter= ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS;
1447 ANIM_animdata_filter(ac, &all_data, filter, ac->data, ac->datatype);
1450 /* filter data that we're working on
1451 * - hierarchy matters if we're doing this from the channels region
1452 * since we only want to apply this to channels we can "see",
1453 * and have these affect their relatives
1454 * - but for Graph Editor, this gets used also from main region
1455 * where hierarchy doesn't apply [#21276]
1457 if ((ac->spacetype == SPACE_IPO) && (ac->regiontype != RGN_TYPE_CHANNELS)) {
1458 /* graph editor (case 2) */
1459 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
1463 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
1465 if (onlysel) filter |= ANIMFILTER_SEL;
1466 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1468 /* if toggling, check if disable or enable */
1469 if (mode == ACHANNEL_SETFLAG_TOGGLE) {
1470 /* default to turn all on, unless we encounter one that's on... */
1471 mode= ACHANNEL_SETFLAG_ADD;
1473 /* see if we should turn off instead... */
1474 for (ale= anim_data.first; ale; ale= ale->next) {
1475 /* set the setting in the appropriate way (if available) */
1476 if (ANIM_channel_setting_get(ac, ale, setting) > 0) {
1477 mode= ACHANNEL_SETFLAG_CLEAR;
1483 /* apply the setting */
1484 for (ale= anim_data.first; ale; ale= ale->next) {
1485 /* skip channel if setting is not available */
1486 if (ANIM_channel_setting_get(ac, ale, setting) == -1)
1489 /* set the setting in the appropriate way */
1490 ANIM_channel_setting_set(ac, ale, setting, mode);
1492 /* if flush status... */
1494 ANIM_flush_setting_anim_channels(ac, &all_data, ale, setting, mode);
1497 BLI_freelistN(&anim_data);
1498 BLI_freelistN(&all_data);
1501 /* ------------------- */
1503 static int animchannels_setflag_exec(bContext *C, wmOperator *op)
1506 short mode, setting;
1509 /* get editor data */
1510 if (ANIM_animdata_get_context(C, &ac) == 0)
1511 return OPERATOR_CANCELLED;
1513 /* mode (eAnimChannels_SetFlag), setting (eAnimChannel_Settings) */
1514 mode= RNA_enum_get(op->ptr, "mode");
1515 setting= RNA_enum_get(op->ptr, "type");
1517 /* check if setting is flushable */
1518 if (setting == ACHANNEL_SETTING_EXPAND)
1522 * - only selected channels are affected
1524 setflag_anim_channels(&ac, setting, mode, 1, flush);
1526 /* send notifier that things have changed */
1527 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1529 return OPERATOR_FINISHED;
1533 static void ANIM_OT_channels_setting_enable (wmOperatorType *ot)
1536 ot->name= "Enable Channel Setting";
1537 ot->idname= "ANIM_OT_channels_setting_enable";
1538 ot->description= "Enable specified setting on all selected animation channels";
1541 ot->invoke= WM_menu_invoke;
1542 ot->exec= animchannels_setflag_exec;
1543 ot->poll= animedit_poll_channels_active;
1546 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1549 /* flag-setting mode */
1550 RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_ADD, "Mode", "");
1551 /* setting to set */
1552 ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
1555 static void ANIM_OT_channels_setting_disable (wmOperatorType *ot)
1558 ot->name= "Disable Channel Setting";
1559 ot->idname= "ANIM_OT_channels_setting_disable";
1560 ot->description= "Disable specified setting on all selected animation channels";
1563 ot->invoke= WM_menu_invoke;
1564 ot->exec= animchannels_setflag_exec;
1565 ot->poll= animedit_poll_channels_active;
1568 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1571 /* flag-setting mode */
1572 RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_CLEAR, "Mode", "");
1573 /* setting to set */
1574 ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
1577 static void ANIM_OT_channels_setting_invert (wmOperatorType *ot)
1580 ot->name= "Invert Channel Setting";
1581 ot->idname= "ANIM_OT_channels_setting_toggle";
1582 ot->description= "Invert specified setting on all selected animation channels";
1585 ot->invoke= WM_menu_invoke;
1586 ot->exec= animchannels_setflag_exec;
1587 ot->poll= animedit_poll_channels_active;
1590 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1593 /* flag-setting mode */
1594 RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_INVERT, "Mode", "");
1595 /* setting to set */
1596 ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
1599 static void ANIM_OT_channels_setting_toggle (wmOperatorType *ot)
1602 ot->name= "Toggle Channel Setting";
1603 ot->idname= "ANIM_OT_channels_setting_toggle";
1604 ot->description= "Toggle specified setting on all selected animation channels";
1607 ot->invoke= WM_menu_invoke;
1608 ot->exec= animchannels_setflag_exec;
1609 ot->poll= animedit_poll_channels_active;
1612 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1615 /* flag-setting mode */
1616 RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", "");
1617 /* setting to set */
1618 ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
1621 static void ANIM_OT_channels_editable_toggle (wmOperatorType *ot)
1624 ot->name= "Toggle Channel Editability";
1625 ot->idname= "ANIM_OT_channels_editable_toggle";
1626 ot->description= "Toggle editability of selected channels";
1629 ot->exec= animchannels_setflag_exec;
1630 ot->poll= animedit_poll_channels_active;
1633 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1636 /* flag-setting mode */
1637 RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", "");
1638 /* setting to set */
1639 RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, ACHANNEL_SETTING_PROTECT, "Type", "");
1642 /* ********************** Expand Channels Operator *********************** */
1644 static int animchannels_expand_exec (bContext *C, wmOperator *op)
1649 /* get editor data */
1650 if (ANIM_animdata_get_context(C, &ac) == 0)
1651 return OPERATOR_CANCELLED;
1653 /* only affect selected channels? */
1654 if (RNA_boolean_get(op->ptr, "all"))
1657 /* modify setting */
1658 setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_ADD, onlysel, 0);
1660 /* send notifier that things have changed */
1661 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1663 return OPERATOR_FINISHED;
1666 static void ANIM_OT_channels_expand (wmOperatorType *ot)
1669 ot->name= "Expand Channels";
1670 ot->idname= "ANIM_OT_channels_expand";
1671 ot->description= "Expand (i.e. open) all selected expandable animation channels";
1674 ot->exec= animchannels_expand_exec;
1675 ot->poll= animedit_poll_channels_active;
1678 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1681 ot->prop= RNA_def_boolean(ot->srna, "all", 1, "All", "Expand all channels (not just selected ones)");
1684 /* ********************** Collapse Channels Operator *********************** */
1686 static int animchannels_collapse_exec (bContext *C, wmOperator *op)
1691 /* get editor data */
1692 if (ANIM_animdata_get_context(C, &ac) == 0)
1693 return OPERATOR_CANCELLED;
1695 /* only affect selected channels? */
1696 if (RNA_boolean_get(op->ptr, "all"))
1699 /* modify setting */
1700 setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_CLEAR, onlysel, 0);
1702 /* send notifier that things have changed */
1703 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1705 return OPERATOR_FINISHED;
1708 static void ANIM_OT_channels_collapse (wmOperatorType *ot)
1711 ot->name= "Collapse Channels";
1712 ot->idname= "ANIM_OT_channels_collapse";
1713 ot->description= "Collapse (i.e. close) all selected expandable animation channels";
1716 ot->exec= animchannels_collapse_exec;
1717 ot->poll= animedit_poll_channels_active;
1720 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1723 ot->prop= RNA_def_boolean(ot->srna, "all", 1, "All", "Collapse all channels (not just selected ones)");
1726 /* ******************* Reenable Disabled Operator ******************* */
1728 static int animchannels_enable_poll (bContext *C)
1730 ScrArea *sa= CTX_wm_area(C);
1732 /* channels region test */
1733 // TODO: could enhance with actually testing if channels region?
1734 if (ELEM(NULL, sa, CTX_wm_region(C)))
1737 /* animation editor test - Action/Dopesheet/etc. and Graph only */
1738 if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO) == 0)
1744 static int animchannels_enable_exec (bContext *C, wmOperator *UNUSED(op))
1748 ListBase anim_data = {NULL, NULL};
1752 /* get editor data */
1753 if (ANIM_animdata_get_context(C, &ac) == 0)
1754 return OPERATOR_CANCELLED;
1757 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS);
1758 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1760 /* loop through filtered data and clean curves */
1761 for (ale= anim_data.first; ale; ale= ale->next) {
1762 FCurve *fcu = (FCurve *)ale->data;
1764 /* remove disabled flags from F-Curves */
1765 fcu->flag &= ~FCURVE_DISABLED;
1767 /* for drivers, let's do the same too */
1769 fcu->driver->flag &= ~DRIVER_FLAG_INVALID;
1771 /* tag everything for updates - in particular, this is needed to get drivers working again */
1772 ANIM_list_elem_update(ac.scene, ale);
1775 /* free temp data */
1776 BLI_freelistN(&anim_data);
1778 /* send notifier that things have changed */
1779 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1781 return OPERATOR_FINISHED;
1784 static void ANIM_OT_channels_fcurves_enable (wmOperatorType *ot)
1787 ot->name= "Revive Disabled F-Curves";
1788 ot->idname= "ANIM_OT_channels_fcurves_enable";
1789 ot->description= "Clears 'disabled' tag from all F-Curves to get broken F-Curves working again";
1792 ot->exec= animchannels_enable_exec;
1793 ot->poll= animchannels_enable_poll;
1796 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1799 /* ********************** Select All Operator *********************** */
1801 static int animchannels_deselectall_exec (bContext *C, wmOperator *op)
1805 /* get editor data */
1806 if (ANIM_animdata_get_context(C, &ac) == 0)
1807 return OPERATOR_CANCELLED;
1809 /* 'standard' behaviour - check if selected, then apply relevant selection */
1810 if (RNA_boolean_get(op->ptr, "invert"))
1811 ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 0, ACHANNEL_SETFLAG_TOGGLE);
1813 ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_ADD);
1815 /* send notifier that things have changed */
1816 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_SELECTED, NULL);
1818 return OPERATOR_FINISHED;
1821 static void ANIM_OT_channels_select_all_toggle (wmOperatorType *ot)
1824 ot->name= "Select All";
1825 ot->idname= "ANIM_OT_channels_select_all_toggle";
1826 ot->description= "Toggle selection of all animation channels";
1829 ot->exec= animchannels_deselectall_exec;
1830 ot->poll= animedit_poll_channels_nla_tweakmode_off;
1833 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1836 ot->prop= RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
1839 /* ******************** Borderselect Operator *********************** */
1841 static void borderselect_anim_channels (bAnimContext *ac, rcti *rect, short selectmode)
1843 ListBase anim_data = {NULL, NULL};
1847 SpaceNla *snla = (SpaceNla *)ac->sl;
1848 View2D *v2d= &ac->ar->v2d;
1852 /* set initial y extents */
1853 if (ac->datatype == ANIMCONT_NLA) {
1854 ymin = (float)(-NLACHANNEL_HEIGHT(snla));
1859 ymax = (float)(-ACHANNEL_HEIGHT);
1862 /* convert border-region to view coordinates */
1863 UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin+2, &rectf.xmin, &rectf.ymin);
1864 UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax-2, &rectf.xmax, &rectf.ymax);
1867 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
1868 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1870 /* loop over data, doing border select */
1871 for (ale= anim_data.first; ale; ale= ale->next) {
1872 if (ac->datatype == ANIMCONT_NLA)
1873 ymin= ymax - NLACHANNEL_STEP(snla);
1875 ymin= ymax - ACHANNEL_STEP;
1877 /* if channel is within border-select region, alter it */
1878 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
1879 /* set selection flags only */
1880 ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, selectmode);
1882 /* type specific actions */
1883 switch (ale->type) {
1884 case ANIMTYPE_GROUP:
1886 bActionGroup *agrp= (bActionGroup *)ale->data;
1888 /* always clear active flag after doing this */
1889 agrp->flag &= ~AGRP_ACTIVE;
1892 case ANIMTYPE_NLATRACK:
1894 NlaTrack *nlt= (NlaTrack *)ale->data;
1896 /* for now, it's easier just to do this here manually, as defining a new type
1897 * currently adds complications when doing other stuff
1899 ACHANNEL_SET_FLAG(nlt, selectmode, NLATRACK_SELECTED);
1905 /* set minimum extent to be the maximum of the next channel */
1910 BLI_freelistN(&anim_data);
1913 /* ------------------- */
1915 static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
1922 /* get editor data */
1923 if (ANIM_animdata_get_context(C, &ac) == 0)
1924 return OPERATOR_CANCELLED;
1926 /* get settings from operator */
1927 rect.xmin= RNA_int_get(op->ptr, "xmin");
1928 rect.ymin= RNA_int_get(op->ptr, "ymin");
1929 rect.xmax= RNA_int_get(op->ptr, "xmax");
1930 rect.ymax= RNA_int_get(op->ptr, "ymax");
1932 gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
1933 if (gesture_mode == GESTURE_MODAL_SELECT)
1934 selectmode = ACHANNEL_SETFLAG_ADD;
1936 selectmode = ACHANNEL_SETFLAG_CLEAR;
1938 /* apply borderselect animation channels */
1939 borderselect_anim_channels(&ac, &rect, selectmode);
1941 /* send notifier that things have changed */
1942 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_SELECTED, NULL);
1944 return OPERATOR_FINISHED;
1947 static void ANIM_OT_channels_select_border(wmOperatorType *ot)
1950 ot->name= "Border Select";
1951 ot->idname= "ANIM_OT_channels_select_border";
1952 ot->description= "Select all animation channels within the specified region";
1955 ot->invoke= WM_border_select_invoke;
1956 ot->exec= animchannels_borderselect_exec;
1957 ot->modal= WM_border_select_modal;
1958 ot->cancel= WM_border_select_cancel;
1960 ot->poll= animedit_poll_channels_nla_tweakmode_off;
1963 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1966 WM_operator_properties_gesture_border(ot, FALSE);
1969 /* ******************* Rename Operator ***************************** */
1970 /* Allow renaming some channels by clicking on them */
1972 static void rename_anim_channels (bAnimContext *ac, int channel_index)
1974 ListBase anim_data = {NULL, NULL};
1975 bAnimChannelType *acf;
1979 /* get the channel that was clicked on */
1980 /* filter channels */
1981 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
1982 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1984 /* get channel from index */
1985 ale= BLI_findlink(&anim_data, channel_index);
1987 /* channel not found */
1989 printf("Error: animation channel (index = %d) not found in rename_anim_channels() \n", channel_index);
1991 BLI_freelistN(&anim_data);
1995 /* check that channel can be renamed */
1996 acf = ANIM_channel_get_typeinfo(ale);
1997 if (acf && acf->name_prop) {
2001 /* ok if we can get name property to edit from this channel */
2002 if (acf->name_prop(ale, &ptr, &prop)) {
2003 /* actually showing the rename textfield is done on redraw,
2004 * so here we just store the index of this channel in the
2005 * dopesheet data, which will get utilised when drawing the
2008 * +1 factor is for backwards compat issues
2011 ac->ads->renameIndex = channel_index + 1;
2016 /* free temp data and tag for refresh */
2017 BLI_freelistN(&anim_data);
2018 ED_region_tag_redraw(ac->ar);
2021 static int animchannels_rename_invoke (bContext *C, wmOperator *UNUSED(op), wmEvent *evt)
2029 /* get editor data */
2030 if (ANIM_animdata_get_context(C, &ac) == 0)
2031 return OPERATOR_CANCELLED;
2033 /* get useful pointers from animation context data */
2037 /* figure out which channel user clicked in
2038 * Note: although channels technically start at y= ACHANNEL_FIRST, we need to adjust by half a channel's height
2039 * so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
2040 * ACHANNEL_HEIGHT_HALF.
2042 UI_view2d_region_to_view(v2d, evt->mval[0], evt->mval[1], &x, &y);
2044 if (ac.datatype == ANIMCONT_NLA) {
2045 SpaceNla *snla = (SpaceNla *)ac.sl;
2046 UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index);
2049 UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
2053 rename_anim_channels(&ac, channel_index);
2055 return OPERATOR_FINISHED;
2058 static void ANIM_OT_channels_rename (wmOperatorType *ot)
2061 ot->name= "Rename Channels";
2062 ot->idname= "ANIM_OT_channels_rename";
2063 ot->description= "Rename animation channel under mouse";
2066 ot->invoke= animchannels_rename_invoke;
2067 ot->poll= animedit_poll_channels_active;
2070 /* ******************** Mouse-Click Operator *********************** */
2071 /* Handle selection changes due to clicking on channels. Settings will get caught by UI code... */
2073 static int mouse_anim_channels (bAnimContext *ac, float UNUSED(x), int channel_index, short selectmode)
2075 ListBase anim_data = {NULL, NULL};
2078 int notifierFlags = 0;
2080 /* get the channel that was clicked on */
2081 /* filter channels */
2082 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
2083 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
2085 /* get channel from index */
2086 ale= BLI_findlink(&anim_data, channel_index);
2088 /* channel not found */
2090 printf("Error: animation channel (index = %d) not found in mouse_anim_channels() \n", channel_index);
2092 BLI_freelistN(&anim_data);
2096 /* selectmode -1 is a special case for ActionGroups only, which selects all of the channels underneath it only... */
2097 // TODO: should this feature be extended to work with other channel types too?
2098 if ((selectmode == -1) && (ale->type != ANIMTYPE_GROUP)) {
2099 /* normal channels should not behave normally in this case */
2100 BLI_freelistN(&anim_data);
2104 /* action to take depends on what channel we've got */
2105 // WARNING: must keep this in sync with the equivalent function in nla_channels.c
2106 switch (ale->type) {
2107 case ANIMTYPE_SCENE:
2109 Scene *sce= (Scene *)ale->data;
2110 AnimData *adt= sce->adt;
2112 /* set selection status */
2113 if (selectmode == SELECT_INVERT) {
2115 sce->flag ^= SCE_DS_SELECTED;
2116 if (adt) adt->flag ^= ADT_UI_SELECTED;
2119 sce->flag |= SCE_DS_SELECTED;
2120 if (adt) adt->flag |= ADT_UI_SELECTED;
2123 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
2126 case ANIMTYPE_OBJECT:
2128 bDopeSheet *ads= (bDopeSheet *)ac->data;
2129 Scene *sce= (Scene *)ads->source;
2130 Base *base= (Base *)ale->data;
2131 Object *ob= base->object;
2132 AnimData *adt= ob->adt;
2134 /* set selection status */
2135 if (selectmode == SELECT_INVERT) {
2137 base->flag ^= SELECT;
2138 ob->flag= base->flag;
2140 if (adt) adt->flag ^= ADT_UI_SELECTED;
2146 // TODO: should this deselect all other types of channels too?
2147 for (b= sce->base.first; b; b= b->next) {
2149 b->object->flag= b->flag;
2150 if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED|ADT_UI_ACTIVE);
2153 /* select object now */
2154 base->flag |= SELECT;
2156 if (adt) adt->flag |= ADT_UI_SELECTED;
2159 if ((adt) && (adt->flag & ADT_UI_SELECTED))
2160 adt->flag |= ADT_UI_ACTIVE;
2162 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
2166 case ANIMTYPE_FILLACTD: /* Action Expander */
2167 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
2168 case ANIMTYPE_DSLAM:
2169 case ANIMTYPE_DSCAM:
2170 case ANIMTYPE_DSCUR:
2171 case ANIMTYPE_DSSKEY:
2172 case ANIMTYPE_DSWOR:
2173 case ANIMTYPE_DSPART:
2174 case ANIMTYPE_DSMBALL:
2175 case ANIMTYPE_DSARM:
2176 case ANIMTYPE_DSMESH:
2177 case ANIMTYPE_DSNTREE:
2178 case ANIMTYPE_DSTEX:
2179 case ANIMTYPE_DSLAT:
2180 case ANIMTYPE_DSSPK:
2182 /* sanity checking... */
2184 /* select/deselect */
2185 if (selectmode == SELECT_INVERT) {
2186 /* inverse selection status of this AnimData block only */
2187 ale->adt->flag ^= ADT_UI_SELECTED;
2190 /* select AnimData block by itself */
2191 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
2192 ale->adt->flag |= ADT_UI_SELECTED;
2196 if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
2197 ale->adt->flag |= ADT_UI_ACTIVE;
2200 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
2204 case ANIMTYPE_GROUP:
2206 bActionGroup *agrp= (bActionGroup *)ale->data;
2208 /* select/deselect group */
2209 if (selectmode == SELECT_INVERT) {
2210 /* inverse selection status of this group only */
2211 agrp->flag ^= AGRP_SELECTED;
2213 else if (selectmode == -1) {
2214 /* select all in group (and deselect everthing else) */
2217 /* deselect all other channels */
2218 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
2220 /* only select channels in group and group itself */
2221 for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next)
2222 fcu->flag |= FCURVE_SELECTED;
2223 agrp->flag |= AGRP_SELECTED;
2226 /* select group by itself */
2227 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
2228 agrp->flag |= AGRP_SELECTED;
2231 /* if group is selected now, make group the 'active' one in the visible list */
2232 if (agrp->flag & AGRP_SELECTED)
2233 ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
2235 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
2238 case ANIMTYPE_FCURVE:
2240 FCurve *fcu= (FCurve *)ale->data;
2242 /* select/deselect */
2243 if (selectmode == SELECT_INVERT) {
2244 /* inverse selection status of this F-Curve only */
2245 fcu->flag ^= FCURVE_SELECTED;
2248 /* select F-Curve by itself */
2249 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
2250 fcu->flag |= FCURVE_SELECTED;
2253 /* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */
2254 if (fcu->flag & FCURVE_SELECTED)
2255 ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
2257 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
2260 case ANIMTYPE_SHAPEKEY:
2262 KeyBlock *kb= (KeyBlock *)ale->data;
2264 /* select/deselect */
2265 if (selectmode == SELECT_INVERT) {
2266 /* inverse selection status of this ShapeKey only */
2267 kb->flag ^= KEYBLOCK_SEL;
2270 /* select ShapeKey by itself */
2271 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
2272 kb->flag |= KEYBLOCK_SEL;
2275 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
2278 case ANIMTYPE_GPDATABLOCK:
2280 bGPdata *gpd= (bGPdata *)ale->data;
2283 * - although the triangle widget already allows this, the whole channel can also be used for this purpose
2285 gpd->flag ^= GP_DATA_EXPAND;
2287 notifierFlags |= (ND_ANIMCHAN|NA_EDITED);
2290 case ANIMTYPE_GPLAYER:
2292 bGPDlayer *gpl= (bGPDlayer *)ale->data;
2294 /* select/deselect */
2295 if (selectmode == SELECT_INVERT) {
2296 /* invert selection status of this layer only */
2297 gpl->flag ^= GP_LAYER_SELECT;
2300 /* select layer by itself */
2301 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
2302 gpl->flag |= GP_LAYER_SELECT;
2305 notifierFlags |= (ND_ANIMCHAN|NA_EDITED);
2310 printf("Error: Invalid channel type in mouse_anim_channels() \n");
2314 BLI_freelistN(&anim_data);
2316 /* return notifier flags */
2317 return notifierFlags;
2320 /* ------------------- */
2322 /* handle clicking */
2323 static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event)
2329 int notifierFlags = 0;
2334 /* get editor data */
2335 if (ANIM_animdata_get_context(C, &ac) == 0)
2336 return OPERATOR_CANCELLED;
2338 /* get useful pointers from animation context data */
2342 /* select mode is either replace (deselect all, then add) or add/extend */
2343 if (RNA_boolean_get(op->ptr, "extend"))
2344 selectmode= SELECT_INVERT;
2345 else if (RNA_boolean_get(op->ptr, "children_only"))
2346 selectmode= -1; /* this is a bit of a special case for ActionGroups only... should it be removed or extended to all instead? */
2348 selectmode= SELECT_REPLACE;
2350 /* figure out which channel user clicked in
2351 * Note: although channels technically start at y= ACHANNEL_FIRST, we need to adjust by half a channel's height
2352 * so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
2353 * ACHANNEL_HEIGHT_HALF.
2355 UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
2356 UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
2358 /* handle mouse-click in the relevant channel then */
2359 notifierFlags= mouse_anim_channels(&ac, x, channel_index, selectmode);
2361 /* set notifier that things have changed */
2362 WM_event_add_notifier(C, NC_ANIMATION|notifierFlags, NULL);
2364 return OPERATOR_FINISHED;
2367 static void ANIM_OT_channels_click (wmOperatorType *ot)
2370 ot->name= "Mouse Click on Channels";
2371 ot->idname= "ANIM_OT_channels_click";
2372 ot->description= "Handle mouse-clicks over animation channels";
2375 ot->invoke= animchannels_mouseclick_invoke;
2376 ot->poll= animedit_poll_channels_active;
2379 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2382 RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
2383 RNA_def_boolean(ot->srna, "children_only", 0, "Select Children Only", ""); // CTRLKEY|SHIFTKEY
2386 /* ************************************************************************** */
2387 /* Operator Registration */
2389 void ED_operatortypes_animchannels(void)
2391 WM_operatortype_append(ANIM_OT_channels_select_all_toggle);
2392 WM_operatortype_append(ANIM_OT_channels_select_border);
2394 WM_operatortype_append(ANIM_OT_channels_click);
2395 WM_operatortype_append(ANIM_OT_channels_rename);
2397 WM_operatortype_append(ANIM_OT_channels_setting_enable);
2398 WM_operatortype_append(ANIM_OT_channels_setting_disable);
2399 WM_operatortype_append(ANIM_OT_channels_setting_invert);
2400 WM_operatortype_append(ANIM_OT_channels_setting_toggle);
2402 WM_operatortype_append(ANIM_OT_channels_delete);
2404 // XXX does this need to be a separate operator?
2405 WM_operatortype_append(ANIM_OT_channels_editable_toggle);
2407 WM_operatortype_append(ANIM_OT_channels_move);
2409 WM_operatortype_append(ANIM_OT_channels_expand);
2410 WM_operatortype_append(ANIM_OT_channels_collapse);
2412 WM_operatortype_append(ANIM_OT_channels_visibility_toggle);
2413 WM_operatortype_append(ANIM_OT_channels_visibility_set);
2415 WM_operatortype_append(ANIM_OT_channels_fcurves_enable);
2418 // TODO: check on a poll callback for this, to get hotkeys into menus
2419 void ED_keymap_animchannels(wmKeyConfig *keyconf)
2421 wmKeyMap *keymap = WM_keymap_find(keyconf, "Animation Channels", 0, 0);
2425 // XXX for now, only leftmouse....
2426 WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, 0, 0);
2427 RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
2428 RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_CTRL|KM_SHIFT, 0)->ptr, "children_only", 1);
2431 WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
2434 WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", AKEY, KM_PRESS, 0, 0);
2435 RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
2438 WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", BKEY, KM_PRESS, 0, 0);
2439 WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", EVT_TWEAK_L, KM_ANY, 0, 0);
2442 WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", XKEY, KM_PRESS, 0, 0);
2443 WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", DELKEY, KM_PRESS, 0, 0);
2446 WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_toggle", WKEY, KM_PRESS, KM_SHIFT, 0);
2447 WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_enable", WKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
2448 WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_disable", WKEY, KM_PRESS, KM_ALT, 0);
2450 /* settings - specialised hotkeys */
2451 WM_keymap_add_item(keymap, "ANIM_OT_channels_editable_toggle", TABKEY, KM_PRESS, 0, 0);
2453 /* expand/collapse */
2454 WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, 0, 0);
2455 WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, 0, 0);
2457 RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, KM_CTRL, 0)->ptr, "all", 0);
2458 RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, KM_CTRL, 0)->ptr, "all", 0);
2461 RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEUPKEY, KM_PRESS, 0, 0)->ptr, "direction", REARRANGE_ANIMCHAN_UP);
2462 RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEDOWNKEY, KM_PRESS, 0, 0)->ptr, "direction", REARRANGE_ANIMCHAN_DOWN);
2463 RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "direction", REARRANGE_ANIMCHAN_TOP);
2464 RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "direction", REARRANGE_ANIMCHAN_BOTTOM);
2466 /* Graph Editor only */
2467 WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_set", VKEY, KM_PRESS, 0, 0);
2468 WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_toggle", VKEY, KM_PRESS, KM_SHIFT, 0);
2471 /* ************************************************************************** */