Nla Strip Controls: Added dedicated "Expander" channel to Action/Graph Editors
authorJoshua Leung <aligorith@gmail.com>
Sat, 21 Mar 2015 13:46:51 +0000 (02:46 +1300)
committerJoshua Leung <aligorith@gmail.com>
Sat, 28 Mar 2015 12:39:55 +0000 (01:39 +1300)
The "Nla Strip Controls" channel is used to house the per-strip
FCurves for controlling the strip_time and influence properties.
It sits above the active action's first group, at the same level
in the hierarchy as other groups.

TODO: It looks like a dedicated FCurve channel is needed for these
control FCurves, so that we won't accidentally apply NLA mapping
or have these FCurves disabled by the path lookups failing.

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

index 37c40052275373e2a3f671b06c15353b72370877..11d68ed6f755d3bdcbd71561151dec1fbf348eed 100644 (file)
@@ -908,6 +908,106 @@ static bAnimChannelType ACF_GROUP =
        acf_group_setting_ptr           /* pointer for setting */
 };
 
+/* NLA Control FCurves Expander ----------------------- */
+
+/* get backdrop color for nla controls widget */
+static void acf_nla_controls_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), float r_color[3])
+{
+       // TODO: give this its own theme setting?
+       UI_GetThemeColorShade3fv(TH_GROUP, 55, r_color);
+}
+
+/* backdrop for nla controls expander widget */
+static void acf_nla_controls_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
+{
+       bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
+       View2D *v2d = &ac->ar->v2d;
+       short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0;
+       short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
+       float color[3];
+       
+       /* set backdrop drawing color */
+       acf->get_backdrop_color(ac, ale, color);
+       glColor3fv(color);
+       
+       /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */
+       UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
+       UI_draw_roundbox_gl_mode(GL_POLYGON, offset,  yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 5);
+}
+
+/* name for nla controls expander entries */
+static void acf_nla_controls_name(bAnimListElem *ale, char *name)
+{
+       BLI_strncpy(name, IFACE_("NLA Strip Controls"), ANIM_CHAN_NAME_SIZE);
+}
+
+/* check if some setting exists for this channel */
+static bool acf_nla_controls_setting_valid(bAnimContext *ac, bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting)
+{
+       /* for now, all settings are supported, though some are only conditionally */
+       switch (setting) {
+               /* supported */
+               case ACHANNEL_SETTING_EXPAND:
+                       return true;
+               
+               // TOOD: selected?
+               
+               default: /* unsupported */
+                       return false;
+       }
+}
+
+/* get the appropriate flag(s) for the setting when it is valid  */
+static int acf_nla_controls_setting_flag(bAnimContext *ac, eAnimChannel_Settings setting, bool *neg)
+{
+       /* clear extra return data first */
+       *neg = false;
+       
+       switch (setting) {
+               case ACHANNEL_SETTING_EXPAND: /* expanded */
+                       *neg = true;
+                       return ADT_NLA_SKEYS_COLLAPSED;
+               
+               default:
+                       /* this shouldn't happen */
+                       return 0;
+       }
+}
+
+/* get pointer to the setting */
+static void *acf_nla_controls_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings UNUSED(setting), short *type)
+{
+       AnimData *adt = (AnimData *)ale->data;
+       
+       /* all flags are just in adt->flag for now... */
+       return GET_ACF_FLAG_PTR(adt->flag, type);
+}
+
+static int acf_nla_controls_icon(bAnimListElem *UNUSED(ale))
+{
+       return ICON_NLA;
+}
+
+/* NLA Control FCurves Expander type define */
+static bAnimChannelType ACF_NLACONTROLS = 
+{
+       "NLA Controls Expander",        /* type name */
+       ACHANNEL_ROLE_EXPANDER,         /* role */
+       
+       acf_nla_controls_color,         /* backdrop color */
+       acf_nla_controls_backdrop,      /* backdrop */
+       acf_generic_indention_0,        /* indent level */
+       acf_generic_group_offset,       /* offset */
+
+       acf_nla_controls_name,          /* name */
+       NULL,                           /* name prop */
+       acf_nla_controls_icon,          /* icon */
+
+       acf_nla_controls_setting_valid, /* has setting */
+       acf_nla_controls_setting_flag,  /* flag for setting */
+       acf_nla_controls_setting_ptr    /* pointer for setting */
+};
+
 /* F-Curve ------------------------------------------- */
 
 /* name for fcurve entries */
@@ -3222,6 +3322,8 @@ static void ANIM_init_channel_typeinfo_data(void)
                animchannelTypeInfo[type++] = &ACF_GROUP;        /* Group */
                animchannelTypeInfo[type++] = &ACF_FCURVE;       /* F-Curve */
                
+               animchannelTypeInfo[type++] = &ACF_NLACONTROLS;  /* NLA Control FCurve Expander */
+               
                animchannelTypeInfo[type++] = &ACF_FILLACTD;     /* Object Action Expander */
                animchannelTypeInfo[type++] = &ACF_FILLDRIVERS;  /* Drivers Expander */
                
index d6daa64a9f22e9c46f3781b82a216895aefd3993..b5d1de9c7d60e373b908918c73c53bd45bca6759 100644 (file)
@@ -423,6 +423,7 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
  *  - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA)
  *  - nlaOk: line or block of code to execute for NLA tracks+strips case
  *  - driversOk: line or block of code to execute for Drivers case
