RNA
[blender.git] / source / blender / editors / animation / anim_channels.c
index 2564068a0c57d0899af19ff046d2dfaeb4d2cdf6..c52ade1bba855db71d14228fbce0fa1575b9414c 100644 (file)
 #include "BLI_arithb.h"
 
 #include "DNA_listBase.h"
+#include "DNA_anim_types.h"
 #include "DNA_action_types.h"
 #include "DNA_armature_types.h"
 #include "DNA_camera_types.h"
 #include "DNA_curve_types.h"
-#include "DNA_ipo_types.h"
 #include "DNA_object_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_scene_types.h"
@@ -58,6 +58,7 @@
 #include "DNA_userdef_types.h"
 #include "DNA_gpencil_types.h"
 #include "DNA_windowmanager_types.h"
+#include "DNA_world_types.h"
 
 #include "RNA_access.h"
 #include "RNA_define.h"
 /* ************************************************************************** */
 /* CHANNELS API */
 
-/* -------------------------- Internal Tools -------------------------------- */
+/* -------------------------- Internal Macros ------------------------------- */
 
+/* set/clear/toggle macro 
+ *     - channel - channel with a 'flag' member that we're setting
+ *     - smode - 0=clear, 1=set, 2=toggle
+ *     - sflag - bitflag to set
+ */
+#define ACHANNEL_SET_FLAG(channel, smode, sflag) \
+       { \
+               if (smode == ACHANNEL_SETFLAG_TOGGLE)   (channel)->flag ^= (sflag); \
+               else if (smode == ACHANNEL_SETFLAG_ADD) (channel)->flag |= (sflag); \
+               else                                                                    (channel)->flag &= ~(sflag); \
+       }
+       
+/* set/clear/toggle macro, where the flag is negative 
+ *     - channel - channel with a 'flag' member that we're setting
+ *     - smode - 0=clear, 1=set, 2=toggle
+ *     - sflag - bitflag to set
+ */
+#define ACHANNEL_SET_FLAG_NEG(channel, smode, sflag) \
+       { \
+               if (smode == ACHANNEL_SETFLAG_TOGGLE)   (channel)->flag ^= (sflag); \
+               else if (smode == ACHANNEL_SETFLAG_ADD) (channel)->flag &= ~(sflag); \
+               else                                                                    (channel)->flag |= (sflag); \
+       }
+
+/* -------------------------- Exposed API ----------------------------------- */
+
+/* Set the given animation-channel as the active one for the active context */
+void ANIM_set_active_channel (void *data, short datatype, int filter, void *channel_data, short channel_type)
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       
+       /* try to build list of filtered items */
+       // XXX we don't need/supply animcontext for now, since in this case, there's nothing really essential there that isn't already covered
+       ANIM_animdata_filter(NULL, &anim_data, filter, data, datatype);
+       if (anim_data.first == NULL)
+               return;
+               
+       /* only clear the 'active' flag for the channels of the same type */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               /* skip if types don't match */
+               if (channel_type != ale->type)
+                       continue;
+               
+               /* flag to set depends on type */
+               switch (ale->type) {
+                       case ANIMTYPE_GROUP:
+                       {
+                               bActionGroup *agrp= (bActionGroup *)ale->data;
+                               
+                               ACHANNEL_SET_FLAG(agrp, ACHANNEL_SETFLAG_CLEAR, AGRP_ACTIVE);
+                       }
+                               break;
+                       case ANIMTYPE_FCURVE:
+                       {
+                               FCurve *fcu= (FCurve *)ale->data;
+                               
+                               ACHANNEL_SET_FLAG(fcu, ACHANNEL_SETFLAG_CLEAR, FCURVE_ACTIVE);
+                       }
+                               break;
+               }
+       }
+       
+       /* set active flag */
+       if (channel_data) {
+               switch (channel_type) {
+                       case ANIMTYPE_GROUP:
+                       {
+                               bActionGroup *agrp= (bActionGroup *)channel_data;
+                               agrp->flag |= AGRP_ACTIVE;
+                       }
+                               break;
+                       case ANIMTYPE_FCURVE:
+                       {
+                               FCurve *fcu= (FCurve *)channel_data;
+                               fcu->flag |= FCURVE_ACTIVE;
+                       }
+                               break;
+               }
+       }
+       
+       /* clean up */
+       BLI_freelistN(&anim_data);
+}
+
+/* Deselect all animation channels 
+ *     - data: pointer to datatype, as contained in bAnimContext
+ *     - datatype: the type of data that 'data' represents (eAnimCont_Types)
+ *     - test: check if deselecting instead of selecting
+ *     - sel: eAnimChannels_SetFlag;
+ */
+void ANIM_deselect_anim_channels (void *data, short datatype, short test, short sel)
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       /* filter data */
+       filter= ANIMFILTER_VISIBLE;
+       ANIM_animdata_filter(NULL, &anim_data, filter, data, datatype);
+       
+       /* See if we should be selecting or deselecting */
+       if (test) {
+               for (ale= anim_data.first; ale; ale= ale->next) {
+                       if (sel == 0) 
+                               break;
+                       
+                       switch (ale->type) {
+                               case ANIMTYPE_SCENE:
+                                       if (ale->flag & SCE_DS_SELECTED)
+                                               sel= ACHANNEL_SETFLAG_CLEAR;
+                                       break;
+                               case ANIMTYPE_OBJECT:
+                                       if (ale->flag & SELECT)
+                                               sel= ACHANNEL_SETFLAG_CLEAR;
+                                       break;
+                               case ANIMTYPE_FILLACTD:
+                                       if (ale->flag & ACT_SELECTED)
+                                               sel= ACHANNEL_SETFLAG_CLEAR;
+                                       break;
+                               case ANIMTYPE_GROUP:
+                                       if (ale->flag & AGRP_SELECTED)
+                                               sel= ACHANNEL_SETFLAG_CLEAR;
+                                       break;
+                               case ANIMTYPE_FCURVE:
+                                       if (ale->flag & FCURVE_SELECTED)
+                                               sel= ACHANNEL_SETFLAG_CLEAR;
+                                       break;
+                       }
+               }
+       }
+               
+       /* Now set the flags */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               switch (ale->type) {
+                       case ANIMTYPE_SCENE:
+                       {
+                               Scene *scene= (Scene *)ale->data;
+                               
+                               ACHANNEL_SET_FLAG(scene, sel, SCE_DS_SELECTED);
+                       }
+                               break;
+                       case ANIMTYPE_OBJECT:
+                       {
+                               Base *base= (Base *)ale->data;
+                               Object *ob= base->object;
+                               
+                               ACHANNEL_SET_FLAG(base, sel, SELECT);
+                               ACHANNEL_SET_FLAG(ob, sel, SELECT);
+                       }
+                               break;
+                       case ANIMTYPE_FILLACTD:
+                       {
+                               bAction *act= (bAction *)ale->data;
+                               
+                               ACHANNEL_SET_FLAG(act, sel, ACT_SELECTED);
+                       }
+                               break;
+                       case ANIMTYPE_GROUP:
+                       {
+                               bActionGroup *agrp= (bActionGroup *)ale->data;
+                               
+                               ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED);
+                               agrp->flag &= ~AGRP_ACTIVE;
+                       }
+                               break;
+                       case ANIMTYPE_FCURVE:
+                       {
+                               FCurve *fcu= (FCurve *)ale->data;
+                               
+                               ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED);
+                               fcu->flag &= ~FCURVE_ACTIVE;
+                       }
+                               break;
+               }
+       }
+       
+       /* Cleanup */
+       BLI_freelistN(&anim_data);
+}
+
+/* ************************************************************************** */
+/* OPERATORS */
+
+/* ****************** Rearrange Channels Operator ******************* */
+/* This operator only works for Action Editor mode for now, as having it elsewhere makes things difficult */
+
+#if 0 // XXX old animation system - needs to be updated for new system...
+
+/* constants for channel rearranging */
+/* WARNING: don't change exising ones without modifying rearrange func accordingly */
+enum {
+       REARRANGE_ACTCHAN_TOP= -2,
+       REARRANGE_ACTCHAN_UP= -1,
+       REARRANGE_ACTCHAN_DOWN= 1,
+       REARRANGE_ACTCHAN_BOTTOM= 2
+};
+
+/* make sure all action-channels belong to a group (and clear action's list) */
+static void split_groups_action_temp (bAction *act, bActionGroup *tgrp)
+{
+       bActionChannel *achan;
+       bActionGroup *agrp;
+       
+       /* Separate action-channels into lists per group */
+       for (agrp= act->groups.first; agrp; agrp= agrp->next) {
+               if (agrp->channels.first) {
+                       achan= agrp->channels.last;
+                       act->chanbase.first= achan->next;
+                       
+                       achan= agrp->channels.first;
+                       achan->prev= NULL;
+                       
+                       achan= agrp->channels.last;
+                       achan->next= NULL;
+               }
+       }
+       
+       /* Initialise memory for temp-group */
+       memset(tgrp, 0, sizeof(bActionGroup));
+       tgrp->flag |= (AGRP_EXPANDED|AGRP_TEMP);
+       strcpy(tgrp->name, "#TempGroup");
+               
+       /* Move any action-channels not already moved, to the temp group */
+       if (act->chanbase.first) {
+               /* start of list */
+               achan= act->chanbase.first;
+               achan->prev= NULL;
+               tgrp->channels.first= achan;
+               act->chanbase.first= NULL;
+               
+               /* end of list */
+               achan= act->chanbase.last;
+               achan->next= NULL;
+               tgrp->channels.last= achan;
+               act->chanbase.last= NULL;
+       }
+       
+       /* Add temp-group to list */
+       BLI_addtail(&act->groups, tgrp);
+}
+
+/* link lists of channels that groups have */
+static void join_groups_action_temp (bAction *act)
+{
+       bActionGroup *agrp;
+       bActionChannel *achan;
+       
+       for (agrp= act->groups.first; agrp; agrp= agrp->next) {
+               ListBase tempGroup;
+               
+               /* add list of channels to action's channels */
+               tempGroup= agrp->channels;
+               addlisttolist(&act->chanbase, &agrp->channels);
+               agrp->channels= tempGroup;
+               
+               /* clear moved flag */
+               agrp->flag &= ~AGRP_MOVED;
+               
+               /* if temp-group... remove from list (but don't free as it's on the stack!) */
+               if (agrp->flag & AGRP_TEMP) {
+                       BLI_remlink(&act->groups, agrp);
+                       break;
+               }
+       }
+       
+       /* clear "moved" flag from all achans */
+       for (achan= act->chanbase.first; achan; achan= achan->next) 
+               achan->flag &= ~ACHAN_MOVED;
+}
+
+
+static short rearrange_actchannel_is_ok (Link *channel, short type)
+{
+       if (type == ANIMTYPE_GROUP) {
+               bActionGroup *agrp= (bActionGroup *)channel;
+               
+               if (SEL_AGRP(agrp) && !(agrp->flag & AGRP_MOVED))
+                       return 1;
+       }
+       else if (type == ANIMTYPE_ACHAN) {
+               bActionChannel *achan= (bActionChannel *)channel;
+               
+               if (VISIBLE_ACHAN(achan) && SEL_ACHAN(achan) && !(achan->flag & ACHAN_MOVED))
+                       return 1;
+       }
+       
+       return 0;
+}
+
+static short rearrange_actchannel_after_ok (Link *channel, short type)
+{
+       if (type == ANIMTYPE_GROUP) {
+               bActionGroup *agrp= (bActionGroup *)channel;
+               
+               if (agrp->flag & AGRP_TEMP)
+                       return 0;
+       }
+       
+       return 1;
+}
+
+
+static short rearrange_actchannel_top (ListBase *list, Link *channel, short type)
+{
+       if (rearrange_actchannel_is_ok(channel, type)) {
+               /* take it out off the chain keep data */
+               BLI_remlink(list, channel);
+               
+               /* make it first element */
+               BLI_insertlinkbefore(list, list->first, channel);
+               
+               return 1;
+       }
+       
+       return 0;
+}
+
+static short rearrange_actchannel_up (ListBase *list, Link *channel, short type)
+{
+       if (rearrange_actchannel_is_ok(channel, type)) {
+               Link *prev= channel->prev;
+               
+               if (prev) {
+                       /* take it out off the chain keep data */
+                       BLI_remlink(list, channel);
+                       
+                       /* push it up */
+                       BLI_insertlinkbefore(list, prev, channel);
+                       
+                       return 1;
+               }
+       }
+       
+       return 0;
+}
+
+static short rearrange_actchannel_down (ListBase *list, Link *channel, short type)
+{
+       if (rearrange_actchannel_is_ok(channel, type)) {
+               Link *next = (channel->next) ? channel->next->next : NULL;
+               
+               if (next) {
+                       /* take it out off the chain keep data */
+                       BLI_remlink(list, channel);
+                       
+                       /* move it down */
+                       BLI_insertlinkbefore(list, next, channel);
+                       
+                       return 1;
+               }
+               else if (rearrange_actchannel_after_ok(list->last, type)) {
+                       /* take it out off the chain keep data */
+                       BLI_remlink(list, channel);
+                       
+                       /* add at end */
+                       BLI_addtail(list, channel);
+                       
+                       return 1;
+               }
+               else {
+                       /* take it out off the chain keep data */
+                       BLI_remlink(list, channel);
+                       
+                       /* add just before end */
+                       BLI_insertlinkbefore(list, list->last, channel);
+                       
+                       return 1;
+               }
+       }
+       
+       return 0;
+}
+
+static short rearrange_actchannel_bottom (ListBase *list, Link *channel, short type)
+{
+       if (rearrange_actchannel_is_ok(channel, type)) {
+               if (rearrange_actchannel_after_ok(list->last, type)) {
+                       /* take it out off the chain keep data */
+                       BLI_remlink(list, channel);
+                       
+                       /* add at end */
+                       BLI_addtail(list, channel);
+                       
+                       return 1;
+               }
+       }
+       
+       return 0;
+}
+
+
+/* Change the order of action-channels 
+ *     mode: REARRANGE_ACTCHAN_*  
+ */
+static void rearrange_action_channels (bAnimContext *ac, short mode)
+{
+       bAction *act;
+       bActionChannel *achan, *chan;
+       bActionGroup *agrp, *grp;
+       bActionGroup tgrp;
+       
+       short (*rearrange_func)(ListBase *, Link *, short);
+       short do_channels = 1;
+       
+       /* Get the active action, exit if none are selected */
+       act= (bAction *)ac->data;
+       
+       /* exit if invalid mode */
+       switch (mode) {
+               case REARRANGE_ACTCHAN_TOP:
+                       rearrange_func= rearrange_actchannel_top;
+                       break;
+               case REARRANGE_ACTCHAN_UP:
+                       rearrange_func= rearrange_actchannel_up;
+                       break;
+               case REARRANGE_ACTCHAN_DOWN:
+                       rearrange_func= rearrange_actchannel_down;
+                       break;
+               case REARRANGE_ACTCHAN_BOTTOM:
+                       rearrange_func= rearrange_actchannel_bottom;
+                       break;
+               default:
+                       return;
+       }
+       
+       /* make sure we're only operating with groups */
+       split_groups_action_temp(act, &tgrp);
+       
+       /* rearrange groups first (and then, only consider channels if the groups weren't moved) */
+       #define GET_FIRST(list) ((mode > 0) ? (list.first) : (list.last))
+       #define GET_NEXT(item) ((mode > 0) ? (item->next) : (item->prev))
+       
+       for (agrp= GET_FIRST(act->groups); agrp; agrp= grp) {
+               /* Get next group to consider */
+               grp= GET_NEXT(agrp);
+               
+               /* try to do group first */
+               if (rearrange_func(&act->groups, (Link *)agrp, ANIMTYPE_GROUP)) {
+                       do_channels= 0;
+                       agrp->flag |= AGRP_MOVED;
+               }
+       }
+       
+       if (do_channels) {
+               for (agrp= GET_FIRST(act->groups); agrp; agrp= grp) {
+                       /* Get next group to consider */
+                       grp= GET_NEXT(agrp);
+                       
+                       /* only consider action-channels if they're visible (group expanded) */
+                       if (EXPANDED_AGRP(agrp)) {
+                               for (achan= GET_FIRST(agrp->channels); achan; achan= chan) {
+                                       /* Get next channel to consider */
+                                       chan= GET_NEXT(achan);
+                                       
+                                       /* Try to do channel */
+                                       if (rearrange_func(&agrp->channels, (Link *)achan, ANIMTYPE_ACHAN))
+                                               achan->flag |= ACHAN_MOVED;
+                               }
+                       }
+               }
+       }
+       #undef GET_FIRST
+       #undef GET_NEXT
+       
+       /* assemble lists into one list (and clear moved tags) */
+       join_groups_action_temp(act);
+}
+
+/* ------------------- */
+
+static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       short mode;
+       
+       /* get editor data - only for Action Editor (for now) */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+       if (ac.datatype != ANIMCONT_ACTION)
+               return OPERATOR_PASS_THROUGH;
+               
+       /* get mode, then rearrange channels */
+       mode= RNA_enum_get(op->ptr, "direction");
+       rearrange_action_channels(&ac, mode);
+       
+       /* set notifier tha things have changed */
+       ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
+       
+       return OPERATOR_FINISHED;
+}
+
+void ANIM_OT_channels_move_up (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Move Channel(s) Up";
+       ot->idname= "ANIM_OT_channels_move_up";
+       
+       /* api callbacks */
+       ot->exec= animchannels_rearrange_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+       RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_UP, "Direction", "");
+}
+
+void ANIM_OT_channels_move_down (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Move Channel(s) Down";
+       ot->idname= "ANIM_OT_channels_move_down";
+       
+       /* api callbacks */
+       ot->exec= animchannels_rearrange_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+       RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_DOWN, "Direction", "");
+}
+
+void ANIM_OT_channels_move_top (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Move Channel(s) to Top";
+       ot->idname= "ANIM_OT_channels_move_to_top";
+       
+       /* api callbacks */
+       ot->exec= animchannels_rearrange_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+       RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_TOP, "Direction", "");
+}
+
+void ANIM_OT_channels_move_bottom (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Move Channel(s) to Bottom";
+       ot->idname= "ANIM_OT_channels_move_to_bottom";
+       
+       /* api callbacks */
+       ot->exec= animchannels_rearrange_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+       RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_BOTTOM, "Direction", "");
+}
+
+#endif // XXX old animation system - needs to be updated for new system...
+
+
+/* ******************** Toggle Channel Visibility Operator *********************** */
+
+static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       short vis= ACHANNEL_SETFLAG_ADD;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+               
+       /* filter data */
+       filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
+       ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+       
+       /* See if we should be making showing all selected or hiding */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               if (vis == ACHANNEL_SETFLAG_CLEAR) 
+                       break;
+               
+               if (ale->flag & FCURVE_VISIBLE)
+                       vis= ACHANNEL_SETFLAG_CLEAR;
+       }
+               
+       /* Now set the flags */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               FCurve *fcu= (FCurve *)ale->data;
+               ACHANNEL_SET_FLAG(fcu, vis, FCURVE_VISIBLE);
+       }
+       
+       /* cleanup */
+       BLI_freelistN(&anim_data);
+       
+       /* set notifier tha things have changed */
+       ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
+       
+       return OPERATOR_FINISHED;
+}
+void ANIM_OT_channels_visibility_toggle (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Toggle Visibility";
+       ot->idname= "ANIM_OT_channels_visibility_toggle";
+       
+       /* api callbacks */
+       ot->exec= animchannels_visibility_toggle_exec;
+       ot->poll= ED_operator_ipo_active;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/* ********************** Set Flags Operator *********************** */
+
+enum {
+//     ACHANNEL_SETTING_SELECT = 0,
+       ACHANNEL_SETTING_PROTECT = 1,
+       ACHANNEL_SETTING_MUTE,
+       ACHANNEL_SETTING_VISIBLE,
+       ACHANNEL_SETTING_EXPAND,
+} eAnimChannel_Settings;
+
+/* defines for setting animation-channel flags */
+EnumPropertyItem prop_animchannel_setflag_types[] = {
+       {ACHANNEL_SETFLAG_CLEAR, "DISABLE", 0, "Disable", ""},
+       {ACHANNEL_SETFLAG_ADD, "ENABLE", 0, "Enable", ""},
+       {ACHANNEL_SETFLAG_TOGGLE, "TOGGLE", 0, "Toggle", ""},
+       {0, NULL, 0, NULL, NULL}
+};
+
+/* defines for set animation-channel settings */
+EnumPropertyItem prop_animchannel_settings_types[] = {
+       {ACHANNEL_SETTING_PROTECT, "PROTECT", 0, "Protect", ""},
+       {ACHANNEL_SETTING_MUTE, "MUTE", 0, "Mute", ""},
+       {0, NULL, 0, NULL, NULL}
+};
+
+
+/* ------------------- */
+
+/* macro to be used in setflag_anim_channels */
+#define ASUBCHANNEL_SEL_OK(ale) ( (onlysel == 0) || \
+               ((ale->id) && (GS(ale->id->name)==ID_OB) && (((Object *)ale->id)->flag & SELECT)) ) 
+
+/* Set/clear a particular flag (setting) for all selected + visible channels 
+ *     setting: the setting to modify
+ *     mode: eAnimChannels_SetFlag
+ *     onlysel: only selected channels get the flag set
+ */
+static void setflag_anim_channels (bAnimContext *ac, short setting, short mode, short onlysel)
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       /* filter data */
+       filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
+       if (onlysel) filter |= ANIMFILTER_SEL;
+       ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+       
+       /* affect selected channels */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               switch (ale->type) {
+                       case ANIMTYPE_OBJECT:
+                       {
+                               Base *base= (Base *)ale->data;
+                               Object *ob= base->object;
+                               
+                               if (setting == ACHANNEL_SETTING_EXPAND) {
+                                       // XXX - settings should really be moved out of ob->nlaflag
+                                       if (mode == ACHANNEL_SETFLAG_TOGGLE)    ob->nlaflag ^= OB_ADS_COLLAPSED;
+                                       else if (mode == ACHANNEL_SETFLAG_ADD)  ob->nlaflag &= ~OB_ADS_COLLAPSED;
+                                       else                                                                    ob->nlaflag |= OB_ADS_COLLAPSED;
+                               }
+                       }
+                               break;
+                       
+                       case ANIMTYPE_FILLACTD:
+                       {
+                               bAction *act= (bAction *)ale->data;
+                               
+                               if (ASUBCHANNEL_SEL_OK(ale)) {
+                                       if (setting == ACHANNEL_SETTING_EXPAND) {
+                                               ACHANNEL_SET_FLAG_NEG(act, mode, ACT_COLLAPSED);
+                                       }
+                               }
+                       }
+                               break;
+                       case ANIMTYPE_FILLDRIVERS:
+                       {
+                               AnimData *adt= (AnimData *)ale->data;
+                               
+                               if (ASUBCHANNEL_SEL_OK(ale)) {
+                                       if (setting == ACHANNEL_SETTING_EXPAND) {
+                                               ACHANNEL_SET_FLAG_NEG(adt, mode, ADT_DRIVERS_COLLAPSED);
+                                       }
+                               }
+                       }
+                               break;
+                       case ANIMTYPE_FILLMATD:
+                       {
+                               Object *ob= (Object *)ale->data;
+                               
+                               // XXX - settings should really be moved out of ob->nlaflag
+                               if ((onlysel == 0) || (ob->flag & SELECT)) {
+                                       if (setting == ACHANNEL_SETTING_EXPAND) {
+                                               if (mode == ACHANNEL_SETFLAG_TOGGLE)    ob->nlaflag ^= OB_ADS_SHOWMATS;
+                                               else if (mode == ACHANNEL_SETFLAG_ADD)  ob->nlaflag |= OB_ADS_SHOWMATS;
+                                               else                                                                    ob->nlaflag &= ~OB_ADS_SHOWMATS;
+                                       }
+                               }
+                       }
+                               break;
+                                       
+                       case ANIMTYPE_DSMAT:
+                       {
+                               Material *ma= (Material *)ale->data;
+                               
+                               if (ASUBCHANNEL_SEL_OK(ale)) {
+                                       if (setting == ACHANNEL_SETTING_EXPAND) {
+                                               ACHANNEL_SET_FLAG(ma, mode, MA_DS_EXPAND);
+                                       }
+                               }
+                       }
+                               break;
+                       case ANIMTYPE_DSLAM:
+                       {
+                               Lamp *la= (Lamp *)ale->data;
+                               
+                               if (ASUBCHANNEL_SEL_OK(ale)) {
+                                       if (setting == ACHANNEL_SETTING_EXPAND) {
+                                               ACHANNEL_SET_FLAG(la, mode, LA_DS_EXPAND);
+                                       }
+                               }
+                       }
+                               break;
+                       case ANIMTYPE_DSCAM:
+                       {
+                               Camera *ca= (Camera *)ale->data;
+                               
+                               if (ASUBCHANNEL_SEL_OK(ale)) {
+                                       if (setting == ACHANNEL_SETTING_EXPAND) {
+                                               ACHANNEL_SET_FLAG(ca, mode, CAM_DS_EXPAND);
+                                       }
+                               }
+                       }
+                               break;
+                       case ANIMTYPE_DSCUR:
+                       {
+                               Curve *cu= (Curve *)ale->data;
+                               
+                               if (ASUBCHANNEL_SEL_OK(ale)) {
+                                       if (setting == ACHANNEL_SETTING_EXPAND) {
+                                               ACHANNEL_SET_FLAG(cu, mode, CU_DS_EXPAND);
+                                       }
+                               }
+                       }
+                               break;
+                       case ANIMTYPE_DSSKEY:
+                       {
+                               Key *key= (Key *)ale->data;
+                               
+                               if (ASUBCHANNEL_SEL_OK(ale)) {
+                                       if (setting == ACHANNEL_SETTING_EXPAND) {
+                                               ACHANNEL_SET_FLAG(key, mode, KEYBLOCK_DS_EXPAND);
+                                       }
+                               }
+                       }
+                               break;
+                       case ANIMTYPE_DSWOR:
+                       {
+                               World *wo= (World *)ale->data;
+                               
+                               if (ASUBCHANNEL_SEL_OK(ale)) {
+                                       if (setting == ACHANNEL_SETTING_EXPAND) {
+                                               ACHANNEL_SET_FLAG(wo, mode, WO_DS_EXPAND);
+                                       }
+                               }
+                       }
+                               break;
+                               
+                       case ANIMTYPE_GROUP:
+                       {
+                               bActionGroup *agrp= (bActionGroup *)ale->data;
+                               
+                               switch (setting) {
+                                       case ACHANNEL_SETTING_PROTECT:
+                                               ACHANNEL_SET_FLAG(agrp, mode, AGRP_PROTECTED);
+                                               break;
+                                       case ACHANNEL_SETTING_EXPAND:
+                                               ACHANNEL_SET_FLAG(agrp, mode, AGRP_EXPANDED);
+                                               break;
+                               }
+                       }
+                               break;
+                       case ANIMTYPE_FCURVE:
+                       {
+                               FCurve *fcu= (FCurve *)ale->data;
+                               
+                               switch (setting) {
+                                       case ACHANNEL_SETTING_MUTE:
+                                               ACHANNEL_SET_FLAG(fcu, mode, FCURVE_MUTED);
+                                               break;
+                                       case ACHANNEL_SETTING_PROTECT:
+                                               ACHANNEL_SET_FLAG(fcu, mode, FCURVE_PROTECTED);
+                                               break;
+                                       case ACHANNEL_SETTING_VISIBLE:
+                                               ACHANNEL_SET_FLAG(fcu, mode, FCURVE_VISIBLE);
+                                               break;
+                               }
+                       }
+                               break;
+                       case ANIMTYPE_GPLAYER:
+                       {
+                               bGPDlayer *gpl= (bGPDlayer *)ale->data;
+                               
+                               switch (setting) {
+                                       case ACHANNEL_SETTING_MUTE:
+                                               ACHANNEL_SET_FLAG(gpl, mode, GP_LAYER_HIDE);
+                                               break;
+                                       case ACHANNEL_SETTING_PROTECT:
+                                               ACHANNEL_SET_FLAG(gpl, mode, GP_LAYER_LOCKED);
+                                               break;
+                               }
+                       }
+                               break;
+               }
+       }
+       
+       BLI_freelistN(&anim_data);
+}
+
+/* ------------------- */
+
+static int animchannels_setflag_exec(bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       short mode, setting;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+               
+       /* mode (eAnimChannels_SetFlag), setting (eAnimChannel_Settings) */
+       mode= RNA_enum_get(op->ptr, "mode");
+       setting= RNA_enum_get(op->ptr, "type");
+       
+       /* modify setting */
+       setflag_anim_channels(&ac, setting, mode, 1);
+       
+       /* set notifier tha things have changed */
+       ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
+       
+       return OPERATOR_FINISHED;
+}
+
+
+void ANIM_OT_channels_setting_enable (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Enable Channel Setting";
+       ot->idname= "ANIM_OT_channels_setting_enable";
+       
+       /* api callbacks */
+       ot->invoke= WM_menu_invoke;
+       ot->exec= animchannels_setflag_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+               /* flag-setting mode */
+       RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_ADD, "Mode", "");
+               /* setting to set */
+       RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
+}
+
+void ANIM_OT_channels_setting_disable (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Disable Channel Setting";
+       ot->idname= "ANIM_OT_channels_setting_disable";
+       
+       /* api callbacks */
+       ot->invoke= WM_menu_invoke;
+       ot->exec= animchannels_setflag_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+               /* flag-setting mode */
+       RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_CLEAR, "Mode", "");
+               /* setting to set */
+       RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
+}
+
+void ANIM_OT_channels_setting_toggle (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Toggle Channel Setting";
+       ot->idname= "ANIM_OT_channels_setting_toggle";
+       
+       /* api callbacks */
+       ot->invoke= WM_menu_invoke;
+       ot->exec= animchannels_setflag_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+               /* flag-setting mode */
+       RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", "");
+               /* setting to set */
+       RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
+}
+
+// XXX currently, this is a separate operator, but perhaps we could in future specify in keymaps whether to call invoke or exec?
+void ANIM_OT_channels_editable_toggle (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Toggle Channel Editability";
+       ot->idname= "ANIM_OT_channels_editable_toggle";
+       
+       /* api callbacks */
+       ot->exec= animchannels_setflag_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+               /* flag-setting mode */
+       RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", "");
+               /* setting to set */
+       RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, ACHANNEL_SETTING_PROTECT, "Type", "");
+}
+
+/* ********************** Expand Channels Operator *********************** */
+
+static int animchannels_expand_exec (bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       short onlysel= 1;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+               
+       /* only affect selected channels? */
+       if (RNA_boolean_get(op->ptr, "all"))
+               onlysel= 0;
+       
+       /* modify setting */
+       setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_ADD, onlysel);
+       
+       /* set notifier that things have changed */
+       ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
+       
+       return OPERATOR_FINISHED;
+}
+
+void ANIM_OT_channels_expand (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Expand Channels";
+       ot->idname= "ANIM_OT_channels_expand";
+       
+       /* api callbacks */
+       ot->exec= animchannels_expand_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+       RNA_def_boolean(ot->srna, "all", 0, "All", "Expand all channels (not just selected ones)");
+}
 
