Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / animation / anim_channels_edit.c
index b6ab04077114f2c72073d51a39d28b2e3b4f2dc8..20e5bec44a37b188e19d4c9aed57ee5b60b59849 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "MEM_guardedalloc.h"
 
+#include "BKE_depsgraph.h"
 #include "BLI_blenlib.h"
 #include "BLI_utildefines.h"
 #include "BLI_listbase.h"
@@ -101,6 +102,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
                                break;
                        }
                        case ANIMTYPE_FCURVE:
+                       case ANIMTYPE_NLACURVE:
                        {
                                FCurve *fcu = (FCurve *)ale->data;
                                
@@ -118,10 +120,10 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
                        case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
                        case ANIMTYPE_DSLAM:
                        case ANIMTYPE_DSCAM:
+                       case ANIMTYPE_DSCACHEFILE:
                        case ANIMTYPE_DSCUR:
                        case ANIMTYPE_DSSKEY:
                        case ANIMTYPE_DSWOR:
-                       case ANIMTYPE_DSPART:
                        case ANIMTYPE_DSMBALL:
                        case ANIMTYPE_DSARM:
                        case ANIMTYPE_DSMESH:
@@ -129,6 +131,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
                        case ANIMTYPE_DSLAT:
                        case ANIMTYPE_DSLINESTYLE:
                        case ANIMTYPE_DSSPK:
+                       case ANIMTYPE_DSGPENCIL:
                        {
                                /* need to verify that this data is valid for now */
                                if (ale->adt) {
@@ -136,6 +139,13 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
                                }
                                break;
                        }
+                       case ANIMTYPE_GPLAYER:
+                       {
+                               bGPDlayer *gpl = (bGPDlayer *)ale->data;
+                               
+                               ACHANNEL_SET_FLAG(gpl, ACHANNEL_SETFLAG_CLEAR, GP_LAYER_ACTIVE);
+                               break;
+                       }
                }
        }
        
@@ -149,6 +159,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
                                break;
                        }
                        case ANIMTYPE_FCURVE:
