Bugfix #20664: NLA Editor - Hiding stuff causes instant crash ..
[blender.git] / source / blender / editors / animation / anim_channels_edit.c
index 72d8f71bc265ad4d519fe8b7b726d2bf0a8537cd..f756c5b3158640025e37b1ed4f0a92271c975af8 100644 (file)
@@ -37,7 +37,7 @@
 #include "MEM_guardedalloc.h"
 
 #include "BLI_blenlib.h"
-#include "BLI_arithb.h"
+#include "BLI_math.h"
 
 #include "DNA_listBase.h"
 #include "DNA_anim_types.h"
 #include "WM_types.h"
 
 /* ************************************************************************** */
-/* CHANNELS API */
+/* CHANNELS API - Exposed API */
 
-/* -------------------------- Exposed API ----------------------------------- */
+/* -------------------------- Selection ------------------------------------- */
 
 /* Set the given animation-channel as the active one for the active context */
+// TODO: extend for animdata types...
 void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type)
 {
        ListBase anim_data = {NULL, NULL};
@@ -130,11 +131,30 @@ void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int
                                ACHANNEL_SET_FLAG(nlt, ACHANNEL_SETFLAG_CLEAR, NLATRACK_ACTIVE);
                        }
                                break;
+                       
+                       case ANIMTYPE_FILLACTD: /* Action Expander */
+                       case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
+                       case ANIMTYPE_DSLAM:
+                       case ANIMTYPE_DSCAM:
+                       case ANIMTYPE_DSCUR:
+                       case ANIMTYPE_DSSKEY:
+                       case ANIMTYPE_DSWOR:
+                       case ANIMTYPE_DSPART:
+                       case ANIMTYPE_DSMBALL:
+                       case ANIMTYPE_DSARM:
+                       case ANIMTYPE_DSMESH:
+                       {
+                               /* need to verify that this data is valid for now */
+                               if (ale->adt) {
+                                       ACHANNEL_SET_FLAG(ale->adt, ACHANNEL_SETFLAG_CLEAR, ADT_UI_ACTIVE);
+                               }
+                       }
+                               break;
                }
        }
        
        /* set active flag */
-       if (channel_data != NULL) {
+       if (channel_data) {
                switch (channel_type) {
                        case ANIMTYPE_GROUP:
                        {
@@ -154,6 +174,24 @@ void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int
                                nlt->flag |= NLATRACK_ACTIVE;
                        }
                                break;
+                               
+                       case ANIMTYPE_FILLACTD: /* Action Expander */
+                       case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
+                       case ANIMTYPE_DSLAM:
+                       case ANIMTYPE_DSCAM:
+                       case ANIMTYPE_DSCUR:
+                       case ANIMTYPE_DSSKEY:
+                       case ANIMTYPE_DSWOR:
+                       case ANIMTYPE_DSPART:
+                       case ANIMTYPE_DSMBALL:
+                       case ANIMTYPE_DSARM:
+                       case ANIMTYPE_DSMESH:
+                       {
+                               /* need to verify that this data is valid for now */
+                               if (ale->adt)
+                                       ale->adt->flag |= ADT_UI_ACTIVE;
+                       }
+                               break;
                }
        }
        
@@ -167,15 +205,15 @@ void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int
  *     - test: check if deselecting instead of selecting
  *     - sel: eAnimChannels_SetFlag;
  */
-void ANIM_deselect_anim_channels (void *data, short datatype, short test, short sel)
+void ANIM_deselect_anim_channels (bAnimContext *ac, 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);
+       filter= ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS;
+       ANIM_animdata_filter(ac, &anim_data, filter, data, datatype);
        
        /* See if we should be selecting or deselecting */
        if (test) {
@@ -189,12 +227,10 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short
                                                sel= ACHANNEL_SETFLAG_CLEAR;
                                        break;
                                case ANIMTYPE_OBJECT:
+                               #if 0   /* for now, do not take object selection into account, since it gets too annoying */
                                        if (ale->flag & SELECT)
                                                sel= ACHANNEL_SETFLAG_CLEAR;
-                                       break;
-                               case ANIMTYPE_FILLACTD:
-                                       if (ale->flag & ACT_SELECTED)
-                                               sel= ACHANNEL_SETFLAG_CLEAR;
+                               #endif
                                        break;
                                case ANIMTYPE_GROUP:
                                        if (ale->flag & AGRP_SELECTED)
@@ -204,10 +240,31 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short
                                        if (ale->flag & FCURVE_SELECTED)
                                                sel= ACHANNEL_SETFLAG_CLEAR;
                                        break;
+                               case ANIMTYPE_SHAPEKEY:
+                                       if (ale->flag & KEYBLOCK_SEL)
+                                               sel= ACHANNEL_SETFLAG_CLEAR;
+                                       break;
                                case ANIMTYPE_NLATRACK:
                                        if (ale->flag & NLATRACK_SELECTED)
                                                sel= ACHANNEL_SETFLAG_CLEAR;
                                        break;
+                                       
+                               case ANIMTYPE_FILLACTD: /* Action Expander */
+                               case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
+                               case ANIMTYPE_DSLAM:
+                               case ANIMTYPE_DSCAM:
+                               case ANIMTYPE_DSCUR:
+                               case ANIMTYPE_DSSKEY:
+                               case ANIMTYPE_DSWOR:
+                               case ANIMTYPE_DSPART:
+                               case ANIMTYPE_DSMBALL:
+                               case ANIMTYPE_DSARM:
+                               case ANIMTYPE_DSMESH:
+                               {
+                                       if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
+                                               sel= ACHANNEL_SETFLAG_CLEAR;
+                               }
+                                       break;
                        }
                }
        }
