DopeSheet: DopeSheet Summary Channel
authorJoshua Leung <aligorith@gmail.com>
Tue, 13 Oct 2009 11:21:02 +0000 (11:21 +0000)
committerJoshua Leung <aligorith@gmail.com>
Tue, 13 Oct 2009 11:21:02 +0000 (11:21 +0000)
Added a summary channel that appears as the first channel in the DopeSheet. For now, this is disabled by default, but can be enabled using the 'Summary' toggle in the header between the mode selector and the standard filtering options. This has been done, since there is a possibility that it will make the DopeSheet run a bit slower.

In this channel you can do everything that you can normally do with DopeSheet channels (i.e. select, transform, edit, etc). It might be worth noting though that care probably needs to be taken when trying to use Copy/Paste, since that is still a bit fidgety...

In the process, I've fixed a few bugs, mostly with selection:
- Selecting keyframes in scene summaries wouldn't work
- Border select only worked in F-Curve and Group channels

source/blender/editors/animation/anim_channels_defines.c
source/blender/editors/animation/anim_filter.c
source/blender/editors/animation/keyframes_draw.c
source/blender/editors/animation/keyframes_edit.c
source/blender/editors/include/ED_anim_api.h
source/blender/editors/include/ED_keyframes_draw.h
source/blender/editors/space_action/action_draw.c
source/blender/editors/space_action/action_header.c
source/blender/editors/space_action/action_select.c
source/blender/makesdna/DNA_action_types.h

index 427fa47923f6f590f64a5fc2d0ec686a506f4a03..a4423d43339e3aa1ba5874a1698fc2857f9e6948 100644 (file)
@@ -280,6 +280,12 @@ static void acf_generic_idblock_name(bAnimListElem *ale, char *name)
 
 /* Settings ------------------------------------------- */
 