+                       case ANIMTYPE_NLACURVE:
                        {
                                FCurve *fcu = (FCurve *)channel_data;
                                fcu->flag |= FCURVE_ACTIVE;
@@ -164,10 +175,10 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
                        case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
                        case ANIMTYPE_DSLAM:
                        case ANIMTYPE_DSCAM:
+                       case ANIMTYPE_DSCACHEFILE:
                        case ANIMTYPE_DSCUR:
                        case ANIMTYPE_DSSKEY:
                        case ANIMTYPE_DSWOR:
-                       case ANIMTYPE_DSPART:
                        case ANIMTYPE_DSMBALL:
                        case ANIMTYPE_DSARM:
                        case ANIMTYPE_DSMESH:
@@ -176,6 +187,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
                        case ANIMTYPE_DSSPK:
                        case ANIMTYPE_DSNTREE:
                        case ANIMTYPE_DSTEX:
+                       case ANIMTYPE_DSGPENCIL:
                        {
                                /* need to verify that this data is valid for now */
                                if (ale && ale->adt) {
@@ -184,8 +196,14 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
                                break;
                        }
                        
-                       /* unhandled currently, but may be interesting */
                        case ANIMTYPE_GPLAYER:
+                       {
+                               bGPDlayer *gpl = (bGPDlayer *)channel_data;
+                               gpl->flag |= GP_LAYER_ACTIVE;
+                               break;
+                       }
+                       
+                       /* unhandled currently, but may be interesting */
                        case ANIMTYPE_MASKLAYER:
                        case ANIMTYPE_SHAPEKEY:
                        case ANIMTYPE_NLAACTION:
@@ -240,6 +258,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
                                                sel = ACHANNEL_SETFLAG_CLEAR;
                                        break;
                                case ANIMTYPE_FCURVE:
+                               case ANIMTYPE_NLACURVE:
                                        if (ale->flag & FCURVE_SELECTED)
                                                sel = ACHANNEL_SETFLAG_CLEAR;
                                        break;
@@ -256,10 +275,10 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
                                case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
                                case ANIMTYPE_DSLAM:
                                case ANIMTYPE_DSCAM:
+                               case ANIMTYPE_DSCACHEFILE:
                                case ANIMTYPE_DSCUR:
                                case ANIMTYPE_DSSKEY:
                                case ANIMTYPE_DSWOR:
-                               case ANIMTYPE_DSPART:
                                case ANIMTYPE_DSMBALL:
                                case ANIMTYPE_DSARM:
                                case ANIMTYPE_DSMESH:
@@ -268,6 +287,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
                                case ANIMTYPE_DSLAT:
                                case ANIMTYPE_DSLINESTYLE:
                                case ANIMTYPE_DSSPK:
+                               case ANIMTYPE_DSGPENCIL:
                                {
                                        if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
                                                sel = ACHANNEL_SETFLAG_CLEAR;
@@ -323,6 +343,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
                                break;
                        }
                        case ANIMTYPE_FCURVE:
+                       case ANIMTYPE_NLACURVE:
                        {
                                FCurve *fcu = (FCurve *)ale->data;
                                
@@ -349,10 +370,10 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
                        case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
                        case ANIMTYPE_DSLAM:
                        case ANIMTYPE_DSCAM:
+                       case ANIMTYPE_DSCACHEFILE:
                        case ANIMTYPE_DSCUR:
                        case ANIMTYPE_DSSKEY:
                        case ANIMTYPE_DSWOR:
-                       case ANIMTYPE_DSPART:
                        case ANIMTYPE_DSMBALL:
                        case ANIMTYPE_DSARM:
                        case ANIMTYPE_DSMESH:
@@ -361,6 +382,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d
                        case ANIMTYPE_DSLAT:
                        case ANIMTYPE_DSLINESTYLE:
                        case ANIMTYPE_DSSPK:
+                       case ANIMTYPE_DSGPENCIL:
                        {
                                /* need to verify that this data is valid for now */
                                if (ale->adt) {
@@ -427,7 +449,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
                return;
        }
        else {
-               bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale_setting);
+               const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale_setting);
                
                if (acf == NULL) {
                        printf("ERROR: no channel info for the changed channel\n");
@@ -456,7 +478,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
        {
                /* 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);
+                       const 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 */
@@ -500,7 +522,7 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn
        {
                /* 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);
+                       const 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 */
@@ -830,6 +852,7 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr
                        break;
                }
                case ANIMTYPE_FCURVE:
+               case ANIMTYPE_NLACURVE:
                {
                        FCurve *fcu = (FCurve *)channel;
                        
@@ -843,8 +866,15 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr
                        is_sel = SEL_NLT(nlt);
                        break;
                }
+               case ANIMTYPE_GPLAYER:
+               {
+                       bGPDlayer *gpl = (bGPDlayer *)channel;
+                       
+                       is_sel = SEL_GPL(gpl);
+                       break;
+               }
                default:
-                       printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %d\n", type);
+                       printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %u\n", type);
                        return;
        }
        
@@ -1167,6 +1197,81 @@ static void rearrange_action_channels(bAnimContext *ac, bAction *act, eRearrange
 
 /* ------------------- */
 
+static void rearrange_nla_control_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
+{
+       ListBase anim_data_visible = {NULL, NULL};
+       
+       NlaTrack *nlt;
+       NlaStrip *strip;
+       
+       /* get rearranging function */
+       AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
+       
+       if (rearrange_func == NULL)
+               return;
+               
+       /* skip if these curves aren't being shown */
+       if (adt->flag & ADT_NLA_SKEYS_COLLAPSED)
+               return;
+       
+       /* Filter visible data. */
+       rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLACURVE);
+       
+       /* we cannot rearrange between strips, but within each strip, we can rearrange those curves */
+       for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+               for (strip = nlt->strips.first; strip; strip = strip->next) {
+                       rearrange_animchannel_islands(&strip->fcurves, rearrange_func, mode, ANIMTYPE_NLACURVE,
+                                                         &anim_data_visible);
+               }
+       }
+       
+       /* free temp data */
+       BLI_freelistN(&anim_data_visible);
+}
+
+/* ------------------- */
+
+static void rearrange_gpencil_channels(bAnimContext *ac, eRearrangeAnimChan_Mode mode)
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       /* get rearranging function */
+       AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
+       
+       if (rearrange_func == NULL)
+               return;
+       
+       /* get Grease Pencil datablocks */
+       filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA);
+       ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+       
+       for (ale = anim_data.first; ale; ale = ale->next) {
+               ListBase anim_data_visible = {NULL, NULL};
+               bGPdata *gpd = ale->data;
+               
+               /* only consider layers if this datablock is open */
+               BLI_assert(ale->type == ANIMTYPE_GPDATABLOCK);
+               if ((gpd->flag & GP_DATA_EXPAND) == 0)
+                       continue;
+               
+               /* Filter visible data. */
+               rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_GPLAYER);
+               
+               /* rearrange datablock's layers */
+               rearrange_animchannel_islands(&gpd->layers, rearrange_func, mode, ANIMTYPE_GPLAYER, &anim_data_visible);
+               
+               /* free visible layers data */
+               BLI_freelistN(&anim_data_visible);
+       }
+       
+       /* free GPD channel data */
+       ANIM_animdata_freelist(&anim_data);
+}
+
+/* ------------------- */
+
 static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
 {
        bAnimContext ac;
@@ -1182,7 +1287,7 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
        /* method to move channels depends on the editor */
        if (ac.datatype == ANIMCONT_GPENCIL) {
                /* Grease Pencil channels */
-               printf("Grease Pencil not supported for moving yet\n");
+               rearrange_gpencil_channels(&ac, mode);
        }
        else if (ac.datatype == ANIMCONT_MASK) {
                /* Grease Pencil channels */
@@ -1213,13 +1318,29 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
                                        rearrange_driver_channels(&ac, adt, mode);
                                        break;
                                
+                               case ANIMCONT_ACTION: /* Single Action only... */
                                case ANIMCONT_SHAPEKEY: // DOUBLE CHECK ME...
-                               default: /* some collection of actions */
+                               {
+                                       if (adt->action)
+                                               rearrange_action_channels(&ac, adt->action, mode);
+                                       else if (G.debug & G_DEBUG)
+                                               printf("Animdata has no action\n");
+                                       break;
+                               }
+                               
+                               default: /* DopeSheet/Graph Editor - Some Actions + NLA Control Curves */
+                               {
+                                       /* NLA Control Curves */
+                                       if (adt->nla_tracks.first)
+                                               rearrange_nla_control_channels(&ac, adt, mode);
+                                       
+                                       /* Action */
                                        if (adt->action)
                                                rearrange_action_channels(&ac, adt->action, mode);
                                        else if (G.debug & G_DEBUG)
                                                printf("Animdata has no action\n");
                                        break;
+                               }
                        }
                }
                