@@ -220,23 +277,26 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short
                                Scene *scene= (Scene *)ale->data;
                                
                                ACHANNEL_SET_FLAG(scene, sel, SCE_DS_SELECTED);
+                               
+                               if (scene->adt) {
+                                       ACHANNEL_SET_FLAG(scene, sel, ADT_UI_SELECTED);
+                               }
                        }
                                break;
                        case ANIMTYPE_OBJECT:
+                       #if 0   /* for now, do not take object selection into account, since it gets too annoying */
                        {
                                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);
+                               if (ob->adt) {
+                                       ACHANNEL_SET_FLAG(ob, sel, ADT_UI_SELECTED);
+                               }
                        }
+                       #endif
                                break;
                        case ANIMTYPE_GROUP:
                        {
@@ -254,6 +314,13 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short
                                fcu->flag &= ~FCURVE_ACTIVE;
                        }
                                break;
+                       case ANIMTYPE_SHAPEKEY:
+                       {
+                               KeyBlock *kb= (KeyBlock *)ale->data;
+                               
+                               ACHANNEL_SET_FLAG(kb, sel, KEYBLOCK_SEL);
+                       }
+                               break;
                        case ANIMTYPE_NLATRACK:
                        {
                                NlaTrack *nlt= (NlaTrack *)ale->data;
@@ -262,6 +329,26 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short
                                nlt->flag &= ~NLATRACK_ACTIVE;
                        }
                                break;
+                               
+                       case ANIMTYPE_FILLACTD: /* Action Expander */
+                       case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
+                       case ANIMTYPE_DSLAM:
+                       case ANIMTYPE_DSCAM:
+                       case ANIMTYPE_DSCUR:
+                       case ANIMTYPE_DSSKEY:
+                       case ANIMTYPE_DSWOR:
+                       case ANIMTYPE_DSPART:
+                       case ANIMTYPE_DSMBALL:
+                       case ANIMTYPE_DSARM:
+                       case ANIMTYPE_DSMESH:
+                       {
+                               /* need to verify that this data is valid for now */
+                               if (ale->adt) {
+                                       ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED);
+                                       ale->adt->flag &= ~ADT_UI_ACTIVE;
+                               }
+                       }
+                               break;
                }
        }
        
@@ -269,6 +356,164 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short
        BLI_freelistN(&anim_data);
 }
 