+/* ********************** Collapse Channels Operator *********************** */
 
-/* -------------------------- Exposed API ----------------------------------- */
+static int animchannels_collapse_exec (bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       short onlysel= 1;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+               
+       /* only affect selected channels? */
+       if (RNA_boolean_get(op->ptr, "all"))
+               onlysel= 0;
+       
+       /* modify setting */
+       setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_CLEAR, onlysel);
+       
+       /* set notifier that things have changed */
+       ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
+       
+       return OPERATOR_FINISHED;
+}
 
-/* ************************************************************************** */
-/* OPERATORS */
+void ANIM_OT_channels_collapse (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Collapse Channels";
+       ot->idname= "ANIM_OT_channels_collapse";
+       
+       /* api callbacks */
+       ot->exec= animchannels_collapse_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+       RNA_def_boolean(ot->srna, "all", 0, "All", "Collapse all channels (not just selected ones)");
+}
 
 /* ********************** Select All Operator *********************** */
 
+static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+               
+       /* 'standard' behaviour - check if selected, then apply relevant selection */
+       if (RNA_boolean_get(op->ptr, "invert"))
+               ANIM_deselect_anim_channels(ac.data, ac.datatype, 0, ACHANNEL_SETFLAG_TOGGLE);
+       else
+               ANIM_deselect_anim_channels(ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_ADD);
+       
+       /* set notifier tha things have changed */
+       ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
+       
+       return OPERATOR_FINISHED;
+}
+void ANIM_OT_channels_select_all_toggle (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select All";
+       ot->idname= "ANIM_OT_channels_select_all_toggle";
+       
+       /* api callbacks */
+       ot->exec= animchannels_deselectall_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+       RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
+}
+
+/* ******************** Borderselect Operator *********************** */
+
+static void borderselect_anim_channels (bAnimContext *ac, rcti *rect, short selectmode)
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       View2D *v2d= &ac->ar->v2d;
+       rctf rectf;
+       float ymin=0, ymax=(float)(-ACHANNEL_HEIGHT);
+       
+       /* convert border-region to view coordinates */
+       UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin+2, &rectf.xmin, &rectf.ymin);
+       UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax-2, &rectf.xmax, &rectf.ymax);
+       
+       /* filter data */
+       filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
+       ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+       
+       /* loop over data, doing border select */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               ymin= ymax - ACHANNEL_STEP;
+               
+               /* if channel is within border-select region, alter it */
+               if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
+                       /* only the following types can be selected */
+                       switch (ale->type) {
+                               case ANIMTYPE_OBJECT: /* object */
+                               {
+                                       Base *base= (Base *)ale->data;
+                                       Object *ob= base->object;
+                                       
+                                       ACHANNEL_SET_FLAG(base, selectmode, SELECT);
+                                       ACHANNEL_SET_FLAG(ob, selectmode, SELECT);
+                               }
+                                       break;
+                               case ANIMTYPE_GROUP: /* action group */
+                               {
+                                       bActionGroup *agrp= (bActionGroup *)ale->data;
+                                       
+                                       ACHANNEL_SET_FLAG(agrp, selectmode, AGRP_SELECTED);
+                                       agrp->flag &= ~AGRP_ACTIVE;
+                               }
+                                       break;
+                               case ANIMTYPE_FCURVE: /* F-Curve channel */
+                               {
+                                       FCurve *fcu = (FCurve *)ale->data;
+                                       
+                                       ACHANNEL_SET_FLAG(fcu, selectmode, FCURVE_SELECTED);
+                               }
+                                       break;
+                               case ANIMTYPE_GPLAYER: /* grease-pencil layer */
+                               {
+                                       bGPDlayer *gpl = (bGPDlayer *)ale->data;
+                                       
+                                       ACHANNEL_SET_FLAG(gpl, selectmode, GP_LAYER_SELECT);
+                               }
+                                       break;
+                       }
+               }
+               
+               /* set minimum extent to be the maximum of the next channel */
+               ymax= ymin;
+       }
+       
+       /* cleanup */
+       BLI_freelistN(&anim_data);
+}
+
+/* ------------------- */
+
+static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       rcti rect;
+       short selectmode=0;
+       int event;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+       
+       /* get settings from operator */
+       rect.xmin= RNA_int_get(op->ptr, "xmin");
+       rect.ymin= RNA_int_get(op->ptr, "ymin");
+       rect.xmax= RNA_int_get(op->ptr, "xmax");
+       rect.ymax= RNA_int_get(op->ptr, "ymax");
+               
+       event= RNA_int_get(op->ptr, "event_type");
+       if (event == LEFTMOUSE) // FIXME... hardcoded
+               selectmode = ACHANNEL_SETFLAG_ADD;
+       else
+               selectmode = ACHANNEL_SETFLAG_CLEAR;
+       
+       /* apply borderselect animation channels */
+       borderselect_anim_channels(&ac, &rect, selectmode);
+       
+       return OPERATOR_FINISHED;
+} 
 