@@ -1275,9 +1396,9 @@ static int animchannels_grouping_poll(bContext *C)
                        /* dopesheet and action only - all others are for other datatypes or have no groups */
                        if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_DOPESHEET) == 0)
                                return 0;
-               }
+
                        break;
-                       
+               }
                case SPACE_IPO:
                {
                        SpaceIpo *sipo = (SpaceIpo *)sl;
@@ -1285,9 +1406,9 @@ static int animchannels_grouping_poll(bContext *C)
                        /* drivers can't have groups... */
                        if (sipo->mode != SIPO_MODE_ANIMATION)
                                return 0;
-               }
+
                        break;
-                       
+               }
                /* unsupported... */
                default:
                        return 0;
@@ -1537,6 +1658,27 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
                                ANIM_fcurve_delete_from_animdata(&ac, adt, fcu);
                                break;
                        }
+                       case ANIMTYPE_NLACURVE:
+                       {
+                               /* NLA Control Curve - Deleting it should disable the corresponding setting... */
+                               NlaStrip *strip = (NlaStrip *)ale->owner;
+                               FCurve *fcu = (FCurve *)ale->data;
+                               
+                               if (STREQ(fcu->rna_path, "strip_time")) {
+                                       strip->flag &= ~NLASTRIP_FLAG_USR_TIME;
+                               }
+                               else if (STREQ(fcu->rna_path, "influence")) {
+                                       strip->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE;
+                               }
+                               else {
+                                       printf("ERROR: Trying to delete NLA Control Curve for unknown property '%s'\n", fcu->rna_path);
+                               }
+                               
+                               /* unlink and free the F-Curve */
+                               BLI_remlink(&strip->fcurves, fcu);
+                               free_fcurve(fcu);
+                               break;
+                       }
                        case ANIMTYPE_GPLAYER:
                        {
                                /* Grease Pencil layer */
@@ -1544,7 +1686,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
                                bGPDlayer *gpl = (bGPDlayer *)ale->data;
                                
                                /* try to delete the layer's data and the layer itself */
-                               free_gpencil_frames(gpl);
+                               BKE_gpencil_free_frames(gpl);
                                BLI_freelinkN(&gpd->layers, gpl);
                                break;
                        }