+/* ---------------------------- Graph Editor ------------------------------------- */
+
+/* Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting 
+ *     - anim_data: list of the all the anim channels that can be chosen
+ *             -> filtered using ANIMFILTER_CHANNELS only, since if we took VISIBLE too,
+ *               then the channels under closed expanders get ignored...
+ *     - ale_setting: the anim channel (not in the anim_data list directly, though occuring there)
+ *             with the new state of the setting that we want flushed up/down the hierarchy 
+ *     - setting: type of setting to set
+ *     - on: whether the visibility setting has been enabled or disabled 
+ */
+void ANIM_flush_setting_anim_channels (bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, int setting, short on)
+{
+       bAnimListElem *ale, *match=NULL;
+       int prevLevel=0, matchLevel=0;
+       
+       /* sanity check */
+       if (ELEM(NULL, anim_data, anim_data->first))
+               return;
+       
+       /* find the channel that got changed */
+       for (ale= anim_data->first; ale; ale= ale->next) {
+               /* compare data, and type as main way of identifying the channel */
+               if ((ale->data == ale_setting->data) && (ale->type == ale_setting->type)) {
+                       /* we also have to check the ID, this is assigned to, since a block may have multiple users */
+                       // TODO: is the owner-data more revealing?
+                       if (ale->id == ale_setting->id) {
+                               match= ale;
+                               break;
+                       }
+               }
+       }
+       if (match == NULL) {
+               printf("ERROR: no channel matching the one changed was found \n");
+               return;
+       }
+       else {
+               bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale_setting);
+               
+               if (acf == NULL) {
+                       printf("ERROR: no channel info for the changed channel \n");
+                       return;
+               }
+               
+               /* get the level of the channel that was affected
+                *       - we define the level as simply being the offset for the start of the channel
+                */
+               matchLevel= (acf->get_offset)? acf->get_offset(ac, ale_setting) : 0;
+               prevLevel= matchLevel;
+       }
+       
+       /* flush up? 
+        *
+        * For Visibility:
+        *      - only flush up if the current state is now enabled (positive 'on' state is default) 
+        *        (otherwise, it's too much work to force the parents to be inactive too)
+        *
+        * For everything else:
+        *      - only flush up if the current state is now disabled (negative 'off' state is default)
+        *        (otherwise, it's too much work to force the parents to be active too)
+        */
+       if ( ((setting == ACHANNEL_SETTING_VISIBLE) && on) ||
+                ((setting != ACHANNEL_SETTING_VISIBLE) && on==0) )
+       {
+               /* go backwards in the list, until the highest-ranking element (by indention has been covered) */
+               for (ale= match->prev; ale; ale= ale->prev) {
+                       bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale);
+                       int level;
+                       
+                       /* if no channel info was found, skip, since this type might not have any useful info */
+                       if (acf == NULL)
+                               continue;
+                       
+                       /* get the level of the current channel traversed 
+                        *       - we define the level as simply being the offset for the start of the channel
+                        */
+                       level= (acf->get_offset)? acf->get_offset(ac, ale) : 0;
+                       
+                       /* if the level is 'less than' (i.e. more important) the level we're matching
+                        * but also 'less than' the level just tried (i.e. only the 1st group above grouped F-Curves, 
+                        * when toggling visibility of F-Curves, gets flushed), flush the new status...
+                        */
+                       if (level < prevLevel)
+                               ANIM_channel_setting_set(ac, ale, setting, on);
+                       /* however, if the level is 'greater than' (i.e. less important than the previous channel,
+                        * stop searching, since we've already reached the bottom of another hierarchy
+                        */
+                       else if (level > matchLevel)
+                               break;
+                       
+                       /* store this level as the 'old' level now */
+                       prevLevel= level;
+               }
+       }
+       
+       /* flush down (always) */
+       {
+               /* go forwards in the list, until the lowest-ranking element (by indention has been covered) */
+               for (ale= match->next; ale; ale= ale->next) {
+                       bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale);
+                       int level;
+                       
+                       /* if no channel info was found, skip, since this type might not have any useful info */
+                       if (acf == NULL)
+                               continue;
+                       
+                       /* get the level of the current channel traversed 
+                        *       - we define the level as simply being the offset for the start of the channel
+                        */
+                       level= (acf->get_offset)? acf->get_offset(ac, ale) : 0;
+                       
+                       /* if the level is 'greater than' (i.e. less important) the channel that was changed, 
+                        * flush the new status...
+                        */
+                       if (level > matchLevel)
+                               ANIM_channel_setting_set(ac, ale, setting, on);
+                       /* however, if the level is 'less than or equal to' the channel that was changed,
+                        * (i.e. the current channel is as important if not more important than the changed channel)
+                        * then we should stop, since we've found the last one of the children we should flush
+                        */
+                       else
+                               break;
+                       
+                       /* store this level as the 'old' level now */
+                       prevLevel= level;
+               }
+       }
+}
+
+/* -------------------------- F-Curves ------------------------------------- */
+
+/* Delete the given F-Curve from its AnimData block */
+void ANIM_fcurve_delete_from_animdata (bAnimContext *ac, AnimData *adt, FCurve *fcu)
+{
+       /* - if no AnimData, we've got nowhere to remove the F-Curve from 
+        *      (this doesn't guarantee that the F-Curve is in there, but at least we tried
+        * - if no F-Curve, there is nothing to remove
+        */
+       if (ELEM(NULL, adt, fcu))
+               return;
+               
+       /* remove from whatever list it came from
+        *      - Action Group
+        *      - Action
+        *      - Drivers
+        *      - TODO... some others?
+        */
+       if (fcu->grp)
+               action_groups_remove_channel(adt->action, fcu);
+       else if ((ac) && (ac->datatype == ANIMCONT_DRIVERS))
+               BLI_remlink(&adt->drivers, fcu);
+       else if (adt->action)
+               BLI_remlink(&adt->action->curves, fcu);
+               
+       /* free the F-Curve itself */
+       free_fcurve(fcu);
+}
+
 /* ************************************************************************** */
 /* OPERATORS */
 