+void ANIM_OT_channels_select_border(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Border Select";
+       ot->idname= "ANIM_OT_channels_select_border";
+       
+       /* api callbacks */
+       ot->invoke= WM_border_select_invoke;
+       ot->exec= animchannels_borderselect_exec;
+       ot->modal= WM_border_select_modal;
+       
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* rna */
+       RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
+       RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
+       RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
+       RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
+       RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
+}
 
 /* ******************** Mouse-Click Operator *********************** */
 /* Depending on the channel that was clicked on, the mouse click will activate whichever
@@ -114,302 +1299,266 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s
        
        /* get the channel that was clicked on */
                /* filter channels */
-       filter= (ANIMFILTER_FORDRAWING | ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
-       filter= ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
+       filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
+       filter= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
        
                /* get channel from index */
        ale= BLI_findlink(&anim_data, channel_index);
        if (ale == NULL) {
                /* channel not found */
-               printf("Error: animation channel not found in mouse_anim_channels() \n");
-                       // XXX remove me..
-               printf("\t channel index = %d, channels = %d\n", channel_index, filter);
+               printf("Error: animation channel (index = %d) not found in mouse_anim_channels() \n", channel_index);
                
                BLI_freelistN(&anim_data);
                return;
        }
        
+       /* selectmode -1 is a special case for ActionGroups only, which selects all of the channels underneath it only... */
+       // TODO: should this feature be extended to work with other channel types too?
+       if ((selectmode == -1) && (ale->type != ANIMTYPE_GROUP)) {
+               /* normal channels should not behave normally in this case */
+               BLI_freelistN(&anim_data);
+               return;
+       }
+       
        /* action to take depends on what channel we've got */
        switch (ale->type) {
+               case ANIMTYPE_SCENE:
+               {
+                       Scene *sce= (Scene *)ale->data;
+                       
+                       if (x < 16) {
+                               /* toggle expand */
+                               sce->flag ^= SCE_DS_COLLAPSED;
+                       }
+                       else {
+                               /* set selection status */
+                               if (selectmode == SELECT_INVERT) {
+                                       /* swap select */
+                                       sce->flag ^= SCE_DS_SELECTED;
+                               }
+                               else {
+                                       sce->flag |= SCE_DS_SELECTED;
+                               }
+                       }
+               }
+                       break;
                case ANIMTYPE_OBJECT:
-                       {
-                               bDopeSheet *ads= (bDopeSheet *)ac->data;
-                               Scene *sce= (Scene *)ads->source;
-                               Base *base= (Base *)ale->data;
-                               Object *ob= base->object;
-                               
-                               if (x < 16) {
-                                       /* toggle expand */
-                                       ob->nlaflag ^= OB_ADS_COLLAPSED;
+               {
+                       bDopeSheet *ads= (bDopeSheet *)ac->data;
+                       Scene *sce= (Scene *)ads->source;
+                       Base *base= (Base *)ale->data;
+                       Object *ob= base->object;
+                       
+                       if (x < 16) {
+                               /* toggle expand */
+                               ob->nlaflag ^= OB_ADS_COLLAPSED; // XXX 
+                       }
+                       else {
+                               /* set selection status */
+                               if (selectmode == SELECT_INVERT) {
+                                       /* swap select */
+                                       base->flag ^= SELECT;
+                                       ob->flag= base->flag;
                                }
                                else {
-                                       /* set selection status */
-                                       // FIXME: this needs to use the new stuff...
-                                       if (selectmode == SELECT_INVERT) {
-                                               /* swap select */
-                                               base->flag ^= SELECT;
-                                               ob->flag= base->flag;
-                                       }
-                                       else {
-                                               Base *b;
-                                               
-                                               /* deleselect all */
-                                               for (b= sce->base.first; b; b= b->next) {
-                                                       b->flag &= ~SELECT;
-                                                       b->object->flag= b->flag;
-                                               }
-                                               
-                                               /* select object now */
-                                               base->flag |= SELECT;
-                                               ob->flag |= SELECT;
+                                       Base *b;
+                                       
+                                       /* deleselect all */
+                                       for (b= sce->base.first; b; b= b->next) {
+                                               b->flag &= ~SELECT;
+                                               b->object->flag= b->flag;
                                        }
                                        
-                                       //set_active_base(base);        /* editview.c */
+                                       /* select object now */
+                                       base->flag |= SELECT;
+                                       ob->flag |= SELECT;
                                }
+                               
+                               /* xxx should be ED_base_object_activate(), but we need context pointer for that... */
+                               //set_active_base(base);
                        }
-                               break;
-               case ANIMTYPE_FILLIPOD:
-                       {
-                               Object *ob= (Object *)ale->data;
-                               ob->nlaflag ^= OB_ADS_SHOWIPO;
-                       }
-                               break;
+               }
+                       break;
                case ANIMTYPE_FILLACTD:
-                       {
-                               bAction *act= (bAction *)ale->data;
-                               act->flag ^= ACTC_EXPANDED;
-                       }
-                               break;
-               case ANIMTYPE_FILLCOND:
-                       {
-                               Object *ob= (Object *)ale->data;
-                               ob->nlaflag ^= OB_ADS_SHOWCONS;
-                       }
-                               break;
+               {
+                       bAction *act= (bAction *)ale->data;
+                       act->flag ^= ACT_COLLAPSED;
+               }
+                       break;
+               case ANIMTYPE_FILLDRIVERS:
+               {
+                       AnimData *adt= (AnimData* )ale->data;
+                       adt->flag ^= ADT_DRIVERS_COLLAPSED;
+               }
+                       break;
                case ANIMTYPE_FILLMATD:
-                       {
-                               Object *ob= (Object *)ale->data;
-                               ob->nlaflag ^= OB_ADS_SHOWMATS;
-                       }
-                               break;
+               {
+                       Object *ob= (Object *)ale->data;
+                       ob->nlaflag ^= OB_ADS_SHOWMATS; // XXX 
+               }
+                       break;
                                
                case ANIMTYPE_DSMAT:
-                       {
-                               Material *ma= (Material *)ale->data;
-                               ma->flag ^= MA_DS_EXPAND;
-                       }
-                               break;
+               {
+                       Material *ma= (Material *)ale->data;
+                       ma->flag ^= MA_DS_EXPAND;
+               }
+                       break;
                case ANIMTYPE_DSLAM:
-                       {
-                               Lamp *la= (Lamp *)ale->data;
-                               la->flag ^= LA_DS_EXPAND;
-                       }
-                               break;
+               {
+                       Lamp *la= (Lamp *)ale->data;
+                       la->flag ^= LA_DS_EXPAND;
+               }
+                       break;
                case ANIMTYPE_DSCAM:
-                       {
-                               Camera *ca= (Camera *)ale->data;
-                               ca->flag ^= CAM_DS_EXPAND;
-                       }
-                               break;
+               {
+                       Camera *ca= (Camera *)ale->data;
+                       ca->flag ^= CAM_DS_EXPAND;
+               }
+                       break;
                case ANIMTYPE_DSCUR:
-                       {
-                               Curve *cu= (Curve *)ale->data;
-                               cu->flag ^= CU_DS_EXPAND;
-                       }
-                               break;
+               {
+                       Curve *cu= (Curve *)ale->data;
+                       cu->flag ^= CU_DS_EXPAND;
+               }
+                       break;
                case ANIMTYPE_DSSKEY:
-                       {
-                               Key *key= (Key *)ale->data;
-                               key->flag ^= KEYBLOCK_DS_EXPAND;
-                       }
-                               break;
+               {
+                       Key *key= (Key *)ale->data;
+                       key->flag ^= KEYBLOCK_DS_EXPAND;
+               }
+                       break;
+               case ANIMTYPE_DSWOR:
+               {
+                       World *wo= (World *)ale->data;
+                       wo->flag ^= WO_DS_EXPAND;
+               }
+                       break;
                        
                case ANIMTYPE_GROUP: 
-                       {
-                               bActionGroup *agrp= (bActionGroup *)ale->data;
-                               short offset= (ac->datatype == ANIMCONT_DOPESHEET)? 21 : 0;
-                               
-                               if ((x < (offset+17)) && (agrp->channels.first)) {
-                                       /* toggle expand */
-                                       agrp->flag ^= AGRP_EXPANDED;
-                               }
-                               else if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
-                                       /* toggle protection/locking */
-                                       agrp->flag ^= AGRP_PROTECTED;
-                               }
-                               else {
-                                       /* select/deselect group */
-                                       if (selectmode == SELECT_INVERT) {
-                                               /* inverse selection status of group */
-                                               //select_action_group(act, agrp, SELECT_INVERT);
-                                       }
-                                       else if (/*G.qual == (LR_CTRLKEY|LR_SHIFTKEY)*/0) {
-                                               // FIXME: need a special case for this!
-                                               /* select all in group (and deselect everthing else) */ 
-                                               //select_action_group_channels(act, agrp);
-                                               //select_action_group(act, agrp, SELECT_ADD);
-                                       }
-                                       else {
-                                               /* select group by itself */
-                                               //deselect_actionchannels(act, ANIMCONT_ACTION, 0);
-                                               //select_action_group(act, agrp, SELECT_ADD);
-                                       }
-                                       
-                                       // XXX
-                                       agrp->flag ^= AGRP_SELECTED;
-                               }
+               {
+                       bActionGroup *agrp= (bActionGroup *)ale->data;
+                       short offset= (ELEM3(ac->datatype, ANIMCONT_DOPESHEET, ANIMCONT_FCURVES, ANIMCONT_DRIVERS))? 18 : 0;
+                       
+                       if ((x < (offset+17)) && (agrp->channels.first)) {
+                               /* toggle expand */
+                               agrp->flag ^= AGRP_EXPANDED;
                        }
-                       break;
-               case ANIMTYPE_ACHAN:
-                       {
-                               bActionChannel *achan= (bActionChannel *)ale->data;
-                               short offset= (ac->datatype == ANIMCONT_DOPESHEET)? 21 : 0;
-                               
-                               if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
-                                       /* toggle protect */
-                                       achan->flag ^= ACHAN_PROTECTED;
-                               }
-                               else if ((x >= (ACHANNEL_NAMEWIDTH-2*ACHANNEL_BUTTON_WIDTH)) && (achan->ipo)) {
-                                       /* toggle mute */
-                                       achan->ipo->muteipo = (achan->ipo->muteipo)? 0: 1;
+                       else if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
+                               /* toggle protection/locking */
+                               agrp->flag ^= AGRP_PROTECTED;
+                       }
+                       else {
+                               /* select/deselect group */
+                               if (selectmode == SELECT_INVERT) {
+                                       /* inverse selection status of this group only */
+                                       agrp->flag ^= AGRP_SELECTED;
                                }
-                               else if (x <= (offset+17)) {
-                                       /* toggle expand */
-                                       achan->flag ^= ACHAN_EXPANDED;
-                               }                               
-                               else {
-                                       /* select/deselect achan */             
-                                       if (selectmode == SELECT_INVERT) {
-                                               //select_channel(act, achan, SELECT_INVERT);
-                                       }
-                                       else {
-                                               //deselect_actionchannels(act, ACTCONT_ACTION, 0);
-                                               //select_channel(act, achan, SELECT_ADD);
-                                       }
+                               else if (selectmode == -1) {
+                                       /* select all in group (and deselect everthing else) */ 
+                                       FCurve *fcu;
                                        
-                                       /* messy... set active bone */
-                                       //select_poseelement_by_name(achan->name, 2);
+                                       /* deselect all other channels */
+                                       ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
                                        
-                                       // XXX for now only
-                                       achan->flag ^= ACHAN_SELECTED;
+                                       /* only select channels in group and group itself */
+                                       for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next)
+                                               fcu->flag |= FCURVE_SELECTED;
+                                       agrp->flag |= AGRP_SELECTED;                                    
+                               }
+                               else {
+                                       /* select group by itself */
+                                       ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+                                       agrp->flag |= AGRP_SELECTED;
                                }
-                       }
-                               break;
-               case ANIMTYPE_FILLIPO:
-                       {
-                               bActionChannel *achan= (bActionChannel *)ale->data;
-                               
-                               achan->flag ^= ACHAN_SHOWIPO;
                                
-                               if ((x > 24) && (achan->flag & ACHAN_SHOWIPO)) {
-                                       /* select+make active achan */          
-                                       //deselect_actionchannels(act, ACTCONT_ACTION, 0);
-                                       //select_channel(act, achan, SELECT_ADD);
-                                       
-                                       /* messy... set active bone */
-                                       //select_poseelement_by_name(achan->name, 2);
-                                       
-                                       // XXX for now only
-                                       achan->flag ^= ACHAN_SELECTED;
-                               }       
+                               /* if group is selected now, make group the 'active' one in the visible list */
+                               if (agrp->flag & AGRP_SELECTED)
+                                       ANIM_set_active_channel(ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
                        }
+               }
                        break;
-               case ANIMTYPE_FILLCON:
-                       {
-                               bActionChannel *achan= (bActionChannel *)ale->data;
-                               
-                               achan->flag ^= ACHAN_SHOWCONS;
-                               
-                               if ((x > 24) && (achan->flag & ACHAN_SHOWCONS)) {
-                                       /* select+make active achan */  
-                                       //deselect_actionchannels(act, ACTCONT_ACTION, 0);
-                                       //select_channel(act, achan, SELECT_ADD);
-                                       
-                                       /* messy... set active bone */
-                                       //select_poseelement_by_name(achan->name, 2);
-                                       
-                                       // XXX for now only
-                                       achan->flag ^= ACHAN_SELECTED;
-                               }       
+               case ANIMTYPE_FCURVE: 
+               {
+                       FCurve *fcu= (FCurve *)ale->data;
+                       short offset;
+                       
+                       if (ac->datatype != ANIMCONT_ACTION) {
+                               /* for now, special case for materials */
+                               if (ale->ownertype == ANIMTYPE_DSMAT)
+                                       offset= 21;
+                               else
+                                       offset= 18;
                        }
-                       break;
-               case ANIMTYPE_ICU: 
-                       {
-                               IpoCurve *icu= (IpoCurve *)ale->data;
-                               
-                               if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
-                                       /* toggle protection */
-                                       icu->flag ^= IPO_PROTECT;
-                               }
-                               else if (x >= (ACHANNEL_NAMEWIDTH-2*ACHANNEL_BUTTON_WIDTH)) {
-                                       /* toggle mute */
-                                       icu->flag ^= IPO_MUTE;
-                               }
-                               else {
-                                       /* select/deselect */
-                                       //select_icu_channel(act, icu, SELECT_INVERT);
-                                       
-                                       // XXX for now only
-                                       icu->flag ^= IPO_SELECT;
-                               }
+                       else
+                               offset = 0;
+                       
+                       if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
+                               /* toggle protection (only if there's a toggle there) */
+                               if (fcu->bezt)
+                                       fcu->flag ^= FCURVE_PROTECTED;
                        }
-                       break;
-               case ANIMTYPE_CONCHAN:
-                       {
-                               bConstraintChannel *conchan= (bConstraintChannel *)ale->data;
-                               
-                               if (x >= (ACHANNEL_NAMEWIDTH-16)) {
-                                       /* toggle protection */
-                                       conchan->flag ^= CONSTRAINT_CHANNEL_PROTECTED;
-                               }
-                               else if ((x >= (ACHANNEL_NAMEWIDTH-32)) && (conchan->ipo)) {
-                                       /* toggle mute */
-                                       conchan->ipo->muteipo = (conchan->ipo->muteipo)? 0: 1;
+                       else if (x >= (ACHANNEL_NAMEWIDTH-2*ACHANNEL_BUTTON_WIDTH)) {
+                               /* toggle mute */
+                               fcu->flag ^= FCURVE_MUTED;
+                       }
+                       else if ((x < (offset+17)) && (ac->spacetype==SPACE_IPO)) {
+                               /* toggle visibility */
+                               fcu->flag ^= FCURVE_VISIBLE;
+                       }
+                       else {
+                               /* select/deselect */
+                               if (selectmode == SELECT_INVERT) {
+                                       /* inverse selection status of this F-Curve only */
+                                       fcu->flag ^= FCURVE_SELECTED;
                                }
                                else {
-                                       /* select/deselect */
-                                       //select_constraint_channel(act, conchan, SELECT_INVERT);
-                                       
-                                       // XXX for now only
-                                       conchan->flag ^= CONSTRAINT_CHANNEL_SELECT;
+                                       /* select F-Curve by itself */
+                                       ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+                                       fcu->flag |= FCURVE_SELECTED;
                                }
-                       }
-                               break;
-               case ANIMTYPE_GPDATABLOCK:
-                       {
-                               bGPdata *gpd= (bGPdata *)ale->data;
                                
-                               /* toggle expand */
-                               gpd->flag ^= GP_DATA_EXPAND;
+                               /* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */
+                               if (fcu->flag & FCURVE_SELECTED)
+                                       ANIM_set_active_channel(ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
                        }
-                               break;
+               }
+                       break;
+               case ANIMTYPE_GPDATABLOCK:
+               {
+                       bGPdata *gpd= (bGPdata *)ale->data;
+                       
+                       /* toggle expand */
+                       gpd->flag ^= GP_DATA_EXPAND;
+               }
+                       break;
                case ANIMTYPE_GPLAYER:
-                       {
+               {
 #if 0 // XXX future of this is unclear
-                               bGPdata *gpd= (bGPdata *)ale->owner;
-                               bGPDlayer *gpl= (bGPDlayer *)ale->data;
-                               
-                               if (x >= (ACHANNEL_NAMEWIDTH-16)) {
-                                       /* toggle lock */
-                                       gpl->flag ^= GP_LAYER_LOCKED;
-                               }
-                               else if (x >= (ACHANNEL_NAMEWIDTH-32)) {
-                                       /* toggle hide */
-                                       gpl->flag ^= GP_LAYER_HIDE;
-                               }
-                               else {
-                                       /* select/deselect */
-                                       //if (G.qual & LR_SHIFTKEY) {
-                                               //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
-                                       //}
-                                       //else {
-                                               //deselect_gpencil_layers(data, 0);
-                                               //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
-                                       //}
-                               }
-#endif // XXX future of this is unclear
+                       bGPdata *gpd= (bGPdata *)ale->owner;
+                       bGPDlayer *gpl= (bGPDlayer *)ale->data;
+                       
+                       if (x >= (ACHANNEL_NAMEWIDTH-16)) {
+                               /* toggle lock */
+                               gpl->flag ^= GP_LAYER_LOCKED;
                        }
-                               break;
+                       else if (x >= (ACHANNEL_NAMEWIDTH-32)) {
+                               /* toggle hide */
+                               gpl->flag ^= GP_LAYER_HIDE;
+                       }
+                       else {
+                               /* select/deselect */
+                               //if (G.qual & LR_SHIFTKEY) {
+                                       //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
+                               //}
+                               //else {
+                                       //deselect_gpencil_layers(data, 0);
+                                       //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
+                               //}
+                       }
+#endif // XXX future of this is unclear
+               }
+                       break;
                case ANIMTYPE_SHAPEKEY:
                        /* TODO: shapekey channels cannot be selected atm... */
                        break;
@@ -449,8 +1598,10 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *
        mval[1]= (event->y - ar->winrct.ymin);
        
        /* select mode is either replace (deselect all, then add) or add/extend */
-       if (RNA_boolean_get(op->ptr, "extend_select"))
+       if (RNA_boolean_get(op->ptr, "extend"))
                selectmode= SELECT_INVERT;
+       else if (RNA_boolean_get(op->ptr, "children_only"))
+               selectmode= -1; /* this is a bit of a special case for ActionGroups only... should it be removed or extended to all instead? */
        else
                selectmode= SELECT_REPLACE;
        
@@ -460,29 +1611,33 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *
         *              ACHANNEL_HEIGHT_HALF.
         */
        UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
-       UI_view2d_listview_get_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
+       UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
        
        /* handle mouse-click in the relevant channel then */
        mouse_anim_channels(&ac, x, channel_index, selectmode);
        
        /* set notifier tha things have changed */
-       ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
+       ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
        
        return OPERATOR_FINISHED;
 }
  
-void ANIM_OT_channels_mouseclick (wmOperatorType *ot)
+void ANIM_OT_channels_click (wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Mouse Click on Channels";
-       ot->idname= "ANIM_OT_channels_mouseclick";
+       ot->idname= "ANIM_OT_channels_click";
        
        /* api callbacks */
        ot->invoke= animchannels_mouseclick_invoke;
        ot->poll= ED_operator_areaactive;
        
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
        /* id-props */
-       RNA_def_property(ot->srna, "extend_select", PROP_BOOLEAN, PROP_NONE); // SHIFTKEY
+       RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
+       RNA_def_boolean(ot->srna, "children_only", 0, "Select Children Only", ""); // CTRLKEY|SHIFTKEY
 }
 
 /* ************************************************************************** */
@@ -490,17 +1645,70 @@ void ANIM_OT_channels_mouseclick (wmOperatorType *ot)
 
 void ED_operatortypes_animchannels(void)
 {
-       WM_operatortype_append(ANIM_OT_channels_mouseclick);
+       WM_operatortype_append(ANIM_OT_channels_select_all_toggle);
+       WM_operatortype_append(ANIM_OT_channels_select_border);
+       WM_operatortype_append(ANIM_OT_channels_click);
+       
+       WM_operatortype_append(ANIM_OT_channels_setting_enable);
+       WM_operatortype_append(ANIM_OT_channels_setting_disable);
+       WM_operatortype_append(ANIM_OT_channels_setting_toggle);
+       
+               // XXX does this need to be a separate operator?
+       WM_operatortype_append(ANIM_OT_channels_editable_toggle);
+       
+               // XXX these need to be updated for new system... todo...
+       //WM_operatortype_append(ANIM_OT_channels_move_up);
+       //WM_operatortype_append(ANIM_OT_channels_move_down);
+       //WM_operatortype_append(ANIM_OT_channels_move_top);
+       //WM_operatortype_append(ANIM_OT_channels_move_bottom);
+       
+       WM_operatortype_append(ANIM_OT_channels_expand);
+       WM_operatortype_append(ANIM_OT_channels_collapse);
+       
+       WM_operatortype_append(ANIM_OT_channels_visibility_toggle);
 }
 
 void ED_keymap_animchannels(wmWindowManager *wm)
 {
        ListBase *keymap = WM_keymap_listbase(wm, "Animation_Channels", 0, 0);
        
-       /* click-select */
+       /* selection */
+               /* click-select */
                // XXX for now, only leftmouse.... 
-       WM_keymap_add_item(keymap, "ANIM_OT_channels_mouseclick", LEFTMOUSE, KM_PRESS, 0, 0);
-       RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_mouseclick", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend_select", 1);
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, 0, 0);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_CTRL|KM_SHIFT, 0)->ptr, "children_only", 1);
+       
+               /* deselect all */
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", AKEY, KM_PRESS, 0, 0);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
+       
+               /* borderselect */
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", BKEY, KM_PRESS, 0, 0);
+       
+       /* settings */
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_toggle", WKEY, KM_PRESS, KM_SHIFT, 0);
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_enable", WKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_disable", WKEY, KM_PRESS, KM_ALT, 0);
+       
+       /* settings - specialised hotkeys */
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_editable_toggle", TABKEY, KM_PRESS, 0, 0);
+       
+       /* expand/collapse */
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, 0, 0);
+       
+       RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, KM_CTRL, 0)->ptr, "all", 1);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, KM_CTRL, 0)->ptr, "all", 1);
+       
+       /* rearranging - actions only */
+       //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_up", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0);
+       //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_down", PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0);
+       //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_to_top", PAGEUPKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
+       //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_to_bottom", PAGEDOWNKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
+       
+       /* Graph Editor only */
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_toggle", VKEY, KM_PRESS, 0, 0);
 }
 
 /* ************************************************************************** */