@@ -1566,7 +1708,8 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
        
        /* send notifier that things have changed */
        WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-       
+       DAG_relations_tag_update(CTX_data_main(C));
+
        return OPERATOR_FINISHED;
 }
  
@@ -1585,175 +1728,6 @@ static 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 *UNUSED(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;
-       
-       /* get list of all channels that selection may need to be flushed to 
-        * - hierarchy mustn't affect what we have access to here...
-        */
-       filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
-       ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
-               
-       /* hide all channels not selected
-        * - hierarchy matters if we're doing this from the channels region
-        *   since we only want to apply this to channels we can "see", 
-        *   and have these affect their relatives
-        * - but for Graph Editor, this gets used also from main region
-        *   where hierarchy doesn't apply, as for [#21276]
-        */
-       if ((ac.spacetype == SPACE_IPO) && (ac.regiontype != RGN_TYPE_CHANNELS)) {
-               /* graph editor (case 2) */
-               filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_UNSEL | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
-       }
-       else {
-               /* standard case */
-               filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_UNSEL | ANIMFILTER_NODUPLIS);
-       }
-       ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-       
-       for (ale = anim_data.first; ale; ale = ale->next) {
-               /* clear setting first */
-               ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_CLEAR);
-               
-               /* now also flush selection status as appropriate 
-                * NOTE: in some cases, this may result in repeat flushing being performed
-                */
-               ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 0);
-       }
-       
-       ANIM_animdata_freelist(&anim_data);
-       
-       /* make all the selected channels visible */
-       filter = (ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
-       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);
-       }
-       
-       ANIM_animdata_freelist(&anim_data);
-       BLI_freelistN(&all_data);
-       
-       
-       /* send notifier that things have changed */
-       WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-       
-       return OPERATOR_FINISHED;
-}
-
-static 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_graphedit_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 *UNUSED(op))
-{
-       bAnimContext ac;
-       ListBase anim_data = {NULL, NULL};
-       ListBase all_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;
-               
-       /* get list of all channels that selection may need to be flushed to 
-        * - hierarchy mustn't affect what we have access to here...
-        */
-       filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
-       ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
-               
-       /* filter data
-        * - restrict this to only applying on settings we can get to in the list
-        */
-       filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
-       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) {
-               /* set the setting in the appropriate way (if available) */
-               if (ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_VISIBLE)) {
-                       vis = ACHANNEL_SETFLAG_CLEAR;
-                       break;
-               }
-       }
-
-       /* Now set the flags */
-       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;
-               
-               /* 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 */
-       ANIM_animdata_freelist(&anim_data);
-       BLI_freelistN(&all_data);
-       
-       /* send notifier that things have changed */
-       WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-       
-       return OPERATOR_FINISHED;
-}
-
-static void ANIM_OT_channels_visibility_toggle(wmOperatorType *ot)
-{
-       /* identifiers */
-       ot->name = "Toggle Visibility";
-       ot->idname = "ANIM_OT_channels_visibility_toggle";
-       ot->description = "Toggle visibility in Graph Editor of all selected animation channels";
-       
-       /* api callbacks */
-       ot->exec = animchannels_visibility_toggle_exec;
-       ot->poll = ED_operator_graphedit_active;
-       
-       /* flags */
-       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
 /* ********************** Set Flags Operator *********************** */
 
 /* defines for setting animation-channel flags */
@@ -2145,7 +2119,7 @@ static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op))
                
                /* remove AnimData? */
                if (action_empty && nla_empty && drivers_empty) {
-                       BKE_free_animdata(id);
+                       BKE_animdata_free(id, true);
                }
        }
        
