Durian Requests for Graph Editor Visibility Toggles (2):
authorJoshua Leung <aligorith@gmail.com>
Mon, 30 Nov 2009 11:10:03 +0000 (11:10 +0000)
committerJoshua Leung <aligorith@gmail.com>
Mon, 30 Nov 2009 11:10:03 +0000 (11:10 +0000)
Improved the hotkeys for toggling the visibility of channels in the keys area for the Graph Editor.

* VKEY - this is now used for making only the selected channels visible, hiding everything else
* Shift-VKEY - the old toggling behaviour

In addition to this, I've made these toggling operators flush the visibility flags up/down the hierarchy, just like clicking on the channels manually do. There are still a few minor oddities to iron out, but it should be better than before.

Also, fixed a bug with these toggling operators introduced during my earlier commit to make filtering work ok. It's always tricky getting these layers of checks just right, so hopefully nothing breaks now again...

source/blender/editors/animation/anim_channels_defines.c
source/blender/editors/animation/anim_channels_edit.c
source/blender/editors/animation/anim_filter.c
source/blender/editors/include/ED_anim_api.h

index 24a8fb445c7841938e5478e2d34333c8c61bb24b..c3044e03a2f5343ffaa63595d4294a58368072ef 100644 (file)
@@ -2340,13 +2340,10 @@ static void achannel_setting_widget_cb(bContext *C, void *poin, void *poin2)
 static void achannel_setting_visible_widget_cb(bContext *C, void *ale_npoin, void *dummy_poin)
 {
        bAnimListElem *ale_setting= (bAnimListElem *)ale_npoin;
-       int prevLevel=0, matchLevel=0;
-       short vizOn = 0;
-       
        bAnimContext ac;
        ListBase anim_data = {NULL, NULL};
-       bAnimListElem *ale, *match=NULL;
        int filter;
+       short vizOn = 0;
        
        /* send notifiers before doing anything else... */
        WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN_EDIT, NULL);
@@ -2374,91 +2371,8 @@ static void achannel_setting_visible_widget_cb(bContext *C, void *ale_npoin, voi
        filter= ANIMFILTER_CHANNELS;
        ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
        
-       /* 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");
-               BLI_freelistN(&anim_data);
-               return;
-       }
-       else {
-               bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale_setting);
-               
-               /* 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;
-       }
-       
-       /* flush up? 
-        *      - only flush up if the current state is now enabled 
-        *        (otherwise, it's too much work to force the parents to be inactive too)
-        */
-       if (vizOn) {
-               /* 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;
-                       
-                       /* 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 previous channel, 
-                        * flush the new status...
-                        */
-                       if (level < matchLevel)
-                               ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, vizOn);
-                       /* 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;
-                       
-                       /* 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, ACHANNEL_SETTING_VISIBLE, vizOn);
-                       /* 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;
-               }
-       }
+       /* call API method to flush the setting */
+       ANIM_visibility_flush_anim_channels(&ac, &anim_data, ale_setting, vizOn);
        
        /* free temp data */
        BLI_freelistN(&anim_data);
index 01ab7bd530c33cc1346a1bd2fc28b0b7069cc22d..e4ce26b615600cf2f917e9cc8bcb3c8a5246eb71 100644 (file)
@@ -352,6 +352,106 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short
        BLI_freelistN(&anim_data);
 }
 
+/* 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 
+ *     - vizOn: whether the visibility setting has been enabled or disabled 
+ */
+void ANIM_visibility_flush_anim_channels (bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, short vizOn)
+{
+       bAnimListElem *ale, *match=NULL;
+       int prevLevel=0, matchLevel=0;
+       
+       /* 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);
+               
+               /* 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;
+       }
+       
+       /* flush up? 
+        *      - only flush up if the current state is now enabled 
+        *        (otherwise, it's too much work to force the parents to be inactive too)
+        */
+       if (vizOn) {
+               /* 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;
+                       
+                       /* 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, ACHANNEL_SETTING_VISIBLE, vizOn);
+                       /* 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;
+                       
+                       /* 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, ACHANNEL_SETTING_VISIBLE, vizOn);
+                       /* 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;
+               }
+       }
+}
+
 /* ************************************************************************** */
 /* OPERATORS */
 
@@ -895,12 +995,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_visibility_flush_anim_channels(&ac, &all_data, ale, 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;
@@ -909,6 +1084,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);
@@ -922,14 +1101,19 @@ static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *op)
                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) {
+               /* change the setting */
                ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, vis);
+               
+               /* now, also flush selection status up/down as appropriate */
+               //ANIM_visibility_flush_anim_channels(&ac, &all_data, ale, (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);
@@ -1696,6 +1880,7 @@ 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(wmKeyConfig *keyconf)
@@ -1742,7 +1927,8 @@ void ED_keymap_animchannels(wmKeyConfig *keyconf)
        //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);
 }
 
 /* ************************************************************************** */
index 6586317b6dcca99971613e0826192ae45345038e..544157c40305e3d1f38712143c6c765bd49d396c 100644 (file)
@@ -859,10 +859,16 @@ static int animdata_filter_action (ListBase *anim_data, bDopeSheet *ads, bAction
                /* get the first F-Curve in this group we can start to use, 
                 * and if there isn't any F-Curve to start from, then don't 
                 * this group at all...
+                *
+                * exceptions for when we might not care whether there's anything inside this group or not
+                *      - if we're interested in channels and their selections, in which case group channel should get considered too
+                *        even if all its sub channels are hidden...
                 */
                first_fcu = animdata_filter_fcurve_next(ads, agrp->channels.first, agrp, filter_mode, owner_id);
                
-               if (first_fcu) {
+               if ( (filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) ||
+                        (first_fcu) ) 
+               {
                        /* add this group as a channel first */
                        if ((filter_mode & ANIMFILTER_CHANNELS) || !(filter_mode & ANIMFILTER_CURVESONLY)) {
                                /* check if filtering by selection */
@@ -1806,7 +1812,7 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bAnimContext *ac, bDo
                        /* additionally, dopesheet filtering also affects what objects to consider */
                        if (ads->filterflag) {
                                /* check selection and object type filters */
-                               if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) || (base == sce->basact)) )  {
+                               if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/) )  {
                                        /* only selected should be shown */
                                        continue;
                                }
index 59efa01cc35d3c27175115b77e3f59afa30ac533..8a73e12f39bb5dad692f0913dd94336b27bb2cf4 100644 (file)
@@ -377,6 +377,17 @@ short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, int setting
 void ANIM_channel_setting_set(bAnimContext *ac, bAnimListElem *ale, int setting, short mode);
 
 
+/* 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 
+ *     - vizOn: whether the visibility setting has been enabled or disabled 
+ */
+void ANIM_visibility_flush_anim_channels(bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, short vizOn);
+
+
 /* Deselect all animation channels */
 void ANIM_deselect_anim_channels(void *data, short datatype, short test, short sel);