@@ -762,25 +1007,8 @@ static int animchannels_delete_exec(bContext *C, wmOperator *op)
                                AnimData *adt= ale->adt;
                                FCurve *fcu= (FCurve *)ale->data;
                                
-                               /* if no AnimData, we've got nowhere to remove the F-Curve from */
-                               if (adt == NULL)
-                                       continue;
-                                       
-                               /* remove from whatever list it came from
-                                *      - Action Group
-                                *      - Action
-                                *      - Drivers
-                                *      - TODO... some others?
-                                */
-                               if (fcu->grp)
-                                       action_groups_remove_channel(adt->action, fcu);
-                               else if (adt->action)
-                                       BLI_remlink(&adt->action->curves, fcu);
-                               else if (ac.datatype == ANIMCONT_DRIVERS)
-                                       BLI_remlink(&adt->drivers, fcu);
-                                       
-                               /* free the F-Curve itself */
-                               free_fcurve(fcu);
+                               /* try to free F-Curve */
+                               ANIM_fcurve_delete_from_animdata(&ac, adt, fcu);
                        }
                }
                
@@ -809,12 +1037,87 @@ void ANIM_OT_channels_delete (wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
+/* ******************** Set Channel Visibility Operator *********************** */
+/* NOTE: this operator is only valid in the Graph Editor channels region */
+
+static int animchannels_visibility_set_exec(bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       ListBase anim_data = {NULL, NULL};
+       ListBase all_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+       
+       
+       /* hide all channels not selected */
+       filter= (ANIMFILTER_VISIBLE | ANIMFILTER_UNSEL);
+       ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+       
+       for (ale= anim_data.first; ale; ale= ale->next)
+               ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_CLEAR);
+       
+       BLI_freelistN(&anim_data);
+       
+       
+       /* get list of all channels that selection may need to be flushed to */
+       filter= ANIMFILTER_CHANNELS;
+       ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
+       
+       /* make all the selected channels visible */
+       filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL);
+       ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+       
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
+               // TODO: find out why this is the case, and fix that
+               if (ale->type == ANIMTYPE_OBJECT)
+                       continue;
+               
+               /* enable the setting */
+               ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD);
+               
+               /* now, also flush selection status up/down as appropriate */
+               ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 1);
+       }
+       
+       BLI_freelistN(&anim_data);
+       BLI_freelistN(&all_data);
+       
+       
+       /* send notifier that things have changed */
+       WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN_EDIT, NULL);
+       
+       return OPERATOR_FINISHED;
+}
+
+void ANIM_OT_channels_visibility_set (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Set Visibility";
+       ot->idname= "ANIM_OT_channels_visibility_set";
+       ot->description= "Make only the selected animation channels visible in the Graph Editor.";
+       
+       /* api callbacks */
+       ot->exec= animchannels_visibility_set_exec;
+       ot->poll= ED_operator_ipo_active;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+
 /* ******************** Toggle Channel Visibility Operator *********************** */
+/* NOTE: this operator is only valid in the Graph Editor channels region */
 
 static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *op)
 {
        bAnimContext ac;
        ListBase anim_data = {NULL, NULL};
+       ListBase all_data = {NULL, NULL};
        bAnimListElem *ale;
        int filter;
        short vis= ACHANNEL_SETFLAG_ADD;
@@ -823,6 +1126,10 @@ static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *op)
        if (ANIM_animdata_get_context(C, &ac) == 0)
                return OPERATOR_CANCELLED;
                