@@ -2334,7 +2308,7 @@ static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
                
        /* 'standard' behavior - check if selected, then apply relevant selection */
        if (RNA_boolean_get(op->ptr, "invert"))
-               ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_TOGGLE);
+               ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_INVERT);
        else
                ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_ADD);
        
@@ -2382,7 +2356,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec
        }
        else {
                ymin = 0.0f;
-               ymax = (float)(-ACHANNEL_HEIGHT);
+               ymax = (float)(-ACHANNEL_HEIGHT(ac));
        }
        
        /* convert border-region to view coordinates */
@@ -2398,7 +2372,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec
                if (ac->datatype == ANIMCONT_NLA)
                        ymin = ymax - NLACHANNEL_STEP(snla);
                else
-                       ymin = ymax - ACHANNEL_STEP;
+                       ymin = ymax - ACHANNEL_STEP(ac);
                
                /* if channel is within border-select region, alter it */
                if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
@@ -2524,12 +2498,13 @@ static void ANIM_OT_channels_select_border(wmOperatorType *ot)
 /* ******************* Rename Operator ***************************** */
 /* Allow renaming some channels by clicking on them */
 
-static void rename_anim_channels(bAnimContext *ac, int channel_index)
+static bool rename_anim_channels(bAnimContext *ac, int channel_index)
 {
        ListBase anim_data = {NULL, NULL};
-       bAnimChannelType *acf;
+       const bAnimChannelType *acf;
        bAnimListElem *ale;
        int filter;
+       bool success = false;
        
        /* get the channel that was clicked on */
        /* filter channels */
@@ -2544,7 +2519,7 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
                        printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", channel_index);
                
                ANIM_animdata_freelist(&anim_data);
-               return;
+               return false;
        }
        
        /* check that channel can be renamed */
@@ -2564,6 +2539,7 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
                         */
                        if (ac->ads) {
                                ac->ads->renameIndex = channel_index + 1;
+                               success = true;
                        }
                }
        }
@@ -2571,22 +2547,18 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
        /* free temp data and tag for refresh */
        ANIM_animdata_freelist(&anim_data);
        ED_region_tag_redraw(ac->ar);
+       return success;
 }
 
-static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static int animchannels_channel_get(bAnimContext *ac, const int mval[2])
 {
-       bAnimContext ac;
        ARegion *ar;
        View2D *v2d;
        int channel_index;
        float x, y;
        
-       /* get editor data */
-       if (ANIM_animdata_get_context(C, &ac) == 0)
-               return OPERATOR_CANCELLED;
-               
        /* get useful pointers from animation context data */
-       ar = ac.ar;
+       ar = ac->ar;
        v2d = &ar->v2d;
        
        /* figure out which channel user clicked in 
@@ -2594,20 +2566,36 @@ static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const
         *              so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
         *              ACHANNEL_HEIGHT_HALF.
         */
-       UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
+       UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
        
-       if (ac.datatype == ANIMCONT_NLA) {
-               SpaceNla *snla = (SpaceNla *)ac.sl;
+       if (ac->datatype == ANIMCONT_NLA) {
+               SpaceNla *snla = (SpaceNla *)ac->sl;
                UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index);
        }
        else {
-               UI_view2d_listview_view_to_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(ac), 0, (float)ACHANNEL_HEIGHT_HALF(ac), x, y, NULL, &channel_index);
        }
-       
+
+       return channel_index;
+}
+
+static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+       bAnimContext ac;
+       int channel_index;
+
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+
+       channel_index = animchannels_channel_get(&ac, event->mval);
+
        /* handle click */
-       rename_anim_channels(&ac, channel_index);
-       
-       return OPERATOR_FINISHED;
+       if (rename_anim_channels(&ac, channel_index))
+               return OPERATOR_FINISHED;
+       else
+               /* allow event to be handled by selectall operator */
+               return OPERATOR_PASS_THROUGH;
 }
 
 static void ANIM_OT_channels_rename(wmOperatorType *ot)