+ *  - nlaKeysOk: line or block of code for NLA Strip Keyframes case
  *  - keysOk: line or block of code for Keyframes case
  *
  * The checks for the various cases are as follows:
@@ -433,9 +434,10 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
  *             converted to a new NLA strip, and the filtering options allow this
  *     2C) allow non-animated datablocks to be included so that datablocks can be added
  *     3) drivers: include drivers from animdata block (for Drivers mode in Graph Editor)
- *     4) normal keyframes: only when there is an active action
+ *  4A) nla strip keyframes: these are the per-strip controls for time and influence
+ *     4B) normal keyframes: only when there is an active action
  */
-#define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, keysOk) \
+#define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, nlaKeysOk, keysOk) \
        { \
                if ((id)->adt) { \
                        if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) { \
@@ -456,6 +458,9 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
                                        } \
                                } \
                                else { \
+                                       if (ANIMDATA_HAS_NLA(id)) { \
+                                               nlaKeysOk \
+                                       } \
                                        if (ANIMDATA_HAS_KEYS(id)) { \
                                                keysOk \
                                        } \
@@ -786,6 +791,16 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
                                ale->adt = BKE_animdata_from_id(data);
                                break;
                        }
+                       case ANIMTYPE_NLACONTROLS:
+                       {
+                               AnimData *adt = (AnimData *)data;
+                               
+                               ale->flag = adt->flag;
+                               
+                               ale->key_data = NULL;
+                               ale->datatype = ALE_NONE;
+                               break;
+                       }
                        case ANIMTYPE_GROUP:
                        {
                                bActionGroup *agrp = (bActionGroup *)data;
@@ -1305,6 +1320,52 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
        return items;
 }
 
+/* Include the control FCurves per NLA Strip in the channel list
+ * NOTE: This is includes the expander too...
+ */
+static size_t animfilter_nla_controls(ListBase *anim_data, bDopeSheet *ads, AnimData *adt, int filter_mode, ID *owner_id)
+{
+       ListBase tmp_data = {NULL, NULL};
+       size_t tmp_items = 0;
+       size_t items = 0;
+       
+       /* add control curves from each NLA strip... */
+       BEGIN_ANIMFILTER_SUBCHANNELS(((adt->flag & ADT_NLA_SKEYS_COLLAPSED) == 0))
+       {
+               NlaTrack *nlt;
+               NlaStrip *strip;
+               
+               /* for now, we only go one level deep - so controls on grouped FCurves are not handled */
+               for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+                       for (strip = nlt->strips.first; strip; strip = strip->next) {
+                               tmp_items += animfilter_fcurves(&tmp_data, ads, strip->fcurves.first, NULL, filter_mode, owner_id);
+                       }
+               }
+       }
+       END_ANIMFILTER_SUBCHANNELS;
+       
+       /* did we find anything? */
+       if (tmp_items) {
+               /* TODO: apply extra tags to indicate the NLA mapping does not apply here! */
+               
+               /* add the expander as a channel first */
+               if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
+                       /* currently these channels cannot be selected, so they should be skipped */
+                       if ((filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)) == 0) {
+                               ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_NLACONTROLS, owner_id);
+                       }
+               }
+               
+               /* now add the list of collected channels */
+               BLI_movelisttolist(anim_data, &tmp_data);
+               BLI_assert(BLI_listbase_is_empty(&tmp_data));
+               items += tmp_items;
+       }
+       
+       /* return the numebr of items added ot the list */
+       return items;
+}
+
 /* determine what animation data from AnimData block should get displayed */
 static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *id, int filter_mode)
 {
@@ -1332,6 +1393,9 @@ static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDope
                        { /* Drivers */
                                items += animfilter_fcurves(anim_data, ads, adt->drivers.first, NULL, filter_mode, id);
                        },
+                       { /* NLA Control Keyframes */
+                               items += animfilter_nla_controls(anim_data, ads, adt, filter_mode, id);
+                       },
                        { /* Keyframes */
                                items += animfilter_action(ac, anim_data, ads, adt->action, filter_mode, id);
                        }
@@ -2214,6 +2278,7 @@ static size_t animdata_filter_ds_obanim(bAnimContext *ac, ListBase *anim_data, b
                        cdata = adt;
                        expanded = EXPANDED_DRVD(adt);
                },
+               { /* NLA Strip Controls - no dedicated channel for now (XXX) */ },
                { /* Keyframes */
                        type = ANIMTYPE_FILLACTD;
                        cdata = adt->action;
@@ -2385,6 +2450,7 @@ static size_t animdata_filter_ds_scene(bAnimContext *ac, ListBase *anim_data, bD
                        cdata = adt;
                        expanded = EXPANDED_DRVD(adt);
                },
+               { /* NLA Strip Controls - no dedicated channel for now (XXX) */ },
                { /* Keyframes */
                        type = ANIMTYPE_FILLACTD;
                        cdata = adt->action;
index 505814297000e98065db9e08f5f5b1f1b23c6266..829ea74f00f2481f748d85d5e9338466cc52f298 100644 (file)
@@ -141,6 +141,8 @@ typedef enum eAnim_ChannelType {
        ANIMTYPE_GROUP,
        ANIMTYPE_FCURVE,
        
+       ANIMTYPE_NLACONTROLS,
+       
        ANIMTYPE_FILLACTD,
        ANIMTYPE_FILLDRIVERS,