+       /* get list of all channels that selection may need to be flushed to */
+       filter= ANIMFILTER_CHANNELS;
+       ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
+               
        /* filter data */
        filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL);
        ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -832,32 +1139,28 @@ static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *op)
                if (vis == ACHANNEL_SETFLAG_CLEAR) 
                        break;
                
-               if ((ale->type == ANIMTYPE_FCURVE) && (ale->flag & FCURVE_VISIBLE))
-                       vis= ACHANNEL_SETFLAG_CLEAR;
-               else if ((ale->type == ANIMTYPE_GROUP) && !(ale->flag & AGRP_NOTVISIBLE))
+               /* set the setting in the appropriate way (if available) */
+               if (ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_VISIBLE))
                        vis= ACHANNEL_SETFLAG_CLEAR;
        }
-               
+
        /* Now set the flags */
        for (ale= anim_data.first; ale; ale= ale->next) {
-               switch (ale->type) {
-                       case ANIMTYPE_FCURVE: /* F-Curve */
-                       {
-                               FCurve *fcu= (FCurve *)ale->data;
-                               ACHANNEL_SET_FLAG(fcu, vis, FCURVE_VISIBLE);
-                       }
-                               break;
-                       case ANIMTYPE_GROUP: /* Group */
-                       {
-                               bActionGroup *agrp= (bActionGroup *)ale->data;
-                               ACHANNEL_SET_FLAG_NEG(agrp, vis, AGRP_NOTVISIBLE);
-                       }
-                               break;
-               }
+               /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
+               // TODO: find out why this is the case, and fix that
+               if (ale->type == ANIMTYPE_OBJECT)
+                       continue;
+               
+               /* change the setting */
+               ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, vis);
+               
+               /* now, also flush selection status up/down as appropriate */
+               ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, (vis == ACHANNEL_SETFLAG_ADD));
        }
        
        /* cleanup */
        BLI_freelistN(&anim_data);
+       BLI_freelistN(&all_data);
        
        /* send notifier that things have changed */
        WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN_EDIT, NULL);
@@ -974,7 +1277,7 @@ void ANIM_OT_channels_setting_enable (wmOperatorType *ot)
                /* 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", "");
+       ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
 }
 
 void ANIM_OT_channels_setting_disable (wmOperatorType *ot)
@@ -996,7 +1299,7 @@ void ANIM_OT_channels_setting_disable (wmOperatorType *ot)
                /* 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", "");
+       ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
 }
 
 void ANIM_OT_channels_setting_toggle (wmOperatorType *ot)
@@ -1018,7 +1321,7 @@ void ANIM_OT_channels_setting_toggle (wmOperatorType *ot)
                /* 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", "");
+       ot->prop= 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?
@@ -1082,7 +1385,7 @@ void ANIM_OT_channels_expand (wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* props */
-       RNA_def_boolean(ot->srna, "all", 0, "All", "Expand all channels (not just selected ones)");
+       RNA_def_boolean(ot->srna, "all", 1, "All", "Expand all channels (not just selected ones)");
 }
 
 /* ********************** Collapse Channels Operator *********************** */
@@ -1124,7 +1427,7 @@ void ANIM_OT_channels_collapse (wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* props */
-       RNA_def_boolean(ot->srna, "all", 0, "All", "Collapse all channels (not just selected ones)");
+       RNA_def_boolean(ot->srna, "all", 1, "All", "Collapse all channels (not just selected ones)");
 }
 
 /* ********************** Select All Operator *********************** */