@@ -2717,6 +2705,10 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                        if ((adt) && (adt->flag & ADT_UI_SELECTED))
                                adt->flag |= ADT_UI_ACTIVE;
                        
+                       /* ensure we exit editmode on whatever object was active before to avoid getting stuck there - T48747 */
+                       if (ob != sce->obedit)
+                               ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
+                       
                        notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
                        break;
                }
@@ -2724,10 +2716,10 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
                case ANIMTYPE_DSLAM:
                case ANIMTYPE_DSCAM:
+               case ANIMTYPE_DSCACHEFILE:
                case ANIMTYPE_DSCUR:
                case ANIMTYPE_DSSKEY:
                case ANIMTYPE_DSWOR:
-               case ANIMTYPE_DSPART:
                case ANIMTYPE_DSMBALL:
                case ANIMTYPE_DSARM:
                case ANIMTYPE_DSMESH:
@@ -2736,6 +2728,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                case ANIMTYPE_DSLAT:
                case ANIMTYPE_DSLINESTYLE:
                case ANIMTYPE_DSSPK:
+               case ANIMTYPE_DSGPENCIL:
                {
                        /* sanity checking... */
                        if (ale->adt) {
@@ -2830,7 +2823,8 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                        notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
                        break;
                }
-               case ANIMTYPE_FCURVE: 
+               case ANIMTYPE_FCURVE:
+               case ANIMTYPE_NLACURVE:
                {
                        FCurve *fcu = (FCurve *)ale->data;
                        
@@ -2847,7 +2841,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                        
                        /* 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, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
+                               ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
                                
                        notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
                        break;
@@ -2870,6 +2864,19 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                        notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
                        break;
                }
+               case ANIMTYPE_NLACONTROLS:
+               {
+                       AnimData *adt = (AnimData *)ale->data;
+                       
+                       /* toggle expand
+                        *   - Although the triangle widget already allows this, since there's nothing else that can be done here now,
+                        *     let's just use it for easier expand/collapse for now
+                        */
+                       adt->flag ^= ADT_NLA_SKEYS_COLLAPSED;
+                       
+                       notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
+                       break;
+               }
                case ANIMTYPE_GPDATABLOCK:
                {
                        bGPdata *gpd = (bGPdata *)ale->data;
@@ -2897,7 +2904,13 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
                                gpl->flag |= GP_LAYER_SELECT;
                        }
                        
-                       notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
+                       /* change active layer, if this is selected (since we must always have an active layer) */
+                       if (gpl->flag & GP_LAYER_SELECT) {
+                               ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER);
+                       }
+                       
+                       WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); /* Grease Pencil updates */
+                       notifierFlags |= (ND_ANIMCHAN | NA_EDITED); /* Animation Ediotrs updates */
                        break;
                }
                case ANIMTYPE_MASKDATABLOCK:
@@ -2979,7 +2992,7 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmE
         *              ACHANNEL_HEIGHT_HALF.
         */
        UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
-       UI_view2d_listview_view_to_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(&ac), 0, (float)ACHANNEL_HEIGHT_HALF(&ac), x, y, NULL, &channel_index);
        
        /* handle mouse-click in the relevant channel then */
        notifierFlags = mouse_anim_channels(C, &ac, channel_index, selectmode);
@@ -3015,6 +3028,105 @@ static void ANIM_OT_channels_click(wmOperatorType *ot)
        RNA_def_property_flag(prop, PROP_SKIP_SAVE);
 }
 