+/* channel type has no settings */
+static short acf_generic_none_setting_valid(bAnimContext *ac, bAnimListElem *ale, int setting)
+{
+       return 0;
+}
+
 /* check if some setting exists for this object-based data-expander (category only) */
 static short acf_generic_dsexpand_setting_valid(bAnimContext *ac, bAnimListElem *ale, int setting)
 {
@@ -335,6 +341,52 @@ static short acf_generic_dataexpand_setting_valid(bAnimContext *ac, bAnimListEle
 /* *********************************************** */
 /* Type Specific Functions + Defines */
 
+/* Animation Summary ----------------------------------- */
+
+/* backdrop for summary widget */
+static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
+{
+       View2D *v2d= &ac->ar->v2d;
+       
+       // FIXME: hardcoded color - same as the 'action' line in NLA
+       glColor3f(0.8f, 0.2f, 0.0f);    // reddish color 
+       
+       /* rounded corners on LHS only 
+        *      - top and bottom 
+        *      - special hack: make the top a bit higher, since we are first... 
+        */
+       uiSetRoundBox((1|8));
+       gl_round_box(GL_POLYGON, 0,  yminc-2, v2d->cur.xmax+EXTRA_SCROLL_PAD, ymaxc, 8);
+}
+
+/* name for summary entries */
+static void acf_summary_name(bAnimListElem *ale, char *name)
+{
+       if (name)
+               strcpy(name, "DopeSheet Summary");
+}
+
+// TODO: this is really a temp icon I think
+static int acf_summary_icon(bAnimListElem *ale)
+{
+       return ICON_BORDERMOVE;
+}
+
+/* all animation summary (DopeSheet only) type define */
+static bAnimChannelType ACF_SUMMARY = 
+{
+       acf_summary_backdrop,                           /* backdrop */
+       acf_generic_indention_0,                        /* indent level */
+       NULL,                                                           /* offset */
+       
+       acf_summary_name,                                       /* name */
+       acf_summary_icon,                                       /* icon */
+       
+       acf_generic_none_setting_valid,         /* has setting */
+       NULL,                                                           /* flag for setting */
+       NULL                                                            /* pointer for setting */
+};
+
 /* Scene ------------------------------------------- */
 
 // TODO: just get this from RNA?
@@ -1803,6 +1855,8 @@ void ANIM_init_channel_typeinfo_data (void)
                animchannelTypeInfo[type++]= NULL;                              /* AnimData */
                animchannelTypeInfo[type++]= NULL;                              /* Special */
                
+               animchannelTypeInfo[type++]= &ACF_SUMMARY;              /* Motion Summary */
+               
                animchannelTypeInfo[type++]= &ACF_SCENE;                /* Scene */
                animchannelTypeInfo[type++]= &ACF_OBJECT;               /* Object */
                animchannelTypeInfo[type++]= &ACF_GROUP;                /* Group */
index fef910a85a302a74e0c8e9750261de8f36a6d0b5..7aba237ffb1ce76fec852e5883a63f4bb2eca37f 100644 (file)
@@ -458,6 +458,16 @@ bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, s
                
                /* do specifics */
                switch (datatype) {
+                       case ANIMTYPE_SUMMARY:
+                       {
+                               /* nothing to include for now... this is just a dummy wrappy around all the other channels 
+                                * in the DopeSheet, and gets included at the start of the list
+                                */
+                               ale->key_data= NULL;
+                               ale->datatype= ALE_ALL;
+                       }
+                               break;
+                       
                        case ANIMTYPE_SCENE:
                        {
                                Scene *sce= (Scene *)data;
@@ -1497,7 +1507,7 @@ static int animdata_filter_dopesheet_scene (ListBase *anim_data, bDopeSheet *ads
 }
 
 // TODO: implement pinning... (if and when pinning is done, what we need to do is to provide freeing mechanisms - to protect against data that was deleted)
-static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int filter_mode)
+static int animdata_filter_dopesheet (ListBase *anim_data, bAnimContext *ac, bDopeSheet *ads, int filter_mode)
 {
        Scene *sce= (Scene *)ads->source;
        Base *base;
@@ -1510,6 +1520,21 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int
                return 0;
        }
        
+       /* dopesheet summary 
+        *      - only for drawing and/or selecting keyframes in channels, but not for real editing 
+        *      - only useful for DopeSheet Editor, where the summary is useful
+        */
+       // TODO: we should really check if some other prohibited filters are also active, but that can be for later
+       if ((filter_mode & ANIMFILTER_CHANNELS) && (ads->filterflag & ADS_FILTER_SUMMARY)) {
+               ale= make_new_animlistelem(ac, ANIMTYPE_SUMMARY, NULL, ANIMTYPE_NONE, NULL);
+               if (ale) {
+                       BLI_addtail(anim_data, ale);
+                       items++;
+               }
+               
+               // TODO: if the summary gets a collapse widget, then we could make the other stuff not get shown... 
+       }
+       
        /* scene-linked animation */
        // TODO: sequencer, composite nodes - are we to include those here too?
        {
@@ -1898,7 +1923,7 @@ int ANIM_animdata_filter (bAnimContext *ac, ListBase *anim_data, int filter_mode
                        case ANIMCONT_FCURVES:
                        case ANIMCONT_DRIVERS:
                        case ANIMCONT_NLA:
-                               items= animdata_filter_dopesheet(anim_data, data, filter_mode);
+                               items= animdata_filter_dopesheet(anim_data, ac, data, filter_mode);
                                break;
                }
                        
index d0b5e12c9dff2658d4c6b1c439499edc7c36e3de..019ece64132d976256722a282c683805691974fc 100644 (file)
@@ -515,6 +515,24 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa
 
 /* *************************** Channel Drawing Funcs *************************** */
 
+void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos)
+{
+       DLRBT_Tree keys, blocks;
+       
+       BLI_dlrbTree_init(&keys);
+       BLI_dlrbTree_init(&blocks);
+       
+               summary_to_keylist(ac, &keys, &blocks);
+       
+       BLI_dlrbTree_linkedlist_sync(&keys);
+       BLI_dlrbTree_linkedlist_sync(&blocks);
+       
+               draw_keylist(v2d, &keys, &blocks, ypos);
+       
+       BLI_dlrbTree_free(&keys);
+       BLI_dlrbTree_free(&blocks);
+}
+
 void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos)
 {
        DLRBT_Tree keys, blocks;
@@ -622,6 +640,25 @@ void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos)
 
 /* *************************** Keyframe List Conversions *************************** */
 
+void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, DLRBT_Tree *blocks)
+{
+       if (ac) {
+               ListBase anim_data = {NULL, NULL};
+               bAnimListElem *ale;
+               int filter;
+               
+               /* get F-Curves to take keyframes from */
+               filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
+               ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+               
+               /* loop through each F-Curve, grabbing the keyframes */
+               for (ale= anim_data.first; ale; ale= ale->next)
+                       fcurve_to_keylist(ale->adt, ale->data, keys, blocks);
+               
+               BLI_freelistN(&anim_data);
+       }
+}
+
 void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, DLRBT_Tree *blocks)
 {
        if (sce) {
index 7f0d3b4503d2642fa3dc3b3a32b4f2c8b33603bd..3b2830e9045790a873b5adf88ff75adab19bfc03 100644 (file)
@@ -310,16 +310,48 @@ static short scene_keys_bezier_loop(BeztEditData *bed, Scene *sce, BeztEditFunc
                return 0;
        
        /* Scene's own animation */
-       if (sce->adt)
-               adt_keys_bezier_loop(bed, sce->adt, bezt_ok, bezt_cb, fcu_cb, filterflag);
+       if (sce->adt) {
+               if (adt_keys_bezier_loop(bed, sce->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
+                       return 1;
+       }
        
        /* World */
-       if (wo && wo->adt)
-               adt_keys_bezier_loop(bed, wo->adt, bezt_ok, bezt_cb, fcu_cb, filterflag);
+       if (wo && wo->adt) {
+               if (adt_keys_bezier_loop(bed, wo->adt, bezt_ok, bezt_cb, fcu_cb, filterflag))
+                       return 1;
+       }
        
        return 0;
 }
 
+/* This function is used to loop over the keyframe data in a DopeSheet summary */
+static short summary_keys_bezier_loop(BeztEditData *bed, bAnimContext *ac, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter, ret_code=0;
+       
+       /* sanity check */
+       if (ac == NULL)
+               return 0;
+       
+       /* get F-Curves to take keyframes from */
+       filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
+       ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+       
+       /* loop through each F-Curve, working on the keyframes until the first curve aborts */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               ret_code= ANIM_fcurve_keys_bezier_loop(bed, ale->data, bezt_ok, bezt_cb, fcu_cb);
+               
+               if (ret_code)
+                       break;
+       }
+       
+       BLI_freelistN(&anim_data);
+       
+       return ret_code;
+}
+
 /* --- */
 
 /* This function is used to apply operation to all keyframes, regardless of the type */
@@ -347,6 +379,8 @@ short ANIM_animchannel_keys_bezier_loop(BeztEditData *bed, bAnimListElem *ale, B
                        return ob_keys_bezier_loop(bed, (Object *)ale->key_data, bezt_ok, bezt_cb, fcu_cb, filterflag);
                case ALE_SCE: /* scene */
                        return scene_keys_bezier_loop(bed, (Scene *)ale->data, bezt_ok, bezt_cb, fcu_cb, filterflag);
+               case ALE_ALL: /* 'all' (DopeSheet summary) */
+                       return summary_keys_bezier_loop(bed, (bAnimContext *)ale->data, bezt_ok, bezt_cb, fcu_cb, filterflag);
        }
        
        return 0;
@@ -377,6 +411,8 @@ short ANIM_animchanneldata_keys_bezier_loop(BeztEditData *bed, void *data, int k
                        return ob_keys_bezier_loop(bed, (Object *)data, bezt_ok, bezt_cb, fcu_cb, filterflag);
                case ALE_SCE: /* scene */
                        return scene_keys_bezier_loop(bed, (Scene *)data, bezt_ok, bezt_cb, fcu_cb, filterflag);
+               case ALE_ALL: /* 'all' (DopeSheet summary) */
+                       return summary_keys_bezier_loop(bed, (bAnimContext *)data, bezt_ok, bezt_cb, fcu_cb, filterflag);
        }
        
        return 0;
index 97f4dd915e4396c892a87a6cd53a91218956ec79..271827c2aba9bac6fcb43deaae005cf062fc2ad7 100644 (file)
@@ -122,6 +122,8 @@ typedef enum eAnim_ChannelType {
        ANIMTYPE_ANIMDATA,
        ANIMTYPE_SPECIALDATA,
        
+       ANIMTYPE_SUMMARY,
+       
        ANIMTYPE_SCENE,
        ANIMTYPE_OBJECT,
        ANIMTYPE_GROUP,
@@ -161,6 +163,7 @@ typedef enum eAnim_KeyType {
        ALE_GPFRAME,            /* Grease Pencil Frames */
        ALE_NLASTRIP,           /* NLA Strips */
        
+       ALE_ALL,                        /* All channels summary */
        ALE_SCE,                        /* Scene summary */
        ALE_OB,                         /* Object summary */
        ALE_ACT,                        /* Action summary */
@@ -184,6 +187,9 @@ typedef enum eAnimFilter_Flags {
        ANIMFILTER_ANIMDATA             = (1<<9),       /* only return the underlying AnimData blocks (not the tracks, etc.) data comes from */
        ANIMFILTER_NLATRACKS    = (1<<10),      /* only include NLA-tracks */
        ANIMFILTER_SELEDIT              = (1<<11),      /* link editability with selected status */
+       
+       /* all filters - the power inside the bracket must be the last power for left-shifts + 1 */
+       ANIMFILTER_ALLFILTERS   = ((1<<12) - 1)
 } eAnimFilter_Flags;
 
 
index 51d7c664fba203bd847608b3dbb7b204ff698623..699502eb9ebb795bbae76b1ec338b5938b2bf64f 100644 (file)
@@ -30,6 +30,7 @@
 #ifndef ED_KEYFRAMES_DRAW_H
 #define ED_KEYFRAMES_DRAW_H
 
+struct bAnimContext;
 struct AnimData;
 struct BezTriple;
 struct FCurve;
@@ -109,6 +110,7 @@ void draw_agroup_channel(struct View2D *v2d, struct AnimData *adt, struct bActio
 void draw_action_channel(struct View2D *v2d, struct AnimData *adt, struct bAction *act, float ypos);
 void draw_object_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Object *ob, float ypos);
 void draw_scene_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Scene *sce, float ypos);
+void draw_summary_channel(struct View2D *v2d, struct bAnimContext *ac, float ypos);
 void draw_gpl_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPDlayer *gpl, float ypos);
 
 /* Keydata Generation */
@@ -117,6 +119,7 @@ void agroup_to_keylist(struct AnimData *adt, struct bActionGroup *agrp, struct D
 void action_to_keylist(struct AnimData *adt, struct bAction *act, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
 void ob_to_keylist(struct bDopeSheet *ads, struct Object *ob, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
 void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
+void summary_to_keylist(struct bAnimContext *ac, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
 void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
 
 /* Keyframe Finding */
index 4288cc10a26c45992d71eb469f7f662ed2f6b254..7181a6b5aa1b3a9a4c4512b1b5e7d6815c96284e 100644 (file)
@@ -260,6 +260,13 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
                                
                                if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)) {
                                        switch (ale->type) {
+                                               case ANIMTYPE_SUMMARY:
+                                               {
+                                                       // FIXME: hardcoded colours - reddish color from NLA
+                                                       glColor4f(0.8f, 0.2f, 0.0f, 0.4f);
+                                               }
+                                                       break;
+                                               
                                                case ANIMTYPE_SCENE:
                                                case ANIMTYPE_OBJECT:
                                                {
@@ -351,6 +358,9 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
                                
                                /* draw 'keyframes' for each specific datatype */
                                switch (ale->datatype) {
+                                       case ALE_ALL:
+                                               draw_summary_channel(v2d, ale->data, y);
+                                               break;
                                        case ALE_SCE:
                                                draw_scene_channel(v2d, ads, ale->key_data, y);
                                                break;
index e0d952c29c1230e2eea0e44fd3eca6ab742c22a2..2468bdf311c85db2c8dba6d6ce9c9af014f635f2 100644 (file)
@@ -331,8 +331,11 @@ void action_header_buttons(const bContext *C, ARegion *ar)
                /* MODE-DEPENDENT DRAWING */
                if (saction->mode == SACTCONT_DOPESHEET) {
                        /* FILTERING OPTIONS */
-                       xco -= 10;
+                               /* DopeSheet summary...  */
+                       uiDefIconTextButBitI(block, TOG, ADS_FILTER_SUMMARY, B_REDR, ICON_BORDERMOVE, "Summary", xco,yco,XIC*4,YIC, &(saction->ads.filterflag), 0, 0, 0, 0, "Include DopeSheet summary row"); // TODO: needs a better icon
+                       xco += (XIC*3.5);
                        
+                               /* Standard filtering... */
                        xco= ANIM_headerUI_standard_buttons(C, &saction->ads, block, xco, yco);
                }
                else if (saction->mode == SACTCONT_ACTION) {
index e358f559b14b0c88676195a2b3a6b676a7af58c9..c945f41bc557388eec1e1bc93527102934a1d1fb 100644 (file)
@@ -219,7 +219,7 @@ static void borderselect_action (bAnimContext *ac, rcti rect, short mode, short
 {
        ListBase anim_data = {NULL, NULL};
        bAnimListElem *ale;
-       int filter;
+       int filter, filterflag;
        
        BeztEditData bed;
        BeztEditFunc ok_cb, select_cb;
@@ -235,6 +235,14 @@ static void borderselect_action (bAnimContext *ac, rcti rect, short mode, short
        filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
        ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
        
+       /* get filtering flag for dopesheet data (if applicable) */
+       if (ac->datatype == ANIMCONT_DOPESHEET) {
+               bDopeSheet *ads= (bDopeSheet *)ac->data;
+               filterflag= ads->filterflag;
+       }
+       else
+               filterflag= 0;
+       
        /* get beztriple editing/validation funcs  */
        select_cb= ANIM_editkeyframes_select(selectmode);
        
@@ -271,20 +279,10 @@ static void borderselect_action (bAnimContext *ac, rcti rect, short mode, short
                        !((ymax < rectf.ymin) || (ymin > rectf.ymax)) )
                {
                        /* loop over data selecting */
-                       if (ale->key_data) {
-                               if (ale->datatype == ALE_FCURVE)
-                                       ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
-                       }
-                       else if (ale->type == ANIMTYPE_GROUP) {
-                               bActionGroup *agrp= ale->data;
-                               FCurve *fcu;
-                               
-                               for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next) 
-                                       ANIM_fcurve_keys_bezier_loop(&bed, fcu, ok_cb, select_cb, NULL);
-                       }
-                       //else if (ale->type == ANIMTYPE_GPLAYER) {
+                       //if (ale->type == ANIMTYPE_GPLAYER)
                        //      borderselect_gplayer_frames(ale->data, rectf.xmin, rectf.xmax, selectmode);
-                       //}
+                       //else
+                               ANIM_animchannel_keys_bezier_loop(&bed, ale, ok_cb, select_cb, NULL, filterflag);
                }
                
                /* set minimum extent to be the maximum of the next channel */
@@ -792,6 +790,12 @@ static void mouse_action_keys (bAnimContext *ac, int mval[2], short select_mode,
                
                if (ale->key_data) {
                        switch (ale->datatype) {
+                               case ALE_SCE:
+                               {
+                                       Scene *scene= (Scene *)ale->key_data;
+                                       scene_to_keylist(ads, scene, &anim_keys, NULL);
+                               }
+                                       break;
                                case ALE_OB:
                                {
                                        Object *ob= (Object *)ale->key_data;
@@ -812,6 +816,10 @@ static void mouse_action_keys (bAnimContext *ac, int mval[2], short select_mode,
                                        break;
                        }
                }
+               else if (ale->type == ANIMTYPE_SUMMARY) {
+                       /* dopesheet summary covers everything */
+                       summary_to_keylist(ac, &anim_keys, NULL);
+               }
                else if (ale->type == ANIMTYPE_GROUP) {
                        bActionGroup *agrp= (bActionGroup *)ale->data;
                        agroup_to_keylist(adt, agrp, &anim_keys, NULL);
index e2eb13f0bdf15b2678e105ed53d97682aa3114af..a011ba879487c526840e1b06b10feaa01e4818c3 100644 (file)
@@ -422,6 +422,7 @@ typedef enum DOPESHEET_FILTERFLAG {
        ADS_FILTER_ONLYDRIVERS          = (1<<1),       /* for 'Drivers' editor - only include Driver data from AnimData */
        ADS_FILTER_ONLYNLA                      = (1<<2),       /* for 'NLA' editor - only include NLA data from AnimData */
        ADS_FILTER_SELEDIT                      = (1<<3),       /* for Graph Editor - used to indicate whether to include a filtering flag or not */
+       ADS_FILTER_SUMMARY                      = (1<<4),       /* for 'DopeSheet' Editor - include 'summary' line */
        
                /* datatype-based filtering */
        ADS_FILTER_NOSHAPEKEYS          = (1<<6),