@@ -1139,9 +1442,9 @@ static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
                
        /* '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);
+               ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 0, ACHANNEL_SETFLAG_TOGGLE);
        else
-               ANIM_deselect_anim_channels(ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_ADD);
+               ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_ADD);
        
        /* send notifier that things have changed */
        WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN_SELECT, NULL);
@@ -1224,7 +1527,7 @@ static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
        bAnimContext ac;
        rcti rect;
        short selectmode=0;
-       int event;
+       int gesture_mode;
        
        /* get editor data */
        if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -1236,8 +1539,8 @@ static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
        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
+       gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
+       if (gesture_mode == GESTURE_MODAL_SELECT)
                selectmode = ACHANNEL_SETFLAG_ADD;
        else
                selectmode = ACHANNEL_SETFLAG_CLEAR;
@@ -1269,11 +1572,7 @@ void ANIM_OT_channels_select_border(wmOperatorType *ot)
        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);
+       WM_operator_properties_gesture_border(ot, FALSE);
 }
 
 /* ******************** Mouse-Click Operator *********************** */
@@ -1289,7 +1588,7 @@ static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, sh
        /* get the channel that was clicked on */
                /* filter channels */
        filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
-       filter= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+       ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
        
                /* get channel from index */
        ale= BLI_findlink(&anim_data, channel_index);
@@ -1310,18 +1609,22 @@ static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, sh
        }
        
        /* action to take depends on what channel we've got */
+       // WARNING: must keep this in sync with the equivalent function in nla_channels.c
        switch (ale->type) {
                case ANIMTYPE_SCENE:
                {
                        Scene *sce= (Scene *)ale->data;
+                       AnimData *adt= sce->adt;
                        
                        /* set selection status */
                        if (selectmode == SELECT_INVERT) {
                                /* swap select */
                                sce->flag ^= SCE_DS_SELECTED;
+                               if (adt) adt->flag ^= ADT_UI_SELECTED;
                        }
                        else {
                                sce->flag |= SCE_DS_SELECTED;
+                               if (adt) adt->flag |= ADT_UI_SELECTED;
                        }
                        
                        notifierFlags |= ND_ANIMCHAN_SELECT;
@@ -1333,34 +1636,76 @@ static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, sh
                        Scene *sce= (Scene *)ads->source;
                        Base *base= (Base *)ale->data;
                        Object *ob= base->object;
+                       AnimData *adt= ob->adt;
                        
                        /* set selection status */
                        if (selectmode == SELECT_INVERT) {
                                /* swap select */
                                base->flag ^= SELECT;
                                ob->flag= base->flag;
+                               
+                               if (adt) adt->flag ^= ADT_UI_SELECTED;
                        }
                        else {
                                Base *b;
                                
-                               /* deleselect all */
+                               /* deselect all */
+                               // TODO: should this deselect all other types of channels too?
                                for (b= sce->base.first; b; b= b->next) {
                                        b->flag &= ~SELECT;
                                        b->object->flag= b->flag;
+                                       if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED|ADT_UI_ACTIVE);
                                }
                                
                                /* select object now */
                                base->flag |= SELECT;
                                ob->flag |= SELECT;
+                               if (adt) adt->flag |= ADT_UI_SELECTED;
                        }
                        
                        /* xxx should be ED_base_object_activate(), but we need context pointer for that... */
                        //set_active_base(base);
+                       if ((adt) && (adt->flag & ADT_UI_SELECTED))
+                               adt->flag |= ADT_UI_ACTIVE;
                        
                        notifierFlags |= ND_ANIMCHAN_SELECT;
                }
                        break;