+static bool select_anim_channel_keys(bAnimContext *ac, int channel_index, bool extend)
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       bool success = false;
+       FCurve *fcu;
+       int i;
+
+       /* get the channel that was clicked on */
+       /* filter channels */
+       filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+       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 */
+               if (G.debug & G_DEBUG)
+                       printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", channel_index);
+
+               ANIM_animdata_freelist(&anim_data);
+               return false;
+       }
+
+       fcu = (FCurve *)ale->key_data;
+       success = (fcu != NULL);
+
+       ANIM_animdata_freelist(&anim_data);
+
+       /* F-Curve may not have any keyframes */
+       if (fcu && fcu->bezt) {
+               BezTriple *bezt;
+
+               if (!extend) {
+                       filter = (ANIMFILTER_DATA_VISIBLE);
+                       ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+                       for (ale = anim_data.first; ale; ale = ale->next) {
+                               FCurve *fcu_inner = (FCurve *)ale->key_data;
+
+                               if (fcu_inner) {
+                                       for (i = 0, bezt = fcu_inner->bezt; i < fcu_inner->totvert; i++, bezt++) {
+                                               bezt->f2 = bezt->f1 = bezt->f3 = 0;
+                                       }
+                               }
+                       }
+
+                       ANIM_animdata_freelist(&anim_data);
+               }
+
+               for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+                       bezt->f2 = bezt->f1 = bezt->f3 = SELECT;
+               }
+       }
+
+       /* free temp data and tag for refresh */
+       ED_region_tag_redraw(ac->ar);
+       return success;
+}
+
+static int animchannels_channel_select_keys_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+       bAnimContext ac;
+       int channel_index;
+       bool extend = RNA_boolean_get(op->ptr, "extend");
+
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+
+       channel_index = animchannels_channel_get(&ac, event->mval);
+
+       /* handle click */
+       if (select_anim_channel_keys(&ac, channel_index, extend)) {
+               WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
+               return OPERATOR_FINISHED;
+       }
+       else
+               /* allow event to be handled by selectall operator */
+               return OPERATOR_PASS_THROUGH;
+}
+
+static void ANIM_OT_channel_select_keys(wmOperatorType *ot)
+{
+       PropertyRNA *prop;
+
+       /* identifiers */
+       ot->name = "Select Channel keyframes";
+       ot->idname = "ANIM_OT_channel_select_keys";
+       ot->description = "Select all keyframes of channel under mouse";
+
+       /* api callbacks */
+       ot->invoke = animchannels_channel_select_keys_invoke;
+       ot->poll = animedit_poll_channels_active;
+
+       prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection");
+       RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
 /* ************************************************************************** */
 /* Operator Registration */
 
@@ -3024,8 +3136,9 @@ void ED_operatortypes_animchannels(void)
        WM_operatortype_append(ANIM_OT_channels_select_border);
        
        WM_operatortype_append(ANIM_OT_channels_click);
+       WM_operatortype_append(ANIM_OT_channel_select_keys);
        WM_operatortype_append(ANIM_OT_channels_rename);
-       
+
        WM_operatortype_append(ANIM_OT_channels_find);
        
        WM_operatortype_append(ANIM_OT_channels_setting_enable);
@@ -3042,9 +3155,6 @@ void ED_operatortypes_animchannels(void)
        WM_operatortype_append(ANIM_OT_channels_expand);
        WM_operatortype_append(ANIM_OT_channels_collapse);
        
-       WM_operatortype_append(ANIM_OT_channels_visibility_toggle);
-       WM_operatortype_append(ANIM_OT_channels_visibility_set);
-       
        WM_operatortype_append(ANIM_OT_channels_fcurves_enable);
        
        WM_operatortype_append(ANIM_OT_channels_clean_empty);
@@ -3068,7 +3178,9 @@ void ED_keymap_animchannels(wmKeyConfig *keyconf)
        /* rename */
        WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
        WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
-       
+       WM_keymap_add_item(keymap, "ANIM_OT_channel_select_keys", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channel_select_keys", LEFTMOUSE, KM_DBL_CLICK, KM_SHIFT, 0)->ptr, "extend", true);
+
        /* find (i.e. a shortcut for setting the name filter) */
        WM_keymap_add_item(keymap, "ANIM_OT_channels_find", FKEY, KM_PRESS, KM_CTRL, 0);
        
@@ -3110,10 +3222,6 @@ void ED_keymap_animchannels(wmKeyConfig *keyconf)
        /* grouping */
        WM_keymap_add_item(keymap, "ANIM_OT_channels_group", GKEY, KM_PRESS, KM_CTRL, 0);
        WM_keymap_add_item(keymap, "ANIM_OT_channels_ungroup", GKEY, KM_PRESS, KM_ALT, 0);
-       
-       /* Graph Editor only */
-       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);
 }
 
 /* ************************************************************************** */