4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
21 * All rights reserved.
23 * Contributor(s): Joshua Leung
25 * ***** END GPL LICENSE BLOCK *****
28 #include "MEM_guardedalloc.h"
30 #include "BLI_blenlib.h"
32 #include "DNA_anim_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_scene_types.h"
35 #include "DNA_key_types.h"
36 #include "DNA_gpencil_types.h"
38 #include "RNA_access.h"
39 #include "RNA_define.h"
41 #include "BKE_action.h"
42 #include "BKE_fcurve.h"
43 #include "BKE_context.h"
44 #include "BKE_global.h"
46 #include "UI_view2d.h"
48 #include "ED_anim_api.h"
49 #include "ED_keyframes_edit.h" // XXX move the select modes out of there!
50 #include "ED_screen.h"
55 /* ************************************************************************** */
56 /* CHANNELS API - Exposed API */
58 /* -------------------------- Selection ------------------------------------- */
60 /* Set the given animation-channel as the active one for the active context */
61 // TODO: extend for animdata types...
62 void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type)
64 ListBase anim_data = {NULL, NULL};
67 /* try to build list of filtered items */
68 ANIM_animdata_filter(ac, &anim_data, filter, data, datatype);
69 if (anim_data.first == NULL)
72 /* only clear the 'active' flag for the channels of the same type */
73 for (ale= anim_data.first; ale; ale= ale->next) {
74 /* skip if types don't match */
75 if (channel_type != ale->type)
78 /* flag to set depends on type */
82 bActionGroup *agrp= (bActionGroup *)ale->data;
84 ACHANNEL_SET_FLAG(agrp, ACHANNEL_SETFLAG_CLEAR, AGRP_ACTIVE);
89 FCurve *fcu= (FCurve *)ale->data;
91 ACHANNEL_SET_FLAG(fcu, ACHANNEL_SETFLAG_CLEAR, FCURVE_ACTIVE);
94 case ANIMTYPE_NLATRACK:
96 NlaTrack *nlt= (NlaTrack *)ale->data;
98 ACHANNEL_SET_FLAG(nlt, ACHANNEL_SETFLAG_CLEAR, NLATRACK_ACTIVE);
102 case ANIMTYPE_FILLACTD: /* Action Expander */
103 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
107 case ANIMTYPE_DSSKEY:
109 case ANIMTYPE_DSPART:
110 case ANIMTYPE_DSMBALL:
112 case ANIMTYPE_DSMESH:
114 /* need to verify that this data is valid for now */
116 ACHANNEL_SET_FLAG(ale->adt, ACHANNEL_SETFLAG_CLEAR, ADT_UI_ACTIVE);
123 /* set active flag */
125 switch (channel_type) {
128 bActionGroup *agrp= (bActionGroup *)channel_data;
129 agrp->flag |= AGRP_ACTIVE;
132 case ANIMTYPE_FCURVE:
134 FCurve *fcu= (FCurve *)channel_data;
135 fcu->flag |= FCURVE_ACTIVE;
138 case ANIMTYPE_NLATRACK:
140 NlaTrack *nlt= (NlaTrack *)channel_data;
141 nlt->flag |= NLATRACK_ACTIVE;
145 case ANIMTYPE_FILLACTD: /* Action Expander */
146 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
150 case ANIMTYPE_DSSKEY:
152 case ANIMTYPE_DSPART:
153 case ANIMTYPE_DSMBALL:
155 case ANIMTYPE_DSMESH:
157 /* need to verify that this data is valid for now */
158 // XXX: ale may be null!
160 ale->adt->flag |= ADT_UI_ACTIVE;
167 BLI_freelistN(&anim_data);
170 /* Deselect all animation channels
171 * - data: pointer to datatype, as contained in bAnimContext
172 * - datatype: the type of data that 'data' represents (eAnimCont_Types)
173 * - test: check if deselecting instead of selecting
174 * - sel: eAnimChannels_SetFlag;
176 void ANIM_deselect_anim_channels (bAnimContext *ac, void *data, short datatype, short test, short sel)
178 ListBase anim_data = {NULL, NULL};
183 filter= ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS;
184 ANIM_animdata_filter(ac, &anim_data, filter, data, datatype);
186 /* See if we should be selecting or deselecting */
188 for (ale= anim_data.first; ale; ale= ale->next) {
194 if (ale->flag & SCE_DS_SELECTED)
195 sel= ACHANNEL_SETFLAG_CLEAR;
197 case ANIMTYPE_OBJECT:
198 #if 0 /* for now, do not take object selection into account, since it gets too annoying */
199 if (ale->flag & SELECT)
200 sel= ACHANNEL_SETFLAG_CLEAR;
204 if (ale->flag & AGRP_SELECTED)
205 sel= ACHANNEL_SETFLAG_CLEAR;
207 case ANIMTYPE_FCURVE:
208 if (ale->flag & FCURVE_SELECTED)
209 sel= ACHANNEL_SETFLAG_CLEAR;
211 case ANIMTYPE_SHAPEKEY:
212 if (ale->flag & KEYBLOCK_SEL)
213 sel= ACHANNEL_SETFLAG_CLEAR;
215 case ANIMTYPE_NLATRACK:
216 if (ale->flag & NLATRACK_SELECTED)
217 sel= ACHANNEL_SETFLAG_CLEAR;
220 case ANIMTYPE_FILLACTD: /* Action Expander */
221 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
225 case ANIMTYPE_DSSKEY:
227 case ANIMTYPE_DSPART:
228 case ANIMTYPE_DSMBALL:
230 case ANIMTYPE_DSMESH:
231 case ANIMTYPE_DSNTREE:
233 case ANIMTYPE_DSLINESTYLE:
235 if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
236 sel= ACHANNEL_SETFLAG_CLEAR;
243 /* Now set the flags */
244 for (ale= anim_data.first; ale; ale= ale->next) {
248 Scene *scene= (Scene *)ale->data;
250 ACHANNEL_SET_FLAG(scene, sel, SCE_DS_SELECTED);
253 ACHANNEL_SET_FLAG(scene, sel, ADT_UI_SELECTED);
257 case ANIMTYPE_OBJECT:
258 #if 0 /* for now, do not take object selection into account, since it gets too annoying */
260 Base *base= (Base *)ale->data;
261 Object *ob= base->object;
263 ACHANNEL_SET_FLAG(base, sel, SELECT);
264 ACHANNEL_SET_FLAG(ob, sel, SELECT);
267 ACHANNEL_SET_FLAG(ob, sel, ADT_UI_SELECTED);
274 bActionGroup *agrp= (bActionGroup *)ale->data;
276 ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED);
277 agrp->flag &= ~AGRP_ACTIVE;
280 case ANIMTYPE_FCURVE:
282 FCurve *fcu= (FCurve *)ale->data;
284 ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED);
285 fcu->flag &= ~FCURVE_ACTIVE;
288 case ANIMTYPE_SHAPEKEY:
290 KeyBlock *kb= (KeyBlock *)ale->data;
292 ACHANNEL_SET_FLAG(kb, sel, KEYBLOCK_SEL);
295 case ANIMTYPE_NLATRACK:
297 NlaTrack *nlt= (NlaTrack *)ale->data;
299 ACHANNEL_SET_FLAG(nlt, sel, NLATRACK_SELECTED);
300 nlt->flag &= ~NLATRACK_ACTIVE;
304 case ANIMTYPE_FILLACTD: /* Action Expander */
305 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
309 case ANIMTYPE_DSSKEY:
311 case ANIMTYPE_DSPART:
312 case ANIMTYPE_DSMBALL:
314 case ANIMTYPE_DSMESH:
315 case ANIMTYPE_DSNTREE:
317 case ANIMTYPE_DSLINESTYLE:
319 /* need to verify that this data is valid for now */
321 ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED);
322 ale->adt->flag &= ~ADT_UI_ACTIVE;
330 BLI_freelistN(&anim_data);
333 /* ---------------------------- Graph Editor ------------------------------------- */
335 /* Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting
336 * - anim_data: list of the all the anim channels that can be chosen
337 * -> filtered using ANIMFILTER_CHANNELS only, since if we took VISIBLE too,
338 * then the channels under closed expanders get ignored...
339 * - ale_setting: the anim channel (not in the anim_data list directly, though occuring there)
340 * with the new state of the setting that we want flushed up/down the hierarchy
341 * - setting: type of setting to set
342 * - on: whether the visibility setting has been enabled or disabled
344 void ANIM_flush_setting_anim_channels (bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, int setting, short on)
346 bAnimListElem *ale, *match=NULL;
347 int prevLevel=0, matchLevel=0;
350 if (ELEM(NULL, anim_data, anim_data->first))
353 /* find the channel that got changed */
354 for (ale= anim_data->first; ale; ale= ale->next) {
355 /* compare data, and type as main way of identifying the channel */
356 if ((ale->data == ale_setting->data) && (ale->type == ale_setting->type)) {
357 /* we also have to check the ID, this is assigned to, since a block may have multiple users */
358 // TODO: is the owner-data more revealing?
359 if (ale->id == ale_setting->id) {
366 printf("ERROR: no channel matching the one changed was found \n");
370 bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale_setting);
373 printf("ERROR: no channel info for the changed channel \n");
377 /* get the level of the channel that was affected
378 * - we define the level as simply being the offset for the start of the channel
380 matchLevel= (acf->get_offset)? acf->get_offset(ac, ale_setting) : 0;
381 prevLevel= matchLevel;
387 * - only flush up if the current state is now enabled (positive 'on' state is default)
388 * (otherwise, it's too much work to force the parents to be inactive too)
390 * For everything else:
391 * - only flush up if the current state is now disabled (negative 'off' state is default)
392 * (otherwise, it's too much work to force the parents to be active too)
394 if ( ((setting == ACHANNEL_SETTING_VISIBLE) && on) ||
395 ((setting != ACHANNEL_SETTING_VISIBLE) && on==0) )
397 /* go backwards in the list, until the highest-ranking element (by indention has been covered) */
398 for (ale= match->prev; ale; ale= ale->prev) {
399 bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale);
402 /* if no channel info was found, skip, since this type might not have any useful info */
406 /* get the level of the current channel traversed
407 * - we define the level as simply being the offset for the start of the channel
409 level= (acf->get_offset)? acf->get_offset(ac, ale) : 0;
411 /* if the level is 'less than' (i.e. more important) the level we're matching
412 * but also 'less than' the level just tried (i.e. only the 1st group above grouped F-Curves,
413 * when toggling visibility of F-Curves, gets flushed, which should happen if we don't let prevLevel
414 * get updated below once the first 1st group is found)...
416 if (level < prevLevel) {
417 /* flush the new status... */
418 ANIM_channel_setting_set(ac, ale, setting, on);
420 /* store this level as the 'old' level now */
423 /* if the level is 'greater than' (i.e. less important) than the previous level... */
424 else if (level > prevLevel) {
425 /* if previous level was a base-level (i.e. 0 offset / root of one hierarchy),
430 /* otherwise, this level weaves into another sibling hierarchy to the previous one just
431 * finished, so skip until we get to the parent of this level
439 /* flush down (always) */
441 /* go forwards in the list, until the lowest-ranking element (by indention has been covered) */
442 for (ale= match->next; ale; ale= ale->next) {
443 bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale);
446 /* if no channel info was found, skip, since this type might not have any useful info */
450 /* get the level of the current channel traversed
451 * - we define the level as simply being the offset for the start of the channel
453 level= (acf->get_offset)? acf->get_offset(ac, ale) : 0;
455 /* if the level is 'greater than' (i.e. less important) the channel that was changed,
456 * flush the new status...
458 if (level > matchLevel)
459 ANIM_channel_setting_set(ac, ale, setting, on);
460 /* however, if the level is 'less than or equal to' the channel that was changed,
461 * (i.e. the current channel is as important if not more important than the changed channel)
462 * then we should stop, since we've found the last one of the children we should flush
467 /* store this level as the 'old' level now */
468 prevLevel= level; // XXX: prevLevel is unused
473 /* -------------------------- F-Curves ------------------------------------- */
475 /* Delete the given F-Curve from its AnimData block */
476 void ANIM_fcurve_delete_from_animdata (bAnimContext *ac, AnimData *adt, FCurve *fcu)
478 /* - if no AnimData, we've got nowhere to remove the F-Curve from
479 * (this doesn't guarantee that the F-Curve is in there, but at least we tried
480 * - if no F-Curve, there is nothing to remove
482 if (ELEM(NULL, adt, fcu))
485 /* remove from whatever list it came from
489 * - TODO... some others?
492 action_groups_remove_channel(adt->action, fcu);
493 else if ((ac) && (ac->datatype == ANIMCONT_DRIVERS))
494 BLI_remlink(&adt->drivers, fcu);
495 else if (adt->action)
496 BLI_remlink(&adt->action->curves, fcu);
498 /* free the F-Curve itself */
502 /* ************************************************************************** */
505 /* ****************** Operator Utilities ********************************** */
507 /* poll callback for being in an Animation Editor channels list region */
508 int animedit_poll_channels_active (bContext *C)
510 ScrArea *sa= CTX_wm_area(C);
512 /* channels region test */
513 // TODO: could enhance with actually testing if channels region?
514 if (ELEM(NULL, sa, CTX_wm_region(C)))
516 /* animation editor test */
517 if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
523 /* poll callback for Animation Editor channels list region + not in NLA-tweakmode for NLA */
524 int animedit_poll_channels_nla_tweakmode_off (bContext *C)
526 ScrArea *sa= CTX_wm_area(C);
527 Scene *scene = CTX_data_scene(C);
529 /* channels region test */
530 // TODO: could enhance with actually testing if channels region?
531 if (ELEM(NULL, sa, CTX_wm_region(C)))
533 /* animation editor test */
534 if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
537 /* NLA TweakMode test */
538 if (sa->spacetype == SPACE_NLA) {
539 if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON))
546 /* ****************** Rearrange Channels Operator ******************* */
547 /* This operator only works for Action Editor mode for now, as having it elsewhere makes things difficult */
549 #if 0 // XXX old animation system - needs to be updated for new system...
551 /* constants for channel rearranging */
552 /* WARNING: don't change exising ones without modifying rearrange func accordingly */
554 REARRANGE_ACTCHAN_TOP= -2,
555 REARRANGE_ACTCHAN_UP= -1,
556 REARRANGE_ACTCHAN_DOWN= 1,
557 REARRANGE_ACTCHAN_BOTTOM= 2
560 /* make sure all action-channels belong to a group (and clear action's list) */
561 static void split_groups_action_temp (bAction *act, bActionGroup *tgrp)
563 bActionChannel *achan;
566 /* Separate action-channels into lists per group */
567 for (agrp= act->groups.first; agrp; agrp= agrp->next) {
568 if (agrp->channels.first) {
569 achan= agrp->channels.last;
570 act->chanbase.first= achan->next;
572 achan= agrp->channels.first;
575 achan= agrp->channels.last;
580 /* Initialise memory for temp-group */
581 memset(tgrp, 0, sizeof(bActionGroup));
582 tgrp->flag |= (AGRP_EXPANDED|AGRP_TEMP);
583 strcpy(tgrp->name, "#TempGroup");
585 /* Move any action-channels not already moved, to the temp group */
586 if (act->chanbase.first) {
588 achan= act->chanbase.first;
590 tgrp->channels.first= achan;
591 act->chanbase.first= NULL;
594 achan= act->chanbase.last;
596 tgrp->channels.last= achan;
597 act->chanbase.last= NULL;
600 /* Add temp-group to list */
601 BLI_addtail(&act->groups, tgrp);
604 /* link lists of channels that groups have */
605 static void join_groups_action_temp (bAction *act)
608 bActionChannel *achan;
610 for (agrp= act->groups.first; agrp; agrp= agrp->next) {
613 /* add list of channels to action's channels */
614 tempGroup= agrp->channels;
615 addlisttolist(&act->chanbase, &agrp->channels);
616 agrp->channels= tempGroup;
618 /* clear moved flag */
619 agrp->flag &= ~AGRP_MOVED;
621 /* if temp-group... remove from list (but don't free as it's on the stack!) */
622 if (agrp->flag & AGRP_TEMP) {
623 BLI_remlink(&act->groups, agrp);
628 /* clear "moved" flag from all achans */
629 for (achan= act->chanbase.first; achan; achan= achan->next)
630 achan->flag &= ~ACHAN_MOVED;
634 static short rearrange_actchannel_is_ok (Link *channel, short type)
636 if (type == ANIMTYPE_GROUP) {
637 bActionGroup *agrp= (bActionGroup *)channel;
639 if (SEL_AGRP(agrp) && !(agrp->flag & AGRP_MOVED))
642 else if (type == ANIMTYPE_ACHAN) {
643 bActionChannel *achan= (bActionChannel *)channel;
645 if (VISIBLE_ACHAN(achan) && SEL_ACHAN(achan) && !(achan->flag & ACHAN_MOVED))
652 static short rearrange_actchannel_after_ok (Link *channel, short type)
654 if (type == ANIMTYPE_GROUP) {
655 bActionGroup *agrp= (bActionGroup *)channel;
657 if (agrp->flag & AGRP_TEMP)
665 static short rearrange_actchannel_top (ListBase *list, Link *channel, short type)
667 if (rearrange_actchannel_is_ok(channel, type)) {
668 /* take it out off the chain keep data */
669 BLI_remlink(list, channel);
671 /* make it first element */
672 BLI_insertlinkbefore(list, list->first, channel);
680 static short rearrange_actchannel_up (ListBase *list, Link *channel, short type)
682 if (rearrange_actchannel_is_ok(channel, type)) {
683 Link *prev= channel->prev;
686 /* take it out off the chain keep data */
687 BLI_remlink(list, channel);
690 BLI_insertlinkbefore(list, prev, channel);
699 static short rearrange_actchannel_down (ListBase *list, Link *channel, short type)
701 if (rearrange_actchannel_is_ok(channel, type)) {
702 Link *next = (channel->next) ? channel->next->next : NULL;
705 /* take it out off the chain keep data */
706 BLI_remlink(list, channel);
709 BLI_insertlinkbefore(list, next, channel);
713 else if (rearrange_actchannel_after_ok(list->last, type)) {
714 /* take it out off the chain keep data */
715 BLI_remlink(list, channel);
718 BLI_addtail(list, channel);
723 /* take it out off the chain keep data */
724 BLI_remlink(list, channel);
726 /* add just before end */
727 BLI_insertlinkbefore(list, list->last, channel);
736 static short rearrange_actchannel_bottom (ListBase *list, Link *channel, short type)
738 if (rearrange_actchannel_is_ok(channel, type)) {
739 if (rearrange_actchannel_after_ok(list->last, type)) {
740 /* take it out off the chain keep data */
741 BLI_remlink(list, channel);
744 BLI_addtail(list, channel);
754 /* Change the order of action-channels
755 * mode: REARRANGE_ACTCHAN_*
757 static void rearrange_action_channels (bAnimContext *ac, short mode)
760 bActionChannel *achan, *chan;
761 bActionGroup *agrp, *grp;
764 short (*rearrange_func)(ListBase *, Link *, short);
765 short do_channels = 1;
767 /* Get the active action, exit if none are selected */
768 act= (bAction *)ac->data;
770 /* exit if invalid mode */
772 case REARRANGE_ACTCHAN_TOP:
773 rearrange_func= rearrange_actchannel_top;
775 case REARRANGE_ACTCHAN_UP:
776 rearrange_func= rearrange_actchannel_up;
778 case REARRANGE_ACTCHAN_DOWN:
779 rearrange_func= rearrange_actchannel_down;
781 case REARRANGE_ACTCHAN_BOTTOM:
782 rearrange_func= rearrange_actchannel_bottom;
788 /* make sure we're only operating with groups */
789 split_groups_action_temp(act, &tgrp);
791 /* rearrange groups first (and then, only consider channels if the groups weren't moved) */
792 #define GET_FIRST(list) ((mode > 0) ? (list.first) : (list.last))
793 #define GET_NEXT(item) ((mode > 0) ? (item->next) : (item->prev))
795 for (agrp= GET_FIRST(act->groups); agrp; agrp= grp) {
796 /* Get next group to consider */
799 /* try to do group first */
800 if (rearrange_func(&act->groups, (Link *)agrp, ANIMTYPE_GROUP)) {
802 agrp->flag |= AGRP_MOVED;
807 for (agrp= GET_FIRST(act->groups); agrp; agrp= grp) {
808 /* Get next group to consider */
811 /* only consider action-channels if they're visible (group expanded) */
812 if (EXPANDED_AGRP(agrp)) {
813 for (achan= GET_FIRST(agrp->channels); achan; achan= chan) {
814 /* Get next channel to consider */
815 chan= GET_NEXT(achan);
817 /* Try to do channel */
818 if (rearrange_func(&agrp->channels, (Link *)achan, ANIMTYPE_ACHAN))
819 achan->flag |= ACHAN_MOVED;
827 /* assemble lists into one list (and clear moved tags) */
828 join_groups_action_temp(act);
831 /* ------------------- */
833 static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
838 /* get editor data - only for Action Editor (for now) */
839 if (ANIM_animdata_get_context(C, &ac) == 0)
840 return OPERATOR_CANCELLED;
841 if (ac.datatype != ANIMCONT_ACTION)
842 return OPERATOR_PASS_THROUGH;
844 /* get mode, then rearrange channels */
845 mode= RNA_enum_get(op->ptr, "direction");
846 rearrange_action_channels(&ac, mode);
848 /* send notifier that things have changed */
849 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
851 return OPERATOR_FINISHED;
855 void ANIM_OT_channels_move_up (wmOperatorType *ot)
858 ot->name= "Move Channel(s) Up";
859 ot->idname= "ANIM_OT_channels_move_up";
862 ot->exec= animchannels_rearrange_exec;
863 ot->poll= ED_operator_areaactive;
866 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
869 RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_UP, "Direction", "");
872 void ANIM_OT_channels_move_down (wmOperatorType *ot)
875 ot->name= "Move Channel(s) Down";
876 ot->idname= "ANIM_OT_channels_move_down";
879 ot->exec= animchannels_rearrange_exec;
880 ot->poll= ED_operator_areaactive;
883 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
886 RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_DOWN, "Direction", "");
889 void ANIM_OT_channels_move_top (wmOperatorType *ot)
892 ot->name= "Move Channel(s) to Top";
893 ot->idname= "ANIM_OT_channels_move_to_top";
896 ot->exec= animchannels_rearrange_exec;
897 ot->poll= ED_operator_areaactive;
900 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
903 RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_TOP, "Direction", "");
906 void ANIM_OT_channels_move_bottom (wmOperatorType *ot)
909 ot->name= "Move Channel(s) to Bottom";
910 ot->idname= "ANIM_OT_channels_move_to_bottom";
913 ot->exec= animchannels_rearrange_exec;
914 ot->poll= ED_operator_areaactive;
917 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
920 RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_BOTTOM, "Direction", "");
923 #endif // XXX old animation system - needs to be updated for new system...
925 /* ******************** Delete Channel Operator *********************** */
927 static int animchannels_delete_exec(bContext *C, wmOperator *op)
930 ListBase anim_data = {NULL, NULL};
934 /* get editor data */
935 if (ANIM_animdata_get_context(C, &ac) == 0)
936 return OPERATOR_CANCELLED;
938 /* cannot delete in shapekey */
939 if (ac.datatype == ANIMCONT_SHAPEKEY)
940 return OPERATOR_CANCELLED;
943 /* do groups only first (unless in Drivers mode, where there are none) */
944 if (ac.datatype != ANIMCONT_DRIVERS) {
946 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CHANNELS | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
947 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
949 /* delete selected groups and their associated channels */
950 for (ale= anim_data.first; ale; ale= ale->next) {
951 /* only groups - don't check other types yet, since they may no-longer exist */
952 if (ale->type == ANIMTYPE_GROUP) {
953 bActionGroup *agrp= (bActionGroup *)ale->data;
954 AnimData *adt= ale->adt;
957 /* skip this group if no AnimData available, as we can't safely remove the F-Curves */
961 /* delete all of the Group's F-Curves, but no others */
962 for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcn) {
965 /* remove from group and action, then free */
966 action_groups_remove_channel(adt->action, fcu);
970 /* free the group itself */
972 BLI_freelinkN(&adt->action->groups, agrp);
979 BLI_freelistN(&anim_data);
982 /* now do F-Curves */
983 if (ac.datatype != ANIMCONT_GPENCIL) {
985 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
986 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
988 /* delete selected F-Curves */
989 for (ale= anim_data.first; ale; ale= ale->next) {
990 /* only F-Curves, and only if we can identify its parent */
991 if (ale->type == ANIMTYPE_FCURVE) {
992 AnimData *adt= ale->adt;
993 FCurve *fcu= (FCurve *)ale->data;
995 /* try to free F-Curve */
996 ANIM_fcurve_delete_from_animdata(&ac, adt, fcu);
1001 BLI_freelistN(&anim_data);
1004 /* send notifier that things have changed */
1005 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1007 return OPERATOR_FINISHED;
1010 void ANIM_OT_channels_delete (wmOperatorType *ot)
1013 ot->name= "Delete Channels";
1014 ot->idname= "ANIM_OT_channels_delete";
1015 ot->description= "Delete all selected animation channels";
1018 ot->exec= animchannels_delete_exec;
1019 ot->poll= animedit_poll_channels_active;
1022 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1025 /* ******************** Set Channel Visibility Operator *********************** */
1026 /* NOTE: this operator is only valid in the Graph Editor channels region */
1028 static int animchannels_visibility_set_exec(bContext *C, wmOperator *op)
1031 ListBase anim_data = {NULL, NULL};
1032 ListBase all_data = {NULL, NULL};
1036 /* get editor data */
1037 if (ANIM_animdata_get_context(C, &ac) == 0)
1038 return OPERATOR_CANCELLED;
1040 /* get list of all channels that selection may need to be flushed to */
1041 filter= ANIMFILTER_CHANNELS;
1042 ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
1044 /* hide all channels not selected */
1045 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_UNSEL | ANIMFILTER_NODUPLIS);
1046 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1048 for (ale= anim_data.first; ale; ale= ale->next) {
1049 /* clear setting first */
1050 ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_CLEAR);
1052 /* now also flush selection status as appropriate
1053 * NOTE: in some cases, this may result in repeat flushing being performed
1055 ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 0);
1058 BLI_freelistN(&anim_data);
1060 /* make all the selected channels visible */
1061 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
1062 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1064 for (ale= anim_data.first; ale; ale= ale->next) {
1065 /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
1066 // TODO: find out why this is the case, and fix that
1067 if (ale->type == ANIMTYPE_OBJECT)
1070 /* enable the setting */
1071 ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD);
1073 /* now, also flush selection status up/down as appropriate */
1074 ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 1);
1077 BLI_freelistN(&anim_data);
1078 BLI_freelistN(&all_data);
1081 /* send notifier that things have changed */
1082 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1084 return OPERATOR_FINISHED;
1087 void ANIM_OT_channels_visibility_set (wmOperatorType *ot)
1090 ot->name= "Set Visibility";
1091 ot->idname= "ANIM_OT_channels_visibility_set";
1092 ot->description= "Make only the selected animation channels visible in the Graph Editor";
1095 ot->exec= animchannels_visibility_set_exec;
1096 ot->poll= ED_operator_ipo_active;
1099 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1103 /* ******************** Toggle Channel Visibility Operator *********************** */
1104 /* NOTE: this operator is only valid in the Graph Editor channels region */
1106 static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *op)
1109 ListBase anim_data = {NULL, NULL};
1110 ListBase all_data = {NULL, NULL};
1113 short vis= ACHANNEL_SETFLAG_ADD;
1115 /* get editor data */
1116 if (ANIM_animdata_get_context(C, &ac) == 0)
1117 return OPERATOR_CANCELLED;
1119 /* get list of all channels that selection may need to be flushed to */
1120 filter= (ANIMFILTER_CHANNELS | ANIMFILTER_NODUPLIS);
1121 ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
1124 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
1125 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1127 /* See if we should be making showing all selected or hiding */
1128 for (ale= anim_data.first; ale; ale= ale->next) {
1129 /* set the setting in the appropriate way (if available) */
1130 if (ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_VISIBLE)) {
1131 vis= ACHANNEL_SETFLAG_CLEAR;
1136 /* Now set the flags */
1137 for (ale= anim_data.first; ale; ale= ale->next) {
1138 /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
1139 // TODO: find out why this is the case, and fix that
1140 if (ale->type == ANIMTYPE_OBJECT)
1143 /* change the setting */
1144 ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, vis);
1146 /* now, also flush selection status up/down as appropriate */
1147 ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, (vis == ACHANNEL_SETFLAG_ADD));
1151 BLI_freelistN(&anim_data);
1152 BLI_freelistN(&all_data);
1154 /* send notifier that things have changed */
1155 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1157 return OPERATOR_FINISHED;
1160 void ANIM_OT_channels_visibility_toggle (wmOperatorType *ot)
1163 ot->name= "Toggle Visibility";
1164 ot->idname= "ANIM_OT_channels_visibility_toggle";
1165 ot->description= "Toggle visibility in Graph Editor of all selected animation channels";
1168 ot->exec= animchannels_visibility_toggle_exec;
1169 ot->poll= ED_operator_ipo_active;
1172 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1175 /* ********************** Set Flags Operator *********************** */
1177 /* defines for setting animation-channel flags */
1178 EnumPropertyItem prop_animchannel_setflag_types[] = {
1179 {ACHANNEL_SETFLAG_TOGGLE, "TOGGLE", 0, "Toggle", ""},
1180 {ACHANNEL_SETFLAG_CLEAR, "DISABLE", 0, "Disable", ""},
1181 {ACHANNEL_SETFLAG_ADD, "ENABLE", 0, "Enable", ""},
1182 {ACHANNEL_SETFLAG_INVERT, "INVERT", 0, "Invert", ""},
1183 {0, NULL, 0, NULL, NULL}
1186 /* defines for set animation-channel settings */
1187 // TODO: could add some more types, but those are really quite dependent on the mode...
1188 EnumPropertyItem prop_animchannel_settings_types[] = {
1189 {ACHANNEL_SETTING_PROTECT, "PROTECT", 0, "Protect", ""},
1190 {ACHANNEL_SETTING_MUTE, "MUTE", 0, "Mute", ""},
1191 {0, NULL, 0, NULL, NULL}
1195 /* ------------------- */
1197 /* macro to be used in setflag_anim_channels */
1198 #define ASUBCHANNEL_SEL_OK(ale) ( (onlysel == 0) || \
1199 ((ale->id) && (GS(ale->id->name)==ID_OB) && (((Object *)ale->id)->flag & SELECT)) )
1201 /* Set/clear a particular flag (setting) for all selected + visible channels
1202 * setting: the setting to modify
1203 * mode: eAnimChannels_SetFlag
1204 * onlysel: only selected channels get the flag set
1206 // TODO: enable a setting which turns flushing on/off?
1207 static void setflag_anim_channels (bAnimContext *ac, short setting, short mode, short onlysel, short flush)
1209 ListBase anim_data = {NULL, NULL};
1210 ListBase all_data = {NULL, NULL};
1214 /* filter data that we need if flush is on */
1216 /* get list of all channels that selection may need to be flushed to */
1217 filter= ANIMFILTER_CHANNELS;
1218 ANIM_animdata_filter(ac, &all_data, filter, ac->data, ac->datatype);
1221 /* filter data that we're working on */
1222 // XXX: noduplis enabled so that results don't cancel, but will be problematic for some channels where only type differs
1223 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS | ANIMFILTER_NODUPLIS);
1224 if (onlysel) filter |= ANIMFILTER_SEL;
1225 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1227 /* if toggling, check if disable or enable */
1228 if (mode == ACHANNEL_SETFLAG_TOGGLE) {
1229 /* default to turn all on, unless we encounter one that's on... */
1230 mode= ACHANNEL_SETFLAG_ADD;
1232 /* see if we should turn off instead... */
1233 for (ale= anim_data.first; ale; ale= ale->next) {
1234 /* set the setting in the appropriate way (if available) */
1235 if (ANIM_channel_setting_get(ac, ale, setting) > 0) {
1236 mode= ACHANNEL_SETFLAG_CLEAR;
1242 /* apply the setting */
1243 for (ale= anim_data.first; ale; ale= ale->next) {
1244 /* skip channel if setting is not available */
1245 if (ANIM_channel_setting_get(ac, ale, setting) == -1)
1248 /* set the setting in the appropriate way */
1249 ANIM_channel_setting_set(ac, ale, setting, mode);
1251 /* if flush status... */
1253 ANIM_flush_setting_anim_channels(ac, &all_data, ale, setting, mode);
1256 BLI_freelistN(&anim_data);
1257 BLI_freelistN(&all_data);
1260 /* ------------------- */
1262 static int animchannels_setflag_exec(bContext *C, wmOperator *op)
1265 short mode, setting;
1268 /* get editor data */
1269 if (ANIM_animdata_get_context(C, &ac) == 0)
1270 return OPERATOR_CANCELLED;
1272 /* mode (eAnimChannels_SetFlag), setting (eAnimChannel_Settings) */
1273 mode= RNA_enum_get(op->ptr, "mode");
1274 setting= RNA_enum_get(op->ptr, "type");
1276 /* check if setting is flushable */
1277 if (setting == ACHANNEL_SETTING_EXPAND)
1281 * - only selected channels are affected
1283 setflag_anim_channels(&ac, setting, mode, 1, flush);
1285 /* send notifier that things have changed */
1286 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1288 return OPERATOR_FINISHED;
1292 void ANIM_OT_channels_setting_enable (wmOperatorType *ot)
1295 ot->name= "Enable Channel Setting";
1296 ot->idname= "ANIM_OT_channels_setting_enable";
1297 ot->description= "Enable specified setting on all selected animation channels";
1300 ot->invoke= WM_menu_invoke;
1301 ot->exec= animchannels_setflag_exec;
1302 ot->poll= animedit_poll_channels_active;
1305 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1308 /* flag-setting mode */
1309 RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_ADD, "Mode", "");
1310 /* setting to set */
1311 ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
1314 void ANIM_OT_channels_setting_disable (wmOperatorType *ot)
1317 ot->name= "Disable Channel Setting";
1318 ot->idname= "ANIM_OT_channels_setting_disable";
1319 ot->description= "Disable specified setting on all selected animation channels";
1322 ot->invoke= WM_menu_invoke;
1323 ot->exec= animchannels_setflag_exec;
1324 ot->poll= animedit_poll_channels_active;
1327 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1330 /* flag-setting mode */
1331 RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_CLEAR, "Mode", "");
1332 /* setting to set */
1333 ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
1336 void ANIM_OT_channels_setting_invert (wmOperatorType *ot)
1339 ot->name= "Invert Channel Setting";
1340 ot->idname= "ANIM_OT_channels_setting_toggle";
1341 ot->description= "Invert specified setting on all selected animation channels";
1344 ot->invoke= WM_menu_invoke;
1345 ot->exec= animchannels_setflag_exec;
1346 ot->poll= animedit_poll_channels_active;
1349 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1352 /* flag-setting mode */
1353 RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_INVERT, "Mode", "");
1354 /* setting to set */
1355 ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
1358 void ANIM_OT_channels_setting_toggle (wmOperatorType *ot)
1361 ot->name= "Toggle Channel Setting";
1362 ot->idname= "ANIM_OT_channels_setting_toggle";
1363 ot->description= "Toggle specified setting on all selected animation channels";
1366 ot->invoke= WM_menu_invoke;
1367 ot->exec= animchannels_setflag_exec;
1368 ot->poll= animedit_poll_channels_active;
1371 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1374 /* flag-setting mode */
1375 RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", "");
1376 /* setting to set */
1377 ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
1380 void ANIM_OT_channels_editable_toggle (wmOperatorType *ot)
1383 ot->name= "Toggle Channel Editability";
1384 ot->idname= "ANIM_OT_channels_editable_toggle";
1385 ot->description= "Toggle editability of selected channels";
1388 ot->exec= animchannels_setflag_exec;
1389 ot->poll= animedit_poll_channels_active;
1392 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1395 /* flag-setting mode */
1396 RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", "");
1397 /* setting to set */
1398 RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, ACHANNEL_SETTING_PROTECT, "Type", "");
1401 /* ********************** Expand Channels Operator *********************** */
1403 static int animchannels_expand_exec (bContext *C, wmOperator *op)
1408 /* get editor data */
1409 if (ANIM_animdata_get_context(C, &ac) == 0)
1410 return OPERATOR_CANCELLED;
1412 /* only affect selected channels? */
1413 if (RNA_boolean_get(op->ptr, "all"))
1416 /* modify setting */
1417 setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_ADD, onlysel, 0);
1419 /* send notifier that things have changed */
1420 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1422 return OPERATOR_FINISHED;
1425 void ANIM_OT_channels_expand (wmOperatorType *ot)
1428 ot->name= "Expand Channels";
1429 ot->idname= "ANIM_OT_channels_expand";
1430 ot->description= "Expand (i.e. open) all selected expandable animation channels";
1433 ot->exec= animchannels_expand_exec;
1434 ot->poll= animedit_poll_channels_active;
1437 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1440 ot->prop= RNA_def_boolean(ot->srna, "all", 1, "All", "Expand all channels (not just selected ones)");
1443 /* ********************** Collapse Channels Operator *********************** */
1445 static int animchannels_collapse_exec (bContext *C, wmOperator *op)
1450 /* get editor data */
1451 if (ANIM_animdata_get_context(C, &ac) == 0)
1452 return OPERATOR_CANCELLED;
1454 /* only affect selected channels? */
1455 if (RNA_boolean_get(op->ptr, "all"))
1458 /* modify setting */
1459 setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_CLEAR, onlysel, 0);
1461 /* send notifier that things have changed */
1462 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1464 return OPERATOR_FINISHED;
1467 void ANIM_OT_channels_collapse (wmOperatorType *ot)
1470 ot->name= "Collapse Channels";
1471 ot->idname= "ANIM_OT_channels_collapse";
1472 ot->description= "Collapse (i.e. close) all selected expandable animation channels";
1475 ot->exec= animchannels_collapse_exec;
1476 ot->poll= animedit_poll_channels_active;
1479 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1482 ot->prop= RNA_def_boolean(ot->srna, "all", 1, "All", "Collapse all channels (not just selected ones)");
1485 /* ********************** Select All Operator *********************** */
1487 static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
1491 /* get editor data */
1492 if (ANIM_animdata_get_context(C, &ac) == 0)
1493 return OPERATOR_CANCELLED;
1495 /* 'standard' behaviour - check if selected, then apply relevant selection */
1496 if (RNA_boolean_get(op->ptr, "invert"))
1497 ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 0, ACHANNEL_SETFLAG_TOGGLE);
1499 ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_ADD);
1501 /* send notifier that things have changed */
1502 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_SELECTED, NULL);
1504 return OPERATOR_FINISHED;
1507 void ANIM_OT_channels_select_all_toggle (wmOperatorType *ot)
1510 ot->name= "Select All";
1511 ot->idname= "ANIM_OT_channels_select_all_toggle";
1512 ot->description= "Toggle selection of all animation channels";
1515 ot->exec= animchannels_deselectall_exec;
1516 ot->poll= animedit_poll_channels_nla_tweakmode_off;
1519 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1522 ot->prop= RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
1525 /* ******************** Borderselect Operator *********************** */
1527 static void borderselect_anim_channels (bAnimContext *ac, rcti *rect, short selectmode)
1529 ListBase anim_data = {NULL, NULL};
1533 View2D *v2d= &ac->ar->v2d;
1535 float ymin=0, ymax=(float)(-ACHANNEL_HEIGHT);
1537 /* convert border-region to view coordinates */
1538 UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin+2, &rectf.xmin, &rectf.ymin);
1539 UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax-2, &rectf.xmax, &rectf.ymax);
1542 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
1543 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1545 /* loop over data, doing border select */
1546 for (ale= anim_data.first; ale; ale= ale->next) {
1547 ymin= ymax - ACHANNEL_STEP;
1549 /* if channel is within border-select region, alter it */
1550 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
1551 /* set selection flags only */
1552 ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, selectmode);
1554 /* type specific actions */
1555 switch (ale->type) {
1556 case ANIMTYPE_GROUP:
1558 bActionGroup *agrp= (bActionGroup *)ale->data;
1560 /* always clear active flag after doing this */
1561 agrp->flag &= ~AGRP_ACTIVE;
1567 /* set minimum extent to be the maximum of the next channel */
1572 BLI_freelistN(&anim_data);
1575 /* ------------------- */
1577 static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
1584 /* get editor data */
1585 if (ANIM_animdata_get_context(C, &ac) == 0)
1586 return OPERATOR_CANCELLED;
1588 /* get settings from operator */
1589 rect.xmin= RNA_int_get(op->ptr, "xmin");
1590 rect.ymin= RNA_int_get(op->ptr, "ymin");
1591 rect.xmax= RNA_int_get(op->ptr, "xmax");
1592 rect.ymax= RNA_int_get(op->ptr, "ymax");
1594 gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
1595 if (gesture_mode == GESTURE_MODAL_SELECT)
1596 selectmode = ACHANNEL_SETFLAG_ADD;
1598 selectmode = ACHANNEL_SETFLAG_CLEAR;
1600 /* apply borderselect animation channels */
1601 borderselect_anim_channels(&ac, &rect, selectmode);
1603 /* send notifier that things have changed */
1604 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_SELECTED, NULL);
1606 return OPERATOR_FINISHED;
1609 void ANIM_OT_channels_select_border(wmOperatorType *ot)
1612 ot->name= "Border Select";
1613 ot->idname= "ANIM_OT_channels_select_border";
1614 ot->description= "Select all animation channels within the specified region";
1617 ot->invoke= WM_border_select_invoke;
1618 ot->exec= animchannels_borderselect_exec;
1619 ot->modal= WM_border_select_modal;
1621 ot->poll= animedit_poll_channels_nla_tweakmode_off;
1624 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1627 WM_operator_properties_gesture_border(ot, FALSE);
1630 /* ******************** Mouse-Click Operator *********************** */
1631 /* Handle selection changes due to clicking on channels. Settings will get caught by UI code... */
1633 static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, short selectmode)
1635 ListBase anim_data = {NULL, NULL};
1638 int notifierFlags = 0;
1640 /* get the channel that was clicked on */
1641 /* filter channels */
1642 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
1643 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1645 /* get channel from index */
1646 ale= BLI_findlink(&anim_data, channel_index);
1648 /* channel not found */
1650 printf("Error: animation channel (index = %d) not found in mouse_anim_channels() \n", channel_index);
1652 BLI_freelistN(&anim_data);
1656 /* selectmode -1 is a special case for ActionGroups only, which selects all of the channels underneath it only... */
1657 // TODO: should this feature be extended to work with other channel types too?
1658 if ((selectmode == -1) && (ale->type != ANIMTYPE_GROUP)) {
1659 /* normal channels should not behave normally in this case */
1660 BLI_freelistN(&anim_data);
1664 /* action to take depends on what channel we've got */
1665 // WARNING: must keep this in sync with the equivalent function in nla_channels.c
1666 switch (ale->type) {
1667 case ANIMTYPE_SCENE:
1669 Scene *sce= (Scene *)ale->data;
1670 AnimData *adt= sce->adt;
1672 /* set selection status */
1673 if (selectmode == SELECT_INVERT) {
1675 sce->flag ^= SCE_DS_SELECTED;
1676 if (adt) adt->flag ^= ADT_UI_SELECTED;
1679 sce->flag |= SCE_DS_SELECTED;
1680 if (adt) adt->flag |= ADT_UI_SELECTED;
1683 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
1686 case ANIMTYPE_OBJECT:
1688 bDopeSheet *ads= (bDopeSheet *)ac->data;
1689 Scene *sce= (Scene *)ads->source;
1690 Base *base= (Base *)ale->data;
1691 Object *ob= base->object;
1692 AnimData *adt= ob->adt;
1694 /* set selection status */
1695 if (selectmode == SELECT_INVERT) {
1697 base->flag ^= SELECT;
1698 ob->flag= base->flag;
1700 if (adt) adt->flag ^= ADT_UI_SELECTED;
1706 // TODO: should this deselect all other types of channels too?
1707 for (b= sce->base.first; b; b= b->next) {
1709 b->object->flag= b->flag;
1710 if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED|ADT_UI_ACTIVE);
1713 /* select object now */
1714 base->flag |= SELECT;
1716 if (adt) adt->flag |= ADT_UI_SELECTED;
1719 if ((adt) && (adt->flag & ADT_UI_SELECTED))
1720 adt->flag |= ADT_UI_ACTIVE;
1722 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
1726 case ANIMTYPE_FILLACTD: /* Action Expander */
1727 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */
1728 case ANIMTYPE_DSLAM:
1729 case ANIMTYPE_DSCAM:
1730 case ANIMTYPE_DSCUR:
1731 case ANIMTYPE_DSSKEY:
1732 case ANIMTYPE_DSWOR:
1733 case ANIMTYPE_DSPART:
1734 case ANIMTYPE_DSMBALL:
1735 case ANIMTYPE_DSARM:
1736 case ANIMTYPE_DSMESH:
1737 case ANIMTYPE_DSNTREE:
1738 case ANIMTYPE_DSTEX:
1739 case ANIMTYPE_DSLINESTYLE:
1741 /* sanity checking... */
1743 /* select/deselect */
1744 if (selectmode == SELECT_INVERT) {
1745 /* inverse selection status of this AnimData block only */
1746 ale->adt->flag ^= ADT_UI_SELECTED;
1749 /* select AnimData block by itself */
1750 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1751 ale->adt->flag |= ADT_UI_SELECTED;
1755 if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
1756 ale->adt->flag |= ADT_UI_ACTIVE;
1759 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
1763 case ANIMTYPE_GROUP:
1765 bActionGroup *agrp= (bActionGroup *)ale->data;
1767 /* select/deselect group */
1768 if (selectmode == SELECT_INVERT) {
1769 /* inverse selection status of this group only */
1770 agrp->flag ^= AGRP_SELECTED;
1772 else if (selectmode == -1) {
1773 /* select all in group (and deselect everthing else) */
1776 /* deselect all other channels */
1777 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1779 /* only select channels in group and group itself */
1780 for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next)
1781 fcu->flag |= FCURVE_SELECTED;
1782 agrp->flag |= AGRP_SELECTED;
1785 /* select group by itself */
1786 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1787 agrp->flag |= AGRP_SELECTED;
1790 /* if group is selected now, make group the 'active' one in the visible list */
1791 if (agrp->flag & AGRP_SELECTED)
1792 ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
1794 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
1797 case ANIMTYPE_FCURVE:
1799 FCurve *fcu= (FCurve *)ale->data;
1801 /* select/deselect */
1802 if (selectmode == SELECT_INVERT) {
1803 /* inverse selection status of this F-Curve only */
1804 fcu->flag ^= FCURVE_SELECTED;
1807 /* select F-Curve by itself */
1808 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1809 fcu->flag |= FCURVE_SELECTED;
1812 /* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */
1813 if (fcu->flag & FCURVE_SELECTED)
1814 ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
1816 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
1819 case ANIMTYPE_SHAPEKEY:
1821 KeyBlock *kb= (KeyBlock *)ale->data;
1823 /* select/deselect */
1824 if (selectmode == SELECT_INVERT) {
1825 /* inverse selection status of this ShapeKey only */
1826 kb->flag ^= KEYBLOCK_SEL;
1829 /* select ShapeKey by itself */
1830 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1831 kb->flag |= KEYBLOCK_SEL;
1834 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
1837 case ANIMTYPE_GPDATABLOCK:
1839 bGPdata *gpd= (bGPdata *)ale->data;
1842 gpd->flag ^= GP_DATA_EXPAND;
1844 notifierFlags |= (ND_ANIMCHAN|NA_EDITED);
1847 case ANIMTYPE_GPLAYER:
1849 #if 0 // XXX future of this is unclear
1850 bGPdata *gpd= (bGPdata *)ale->owner; // xxx depreceated
1851 bGPDlayer *gpl= (bGPDlayer *)ale->data;
1853 if (x >= (ACHANNEL_NAMEWIDTH-16)) {
1855 gpl->flag ^= GP_LAYER_LOCKED;
1857 else if (x >= (ACHANNEL_NAMEWIDTH-32)) {
1859 gpl->flag ^= GP_LAYER_HIDE;
1862 /* select/deselect */
1863 //if (G.qual & LR_SHIFTKEY) {
1864 //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
1867 //deselect_gpencil_layers(data, 0);
1868 //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
1871 #endif // XXX future of this is unclear
1876 printf("Error: Invalid channel type in mouse_anim_channels() \n");
1880 BLI_freelistN(&anim_data);
1882 /* return notifier flags */
1883 return notifierFlags;
1886 /* ------------------- */
1888 /* handle clicking */
1889 static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event)
1894 int mval[2], channel_index;
1895 int notifierFlags = 0;
1900 /* get editor data */
1901 if (ANIM_animdata_get_context(C, &ac) == 0)
1902 return OPERATOR_CANCELLED;
1904 /* get useful pointers from animation context data */
1908 /* get mouse coordinates (in region coordinates) */
1909 mval[0]= (event->x - ar->winrct.xmin);
1910 mval[1]= (event->y - ar->winrct.ymin);
1912 /* select mode is either replace (deselect all, then add) or add/extend */
1913 if (RNA_boolean_get(op->ptr, "extend"))
1914 selectmode= SELECT_INVERT;
1915 else if (RNA_boolean_get(op->ptr, "children_only"))
1916 selectmode= -1; /* this is a bit of a special case for ActionGroups only... should it be removed or extended to all instead? */
1918 selectmode= SELECT_REPLACE;
1920 /* figure out which channel user clicked in
1921 * Note: although channels technically start at y= ACHANNEL_FIRST, we need to adjust by half a channel's height
1922 * so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
1923 * ACHANNEL_HEIGHT_HALF.
1925 UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
1926 UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
1928 /* handle mouse-click in the relevant channel then */
1929 notifierFlags= mouse_anim_channels(&ac, x, channel_index, selectmode);
1931 /* set notifier that things have changed */
1932 WM_event_add_notifier(C, NC_ANIMATION|notifierFlags, NULL);
1934 return OPERATOR_FINISHED;
1937 void ANIM_OT_channels_click (wmOperatorType *ot)
1940 ot->name= "Mouse Click on Channels";
1941 ot->idname= "ANIM_OT_channels_click";
1942 ot->description= "Handle mouse-clicks over animation channels";
1945 ot->invoke= animchannels_mouseclick_invoke;
1946 ot->poll= animedit_poll_channels_active;
1949 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1952 RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
1953 RNA_def_boolean(ot->srna, "children_only", 0, "Select Children Only", ""); // CTRLKEY|SHIFTKEY
1956 /* ************************************************************************** */
1957 /* Operator Registration */
1959 void ED_operatortypes_animchannels(void)
1961 WM_operatortype_append(ANIM_OT_channels_select_all_toggle);
1962 WM_operatortype_append(ANIM_OT_channels_select_border);
1963 WM_operatortype_append(ANIM_OT_channels_click);
1965 WM_operatortype_append(ANIM_OT_channels_setting_enable);
1966 WM_operatortype_append(ANIM_OT_channels_setting_disable);
1967 WM_operatortype_append(ANIM_OT_channels_setting_invert);
1968 WM_operatortype_append(ANIM_OT_channels_setting_toggle);
1970 WM_operatortype_append(ANIM_OT_channels_delete);
1972 // XXX does this need to be a separate operator?
1973 WM_operatortype_append(ANIM_OT_channels_editable_toggle);
1975 // XXX these need to be updated for new system... todo...
1976 //WM_operatortype_append(ANIM_OT_channels_move_up);
1977 //WM_operatortype_append(ANIM_OT_channels_move_down);
1978 //WM_operatortype_append(ANIM_OT_channels_move_top);
1979 //WM_operatortype_append(ANIM_OT_channels_move_bottom);
1981 WM_operatortype_append(ANIM_OT_channels_expand);
1982 WM_operatortype_append(ANIM_OT_channels_collapse);
1984 WM_operatortype_append(ANIM_OT_channels_visibility_toggle);
1985 WM_operatortype_append(ANIM_OT_channels_visibility_set);
1988 // TODO: check on a poll callback for this, to get hotkeys into menus
1989 void ED_keymap_animchannels(wmKeyConfig *keyconf)
1991 wmKeyMap *keymap = WM_keymap_find(keyconf, "Animation Channels", 0, 0);
1995 // XXX for now, only leftmouse....
1996 WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, 0, 0);
1997 RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
1998 RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_CTRL|KM_SHIFT, 0)->ptr, "children_only", 1);
2001 WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", AKEY, KM_PRESS, 0, 0);
2002 RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
2005 WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", BKEY, KM_PRESS, 0, 0);
2006 WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", EVT_TWEAK_L, KM_ANY, 0, 0);
2009 WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", XKEY, KM_PRESS, 0, 0);
2010 WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", DELKEY, KM_PRESS, 0, 0);
2013 WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_toggle", WKEY, KM_PRESS, KM_SHIFT, 0);
2014 WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_enable", WKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
2015 WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_disable", WKEY, KM_PRESS, KM_ALT, 0);
2017 /* settings - specialised hotkeys */
2018 WM_keymap_add_item(keymap, "ANIM_OT_channels_editable_toggle", TABKEY, KM_PRESS, 0, 0);
2020 /* expand/collapse */
2021 WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, 0, 0);
2022 WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, 0, 0);
2024 RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, KM_CTRL, 0)->ptr, "all", 0);
2025 RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, KM_CTRL, 0)->ptr, "all", 0);
2027 /* rearranging - actions only */
2028 //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_up", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0);
2029 //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_down", PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0);
2030 //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_to_top", PAGEUPKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
2031 //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_to_bottom", PAGEDOWNKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
2033 /* Graph Editor only */
2034 WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_set", VKEY, KM_PRESS, 0, 0);
2035 WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_toggle", VKEY, KM_PRESS, KM_SHIFT, 0);
2038 /* ************************************************************************** */