+               
+               case ANIMTYPE_FILLACTD: /* Action Expander */
+               case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
+               case ANIMTYPE_DSLAM:
+               case ANIMTYPE_DSCAM:
+               case ANIMTYPE_DSCUR:
+               case ANIMTYPE_DSSKEY:
+               case ANIMTYPE_DSWOR:
+               case ANIMTYPE_DSPART:
+               case ANIMTYPE_DSMBALL:
+               case ANIMTYPE_DSARM:
+               case ANIMTYPE_DSMESH:
+               {
+                       /* sanity checking... */
+                       if (ale->adt) {
+                               /* select/deselect */
+                               if (selectmode == SELECT_INVERT) {
+                                       /* inverse selection status of this AnimData block only */
+                                       ale->adt->flag ^= ADT_UI_SELECTED;
+                               }
+                               else {
+                                       /* select AnimData block by itself */
+                                       ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+                                       ale->adt->flag |= ADT_UI_SELECTED;
+                               }
+                               
+                               /* set active? */
+                               if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
+                                       ale->adt->flag |= ADT_UI_ACTIVE;
+                       }
                        
+                       notifierFlags |= ND_ANIMCHAN_SELECT;
+               }       
+                       break;
+               
                case ANIMTYPE_GROUP: 
                {
                        bActionGroup *agrp= (bActionGroup *)ale->data;
@@ -1375,7 +1720,7 @@ static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, sh
                                FCurve *fcu;
                                
                                /* deselect all other channels */
-                               ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+                               ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
                                
                                /* only select channels in group and group itself */
                                for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next)
@@ -1384,7 +1729,7 @@ static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, sh
                        }
                        else {
                                /* select group by itself */
-                               ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+                               ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
                                agrp->flag |= AGRP_SELECTED;
                        }
                        
@@ -1406,7 +1751,7 @@ static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, sh
                        }
                        else {
                                /* select F-Curve by itself */
-                               ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+                               ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
                                fcu->flag |= FCURVE_SELECTED;
                        }
                        
@@ -1414,6 +1759,24 @@ static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, sh
                        if (fcu->flag & FCURVE_SELECTED)
                                ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
                                
+                       notifierFlags |= ND_ANIMCHAN_SELECT;
+               }
+                       break;
+               case ANIMTYPE_SHAPEKEY: 
+               {
+                       KeyBlock *kb= (KeyBlock *)ale->data;
+                       
+                       /* select/deselect */
+                       if (selectmode == SELECT_INVERT) {
+                               /* inverse selection status of this ShapeKey only */
+                               kb->flag ^= KEYBLOCK_SEL;
+                       }
+                       else {
+                               /* select ShapeKey by itself */
+                               ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+                               kb->flag |= KEYBLOCK_SEL;
+                       }
+                               
                        notifierFlags |= ND_ANIMCHAN_SELECT;
                }
                        break;
@@ -1454,9 +1817,6 @@ static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, sh
 #endif // XXX future of this is unclear
                }
                        break;
-               case ANIMTYPE_SHAPEKEY:
-                       /* TODO: shapekey channels cannot be selected atm... */
-                       break;
                default:
                        printf("Error: Invalid channel type in mouse_anim_channels() \n");
        }
@@ -1568,11 +1928,13 @@ void ED_operatortypes_animchannels(void)
        WM_operatortype_append(ANIM_OT_channels_collapse);
        
        WM_operatortype_append(ANIM_OT_channels_visibility_toggle);
+       WM_operatortype_append(ANIM_OT_channels_visibility_set);
 }
 
-void ED_keymap_animchannels(wmWindowManager *wm)
+// TODO: check on a poll callback for this, to get hotkeys into menus
+void ED_keymap_animchannels(wmKeyConfig *keyconf)
 {
-       ListBase *keymap = WM_keymap_listbase(wm, "Animation_Channels", 0, 0);
+       wmKeyMap *keymap = WM_keymap_find(keyconf, "Animation Channels", 0, 0);
        
        /* selection */
                /* click-select */
@@ -1587,6 +1949,7 @@ void ED_keymap_animchannels(wmWindowManager *wm)
        
                /* borderselect */
        WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", BKEY, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", EVT_TWEAK_L, KM_ANY, 0, 0);
        
        /* delete */
        WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", XKEY, KM_PRESS, 0, 0);
@@ -1604,8 +1967,8 @@ void ED_keymap_animchannels(wmWindowManager *wm)
        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);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, KM_CTRL, 0)->ptr, "all", 0);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, KM_CTRL, 0)->ptr, "all", 0);
        
        /* rearranging - actions only */
        //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_up", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0);
@@ -1614,7 +1977,8 @@ void ED_keymap_animchannels(wmWindowManager *wm)
        //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);
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_set", VKEY, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_toggle", VKEY, KM_PRESS, KM_SHIFT, 0);
 }
 
 /* ************************************************************************** */