diff options
Diffstat (limited to 'source/blender/editors/animation')
-rw-r--r-- | source/blender/editors/animation/anim_channels_defines.c | 396 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_channels_edit.c | 116 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_deps.c | 2 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_filter.c | 1890 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_ipo_utils.c | 10 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_markers.c | 11 | ||||
-rw-r--r-- | source/blender/editors/animation/drivers.c | 2 | ||||
-rw-r--r-- | source/blender/editors/animation/fmodifier_ui.c | 44 | ||||
-rw-r--r-- | source/blender/editors/animation/keyframes_draw.c | 191 | ||||
-rw-r--r-- | source/blender/editors/animation/keyframes_edit.c | 241 | ||||
-rw-r--r-- | source/blender/editors/animation/keyframes_general.c | 4 | ||||
-rw-r--r-- | source/blender/editors/animation/keyingsets.c | 9 |
12 files changed, 1078 insertions, 1838 deletions
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 51fde09b074..e97712a9af0 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -159,8 +159,8 @@ static void acf_generic_channel_color(bAnimContext *ac, bAnimListElem *ale, floa short indent= (acf->get_indent_level) ? acf->get_indent_level(ac, ale) : 0; /* get context info needed... */ - if ((ac->sa) && (ac->sa->spacetype == SPACE_ACTION)) - saction= (SpaceAction *)ac->sa->spacedata.first; + if ((ac->sl) && (ac->spacetype == SPACE_ACTION)) + saction= (SpaceAction *)ac->sl; if (ale->type == ANIMTYPE_FCURVE) { FCurve *fcu= (FCurve *)ale->data; @@ -235,13 +235,6 @@ static short acf_generic_indention_flexible(bAnimContext *UNUSED(ac), bAnimListE { short indent= 0; - if (ale->id) { - /* special exception for materials, textures, and particles */ - // xxx should tex use indention 2? - if (ELEM3(GS(ale->id->name),ID_MA,ID_PA,ID_TE)) - indent++; - } - /* grouped F-Curves need extra level of indention */ if (ale->type == ANIMTYPE_FCURVE) { FCurve *fcu= (FCurve *)ale->data; @@ -266,36 +259,53 @@ static short acf_generic_basic_offset(bAnimContext *ac, bAnimListElem *ale) return 0; } +/* offset based on nodetree type */ +static short acf_nodetree_rootType_offset(bNodeTree *ntree) +{ + if (ntree) { + switch (ntree->type) { + case NTREE_SHADER: + /* 1 additional level (i.e. is indented one level in from material, + * so shift all right by one step) + */ + return INDENT_STEP_SIZE; + + case NTREE_COMPOSIT: + /* no additional levels needed */ + return 0; + + case NTREE_TEXTURE: + /* 2 additional levels */ + return INDENT_STEP_SIZE*2; + } + } + + // unknown + return 0; +} + /* offset for groups + grouped entities */ static short acf_generic_group_offset(bAnimContext *ac, bAnimListElem *ale) { short offset= acf_generic_basic_offset(ac, ale); if (ale->id) { - /* special exception for textures */ + /* texture animdata */ if (GS(ale->id->name) == ID_TE) { - /* minimum offset */ offset += 21; - - /* special offset from owner type */ - switch (ale->ownertype) { - case ANIMTYPE_DSMAT: - offset += 21; - break; - - case ANIMTYPE_DSLAM: - case ANIMTYPE_DSWOR: - offset += 14; - break; - } } - /* special exception for materials and particles */ + /* materials and particles animdata */ else if (ELEM(GS(ale->id->name),ID_MA,ID_PA)) - offset += 21; + offset += 14; - /* if not in Action Editor mode, groupings must carry some offset too... */ + /* if not in Action Editor mode, action-groups (and their children) must carry some offset too... */ else if (ac->datatype != ANIMCONT_ACTION) offset += 14; + + /* nodetree animdata */ + if (GS(ale->id->name) == ID_NT) { + offset += acf_nodetree_rootType_offset((bNodeTree*)ale->id); + } } /* offset is just the normal type - i.e. based on indention */ @@ -324,46 +334,6 @@ static short acf_generic_none_setting_valid(bAnimContext *ac, bAnimListElem *ale } #endif -/* 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) -{ - switch (setting) { - /* only expand supported everywhere */ - case ACHANNEL_SETTING_EXPAND: - return 1; - - /* visible - * - only available in Graph Editor - * - NOT available for 'filler' channels - */ - case ACHANNEL_SETTING_VISIBLE: - if (ELEM3(ale->type, ANIMTYPE_FILLMATD, ANIMTYPE_FILLPARTD, ANIMTYPE_FILLTEXD)) - return 0; - else - return ((ac) && (ac->spacetype == SPACE_IPO)); - - default: - return 0; - } -} - -/* get pointer to the setting (category only) */ -static void *acf_generic_dsexpand_setting_ptr(bAnimListElem *ale, int setting, short *type) -{ - Object *ob= (Object *)ale->data; - - /* clear extra return data first */ - *type= 0; - - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - GET_ACF_FLAG_PTR(ob->nlaflag); // XXX - - default: /* unsupported */ - return NULL; - } -} - /* check if some setting exists for this object-based data-expander (datablock only) */ static short acf_generic_dataexpand_setting_valid(bAnimContext *ac, bAnimListElem *UNUSED(ale), int setting) { @@ -459,8 +429,8 @@ static void *acf_summary_setting_ptr(bAnimListElem *ale, int setting, short *typ /* if data is valid, return pointer to active dopesheet's relevant flag * - this is restricted to DopeSheet/Action Editor only */ - if ((ac->sa) && (ac->spacetype == SPACE_ACTION) && (setting == ACHANNEL_SETTING_EXPAND)) { - SpaceAction *saction= (SpaceAction *)ac->sa->spacedata.first; + if ((ac->sl) && (ac->spacetype == SPACE_ACTION) && (setting == ACHANNEL_SETTING_EXPAND)) { + SpaceAction *saction= (SpaceAction *)ac->sl; bDopeSheet *ads= &saction->ads; /* return pointer to DopeSheet's flag */ @@ -782,7 +752,7 @@ static short acf_group_setting_valid(bAnimContext *ac, bAnimListElem *UNUSED(ale /* for now, all settings are supported, though some are only conditionally */ switch (setting) { case ACHANNEL_SETTING_VISIBLE: /* Only available in Graph Editor */ - return ((ac->sa) && (ac->sa->spacetype==SPACE_IPO)); + return (ac->spacetype==SPACE_IPO); default: /* always supported */ return 1; @@ -879,7 +849,7 @@ static short acf_fcurve_setting_valid(bAnimContext *ac, bAnimListElem *ale, int return 0; // NOTE: in this special case, we need to draw ICON_ZOOMOUT case ACHANNEL_SETTING_VISIBLE: /* Only available in Graph Editor */ - return ((ac->sa) && (ac->sa->spacetype==SPACE_IPO)); + return (ac->spacetype==SPACE_IPO); /* always available */ default: @@ -1028,7 +998,7 @@ static bAnimChannelType ACF_FILLACTD = // TODO: just get this from RNA? static int acf_filldrivers_icon(bAnimListElem *UNUSED(ale)) { - return ICON_ANIM_DATA; + return ICON_DRIVER; } static void acf_filldrivers_name(bAnimListElem *UNUSED(ale), char *name) @@ -1101,203 +1071,6 @@ static bAnimChannelType ACF_FILLDRIVERS = acf_filldrivers_setting_ptr /* pointer for setting */ }; -/* Materials Expander ------------------------------------------- */ - -// TODO: just get this from RNA? -static int acf_fillmatd_icon(bAnimListElem *UNUSED(ale)) -{ - return ICON_MATERIAL_DATA; -} - -static void acf_fillmatd_name(bAnimListElem *UNUSED(ale), char *name) -{ - BLI_strncpy(name, "Materials", ANIM_CHAN_NAME_SIZE); -} - -/* get the appropriate flag(s) for the setting when it is valid */ -static int acf_fillmatd_setting_flag(bAnimContext *UNUSED(ac), int setting, short *neg) -{ - /* clear extra return data first */ - *neg= 0; - - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return OB_ADS_SHOWMATS; - - default: /* unsupported */ - return 0; - } -} - -/* materials expander type define */ -static bAnimChannelType ACF_FILLMATD= -{ - "Materials Filler", /* type name */ - - acf_generic_dataexpand_color, /* backdrop color */ - acf_generic_dataexpand_backdrop,/* backdrop */ - acf_generic_indention_1, /* indent level */ - acf_generic_basic_offset, /* offset */ - - acf_fillmatd_name, /* name */ - acf_fillmatd_icon, /* icon */ - - acf_generic_dsexpand_setting_valid, /* has setting */ - acf_fillmatd_setting_flag, /* flag for setting */ - acf_generic_dsexpand_setting_ptr /* pointer for setting */ -}; - -/* Particles Expander ------------------------------------------- */ - -// TODO: just get this from RNA? -static int acf_fillpartd_icon(bAnimListElem *UNUSED(ale)) -{ - return ICON_PARTICLE_DATA; -} - -static void acf_fillpartd_name(bAnimListElem *UNUSED(ale), char *name) -{ - BLI_strncpy(name, "Particles", ANIM_CHAN_NAME_SIZE); -} - -/* get the appropriate flag(s) for the setting when it is valid */ -static int acf_fillpartd_setting_flag(bAnimContext *UNUSED(ac), int setting, short *neg) -{ - /* clear extra return data first */ - *neg= 0; - - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return OB_ADS_SHOWPARTS; - - default: /* unsupported */ - return 0; - } -} - -/* particles expander type define */ -static bAnimChannelType ACF_FILLPARTD= -{ - "Particles Filler", /* type name */ - - acf_generic_dataexpand_color, /* backdrop color */ - acf_generic_dataexpand_backdrop,/* backdrop */ - acf_generic_indention_1, /* indent level */ - acf_generic_basic_offset, /* offset */ - - acf_fillpartd_name, /* name */ - acf_fillpartd_icon, /* icon */ - - acf_generic_dsexpand_setting_valid, /* has setting */ - acf_fillpartd_setting_flag, /* flag for setting */ - acf_generic_dsexpand_setting_ptr /* pointer for setting */ -}; - -/* Textures Expander ------------------------------------------- */ - -/* offset for groups + grouped entities */ -static short acf_filltexd_offset(bAnimContext *ac, bAnimListElem *ale) -{ - short offset= acf_generic_basic_offset(ac, ale); - - if (ale->id) { - /* materials */ - switch (GS(ale->id->name)) { - case ID_MA: - offset += 21; - break; - - case ID_LA: - case ID_WO: - offset += 14; - break; - } - } - - return offset; -} - -// TODO: just get this from RNA? -static int acf_filltexd_icon(bAnimListElem *UNUSED(ale)) -{ - return ICON_TEXTURE_DATA; -} - -static void acf_filltexd_name(bAnimListElem *UNUSED(ale), char *name) -{ - BLI_strncpy(name, "Textures", ANIM_CHAN_NAME_SIZE); -} - -/* get pointer to the setting (category only) */ -static void *acf_filltexd_setting_ptr(bAnimListElem *ale, int setting, short *type) -{ - ID *id= (ID *)ale->data; - - /* clear extra return data first */ - *type= 0; - - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - { - switch (GS(id->name)) { - case ID_MA: - { - Material *ma= (Material *)id; - GET_ACF_FLAG_PTR(ma->flag); - } - - case ID_LA: - { - Lamp *la= (Lamp *)id; - GET_ACF_FLAG_PTR(la->flag); - } - - case ID_WO: - { - World *wo= (World *)id; - GET_ACF_FLAG_PTR(wo->flag); - } - } - } - - default: /* unsupported */ - return NULL; - } -} - -/* get the appropriate flag(s) for the setting when it is valid */ -static int acf_filltexd_setting_flag(bAnimContext *UNUSED(ac), int setting, short *neg) -{ - /* clear extra return data first */ - *neg= 0; - - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - /* NOTE: the exact same flag must be used for other texture stack types too! */ - return MA_DS_SHOW_TEXS; - - default: /* unsupported */ - return 0; - } -} - -/* particles expander type define */ -static bAnimChannelType ACF_FILLTEXD= -{ - "Textures Filler", /* type name */ - - acf_generic_dataexpand_color, /* backdrop color */ - acf_generic_dataexpand_backdrop,/* backdrop */ - acf_generic_indention_flexible, /* indent level */ - acf_filltexd_offset, /* offset */ - - acf_filltexd_name, /* name */ - acf_filltexd_icon, /* icon */ - - acf_generic_dsexpand_setting_valid, /* has setting */ - acf_filltexd_setting_flag, /* flag for setting */ - acf_filltexd_setting_ptr /* pointer for setting */ -}; /* Material Expander ------------------------------------------- */ @@ -1307,12 +1080,6 @@ static int acf_dsmat_icon(bAnimListElem *UNUSED(ale)) return ICON_MATERIAL_DATA; } -/* offset for material expanders */ -static short acf_dsmat_offset(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale)) -{ - return 21; -} - /* get the appropriate flag(s) for the setting when it is valid */ static int acf_dsmat_setting_flag(bAnimContext *UNUSED(ac), int setting, short *neg) { @@ -1368,10 +1135,10 @@ static bAnimChannelType ACF_DSMAT= { "Material Data Expander", /* type name */ - acf_generic_channel_color, /* backdrop color */ - acf_generic_channel_backdrop, /* backdrop */ - acf_generic_indention_0, /* indent level */ - acf_dsmat_offset, /* offset */ + acf_generic_dataexpand_color, /* backdrop color */ + acf_generic_dataexpand_backdrop,/* backdrop */ + acf_generic_indention_1, /* indent level */ + acf_generic_basic_offset, /* offset */ acf_generic_idblock_name, /* name */ acf_dsmat_icon, /* icon */ @@ -1466,22 +1233,10 @@ static int acf_dstex_icon(bAnimListElem *UNUSED(ale)) } /* offset for texture expanders */ +// FIXME: soon to be obsolete? static short acf_dstex_offset(bAnimContext *UNUSED(ac), bAnimListElem *ale) { - short offset = 21; - - /* special offset from owner type */ - // FIXME: too much now! - switch (ale->ownertype) { - case ANIMTYPE_DSMAT: - offset += 14; - - case ANIMTYPE_DSLAM: - case ANIMTYPE_DSWOR: - offset += 7; - } - - return offset; + return 14; // XXX: simply include this in indention instead? } /* get the appropriate flag(s) for the setting when it is valid */ @@ -1534,14 +1289,14 @@ static void *acf_dstex_setting_ptr(bAnimListElem *ale, int setting, short *type) } } -/* material expander type define */ +/* texture expander type define */ static bAnimChannelType ACF_DSTEX= { "Texture Data Expander", /* type name */ - acf_generic_channel_color, /* backdrop color */ - acf_generic_channel_backdrop, /* backdrop */ - acf_generic_indention_0, /* indent level */ + acf_generic_dataexpand_color, /* backdrop color */ + acf_generic_dataexpand_backdrop,/* backdrop */ + acf_generic_indention_1, /* indent level */ acf_dstex_offset, /* offset */ acf_generic_idblock_name, /* name */ @@ -2102,6 +1857,17 @@ static int acf_dsntree_icon(bAnimListElem *UNUSED(ale)) return ICON_NODETREE; } +/* offset for nodetree expanders */ +static short acf_dsntree_offset(bAnimContext *ac, bAnimListElem *ale) +{ + bNodeTree *ntree = (bNodeTree *)ale->data; + short offset= acf_generic_basic_offset(ac, ale); + + offset += acf_nodetree_rootType_offset(ntree); + + return offset; +} + /* get the appropriate flag(s) for the setting when it is valid */ static int acf_dsntree_setting_flag(bAnimContext *UNUSED(ac), int setting, short *neg) { @@ -2159,8 +1925,8 @@ static bAnimChannelType ACF_DSNTREE= acf_generic_dataexpand_color, /* backdrop color */ acf_generic_dataexpand_backdrop,/* backdrop */ - acf_generic_indention_1, /* indent level */ // XXX this only works for compositing - acf_generic_basic_offset, /* offset */ + acf_generic_indention_1, /* indent level */ + acf_dsntree_offset, /* offset */ acf_generic_idblock_name, /* name */ acf_dsntree_icon, /* icon */ @@ -2590,9 +2356,6 @@ static void ANIM_init_channel_typeinfo_data (void) animchannelTypeInfo[type++]= &ACF_FILLACTD; /* Object Action Expander */ animchannelTypeInfo[type++]= &ACF_FILLDRIVERS; /* Drivers Expander */ - animchannelTypeInfo[type++]= &ACF_FILLMATD; /* Materials Expander */ - animchannelTypeInfo[type++]= &ACF_FILLPARTD; /* Particles Expander */ - animchannelTypeInfo[type++]= &ACF_FILLTEXD; /* Textures Expander */ animchannelTypeInfo[type++]= &ACF_DSMAT; /* Material Channel */ animchannelTypeInfo[type++]= &ACF_DSLAM; /* Lamp Channel */ @@ -2860,7 +2623,7 @@ void ANIM_channel_draw (bAnimContext *ac, bAnimListElem *ale, float yminc, float * - in Graph Editor, checkboxes for visibility in curves area * - in NLA Editor, glowing dots for solo/not solo... */ - if (ac->sa) { + if (ac->sl) { if ((ac->spacetype == SPACE_IPO) && acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) { /* for F-Curves, draw color-preview of curve behind checkbox */ if (ale->type == ANIMTYPE_FCURVE) { @@ -2930,17 +2693,17 @@ void ANIM_channel_draw (bAnimContext *ac, bAnimListElem *ale, float yminc, float glColor3fv(color); /* check if we need to show the sliders */ - if ((ac->sa) && ELEM(ac->spacetype, SPACE_ACTION, SPACE_IPO)) { + if ((ac->sl) && ELEM(ac->spacetype, SPACE_ACTION, SPACE_IPO)) { switch (ac->spacetype) { case SPACE_ACTION: { - SpaceAction *saction= (SpaceAction *)ac->sa->spacedata.first; + SpaceAction *saction= (SpaceAction *)ac->sl; draw_sliders= (saction->flag & SACTION_SLIDERS); } break; case SPACE_IPO: { - SpaceIpo *sipo= (SpaceIpo *)ac->sa->spacedata.first; + SpaceIpo *sipo= (SpaceIpo *)ac->sl; draw_sliders= (sipo->flag & SIPO_SLIDERS); } break; @@ -3013,11 +2776,8 @@ static void achannel_setting_flush_widget_cb(bContext *C, void *ale_npoin, void else return; - /* get all channels that can possibly be chosen - * - therefore, the filter is simply ANIMFILTER_CHANNELS, since if we took VISIBLE too, - * then the channels under closed expanders get ignored... - */ - filter= ANIMFILTER_CHANNELS; + /* get all channels that can possibly be chosen - but ignore hierarchy */ + filter= ANIMFILTER_DATA_VISIBLE|ANIMFILTER_LIST_CHANNELS; ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); /* call API method to flush the setting */ @@ -3127,9 +2887,9 @@ static void draw_setting_widget (bAnimContext *ac, bAnimListElem *ale, bAnimChan /* get the base icon for the setting */ switch (setting) { - case ACHANNEL_SETTING_VISIBLE: /* visibility checkboxes */ - //icon= ((enabled)? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT); - icon= ICON_CHECKBOX_DEHLT; + case ACHANNEL_SETTING_VISIBLE: /* visibility eyes */ + //icon= ((enabled)? ICON_VISIBLE_IPO_ON : ICON_VISIBLE_IPO_OFF); + icon= ICON_VISIBLE_IPO_OFF; if (ale->type == ANIMTYPE_FCURVE) tooltip= "Channel is visible in Graph Editor for editing."; @@ -3158,7 +2918,7 @@ static void draw_setting_widget (bAnimContext *ac, bAnimListElem *ale, bAnimChan tooltip= "Editability of keyframes for this channel."; break; - case ACHANNEL_SETTING_MUTE: /* muted eye */ + case ACHANNEL_SETTING_MUTE: /* muted speaker */ //icon= ((enabled)? ICON_MUTE_IPO_ON : ICON_MUTE_IPO_OFF); icon= ICON_MUTE_IPO_OFF; @@ -3264,7 +3024,7 @@ void ANIM_channel_draw_widgets (bAnimContext *ac, bAnimListElem *ale, uiBlock *b * - in Graph Editor, checkboxes for visibility in curves area * - in NLA Editor, glowing dots for solo/not solo... */ - if (ac->sa) { + if (ac->sl) { if ((ac->spacetype == SPACE_IPO) && acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) { /* visibility toggle */ draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_VISIBLE); @@ -3291,17 +3051,17 @@ void ANIM_channel_draw_widgets (bAnimContext *ac, bAnimListElem *ale, uiBlock *b short draw_sliders = 0; /* check if we need to show the sliders */ - if ((ac->sa) && ELEM(ac->spacetype, SPACE_ACTION, SPACE_IPO)) { + if ((ac->sl) && ELEM(ac->spacetype, SPACE_ACTION, SPACE_IPO)) { switch (ac->spacetype) { case SPACE_ACTION: { - SpaceAction *saction= (SpaceAction *)ac->sa->spacedata.first; + SpaceAction *saction= (SpaceAction *)ac->sl; draw_sliders= (saction->flag & SACTION_SLIDERS); } break; case SPACE_IPO: { - SpaceIpo *sipo= (SpaceIpo *)ac->sa->spacedata.first; + SpaceIpo *sipo= (SpaceIpo *)ac->sl; draw_sliders= (sipo->flag & SIPO_SLIDERS); } break; diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 9145cc2b79d..f66e3a23bbf 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -38,7 +38,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" - +#include "BKE_library.h" #include "DNA_anim_types.h" #include "DNA_object_types.h" @@ -194,7 +194,8 @@ void ANIM_deselect_anim_channels (bAnimContext *ac, void *data, short datatype, int filter; /* filter data */ - filter= ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS; + /* NOTE: no list visible, otherwise, we get dangling */ + filter= ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS; ANIM_animdata_filter(ac, &anim_data, filter, data, datatype); /* See if we should be selecting or deselecting */ @@ -515,12 +516,34 @@ void ANIM_fcurve_delete_from_animdata (bAnimContext *ac, AnimData *adt, FCurve * * - Drivers * - TODO... some others? */ - if (fcu->grp) - action_groups_remove_channel(adt->action, fcu); - else if ((ac) && (ac->datatype == ANIMCONT_DRIVERS)) + if ((ac) && (ac->datatype == ANIMCONT_DRIVERS)) { + /* driver F-Curve */ BLI_remlink(&adt->drivers, fcu); - else if (adt->action) - BLI_remlink(&adt->action->curves, fcu); + } + else if (adt->action) { + /* remove from group or action, whichever one "owns" the F-Curve */ + if (fcu->grp) + action_groups_remove_channel(adt->action, fcu); + else + BLI_remlink(&adt->action->curves, fcu); + + /* if action has no more F-Curves as a result of this, unlink it from + * AnimData if it did not come from a NLA Strip being tweaked. + * + * This is done so that we don't have dangling Object+Action entries in + * channel list that are empty, and linger around long after the data they + * are for has disappeared (and probably won't come back). + */ + // XXX: does everybody always want this? + /* XXX: there's a problem where many actions could build up in the file if multiple + * full add/delete cycles are performed on the same objects, but assume that this is rare + */ + if ((adt->action->curves.first == NULL) && (adt->flag & ADT_NLA_EDIT_ON)==0) + { + id_us_min(&adt->action->id); + adt->action = NULL; + } + } /* free the F-Curve itself */ free_fcurve(fcu); @@ -1031,7 +1054,8 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op) mode= RNA_enum_get(op->ptr, "direction"); /* get animdata blocks */ - filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ANIMDATA); + // XXX: hierarchy visibility is provisional atm... might be wrong decision! + 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) { @@ -1111,7 +1135,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op)) /* do groups only first (unless in Drivers mode, where there are none) */ if (ac.datatype != ANIMCONT_DRIVERS) { /* filter data */ - filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CHANNELS | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); + filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); /* delete selected groups and their associated channels */ @@ -1150,7 +1174,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op)) /* now do F-Curves */ if (ac.datatype != ANIMCONT_GPENCIL) { /* filter data */ - filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); + filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); /* delete selected F-Curves */ @@ -1205,12 +1229,27 @@ static int animchannels_visibility_set_exec(bContext *C, wmOperator *UNUSED(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; + /* 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 */ - filter= (ANIMFILTER_VISIBLE | ANIMFILTER_UNSEL | ANIMFILTER_NODUPLIS); + + /* 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) { @@ -1284,12 +1323,16 @@ static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *UNUSED(o 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 | ANIMFILTER_NODUPLIS); + /* 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 */ - filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); + /* 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 */ @@ -1362,10 +1405,6 @@ static EnumPropertyItem prop_animchannel_settings_types[] = { /* ------------------- */ -/* macro to be used in setflag_anim_channels */ -#define ASUBCHANNEL_SEL_OK(ale) ( (onlysel == 0) || \ - ((ale->id) && (GS(ale->id->name)==ID_OB) && (((Object *)ale->id)->flag & SELECT)) ) - /* Set/clear a particular flag (setting) for all selected + visible channels * setting: the setting to modify * mode: eAnimChannels_SetFlag @@ -1381,14 +1420,29 @@ static void setflag_anim_channels (bAnimContext *ac, short setting, short mode, /* filter data that we need if flush is on */ if (flush) { - /* get list of all channels that selection may need to be flushed to */ - filter= ANIMFILTER_CHANNELS; + /* get list of all channels that selection may need to be flushed to + * - hierarchy visibility needs to be ignored so that settings can get flushed + * "down" inside closed containers + */ + filter= ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS; ANIM_animdata_filter(ac, &all_data, filter, ac->data, ac->datatype); } - /* filter data that we're working on */ - // XXX: noduplis enabled so that results don't cancel, but will be problematic for some channels where only type differs - filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS | ANIMFILTER_NODUPLIS); + /* filter data that we're working on + * - 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 [#21276] + */ + if ((ac->spacetype == SPACE_IPO) && (ac->regiontype != RGN_TYPE_CHANNELS)) { + /* graph editor (case 2) */ + filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); + } + else { + /* standard case */ + filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS); + } if (onlysel) filter |= ANIMFILTER_SEL; ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); @@ -1681,7 +1735,7 @@ static int animchannels_enable_exec (bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; /* filter data */ - filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); + filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS); ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); /* loop through filtered data and clean curves */ @@ -1790,7 +1844,7 @@ static void borderselect_anim_channels (bAnimContext *ac, rcti *rect, short sele UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax-2, &rectf.xmax, &rectf.ymax); /* filter data */ - filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS); + filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* loop over data, doing border select */ @@ -1904,7 +1958,7 @@ static int mouse_anim_channels (bAnimContext *ac, float UNUSED(x), int channel_i /* get the channel that was clicked on */ /* filter channels */ - filter= (ANIMFILTER_VISIBLE | ANIMFILTER_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 */ diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index b5a1781064c..13061113926 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -257,7 +257,7 @@ void ANIM_sync_animchannels_to_data (const bContext *C) /* filter data */ /* NOTE: we want all channels, since we want to be able to set selection status on some of them even when collapsed */ - filter= ANIMFILTER_CHANNELS; + filter= ANIMFILTER_DATA_VISIBLE|ANIMFILTER_LIST_CHANNELS; ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); /* flush settings as appropriate depending on the types of the channels */ diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 967002131c2..b7264ae9a3e 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -127,6 +127,9 @@ static Key *actedit_get_shapekeys (bAnimContext *ac) /* Get data being edited in Action Editor (depending on current 'mode') */ static short actedit_get_context (bAnimContext *ac, SpaceAction *saction) { + /* get dopesheet */ + ac->ads = &saction->ads; + /* sync settings with current view status, then return appropriate data */ switch (saction->mode) { case SACTCONT_ACTION: /* 'Action Editor' */ @@ -190,6 +193,7 @@ static short graphedit_get_context (bAnimContext *ac, SpaceIpo *sipo) sipo->ads= MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet"); sipo->ads->source= (ID *)ac->scene; } + ac->ads = sipo->ads; /* set settings for Graph Editor - "Selected = Editable" */ if (sipo->flag & SIPO_SELCUVERTSONLY) @@ -238,6 +242,7 @@ static short nlaedit_get_context (bAnimContext *ac, SpaceNla *snla) /* init dopesheet data if non-existant (i.e. for old files) */ if (snla->ads == NULL) snla->ads= MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet"); + ac->ads = snla->ads; /* sync settings with current view status, then return appropriate data */ /* update scene-pointer (no need to check for pinning yet, as not implemented) */ @@ -258,29 +263,29 @@ static short nlaedit_get_context (bAnimContext *ac, SpaceNla *snla) */ short ANIM_animdata_context_getdata (bAnimContext *ac) { - ScrArea *sa= ac->sa; + SpaceLink *sl = ac->sl; short ok= 0; /* context depends on editor we are currently in */ - if (sa) { - switch (sa->spacetype) { + if (sl) { + switch (ac->spacetype) { case SPACE_ACTION: { - SpaceAction *saction= (SpaceAction *)sa->spacedata.first; + SpaceAction *saction= (SpaceAction *)sl; ok= actedit_get_context(ac, saction); } break; case SPACE_IPO: { - SpaceIpo *sipo= (SpaceIpo *)sa->spacedata.first; + SpaceIpo *sipo= (SpaceIpo *)sl; ok= graphedit_get_context(ac, sipo); } break; case SPACE_NLA: { - SpaceNla *snla= (SpaceNla *)sa->spacedata.first; + SpaceNla *snla= (SpaceNla *)sl; ok= nlaedit_get_context(ac, snla); } break; @@ -303,6 +308,7 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) { ScrArea *sa= CTX_wm_area(C); ARegion *ar= CTX_wm_region(C); + SpaceLink *sl= CTX_wm_space_data(C); Scene *scene= CTX_data_scene(C); /* clear old context info */ @@ -317,6 +323,7 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) } ac->sa= sa; ac->ar= ar; + ac->sl= sl; ac->spacetype= (sa) ? sa->spacetype : 0; ac->regiontype= (ar) ? ar->regiontype : 0; @@ -327,6 +334,35 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) /* ************************************************************ */ /* Blender Data <-- Filter --> Channels to be operated on */ +/* macros to use before/after getting the sub-channels of some channel, + * to abstract away some of the tricky logic involved + * + * cases: + * 1) Graph Edit main area (just data) OR channels visible in Channel List + * 2) If not showing channels, we're only interested in the data (Action Editor's editing) + * 3) We don't care what data, we just care there is some (so that a collapsed + * channel can be kept around). No need to clear channels-flag in order to + * keep expander channels with no sub-data out, as those cases should get + * dealt with by the recursive detection idiom in place. + */ +#define BEGIN_ANIMFILTER_SUBCHANNELS(expanded_check) \ + { \ + int _filter = filter_mode; \ + short _doSubChannels = 0; \ + if (!(filter_mode & ANIMFILTER_LIST_VISIBLE) || (expanded_check)) \ + _doSubChannels=1; \ + else if (!(filter_mode & ANIMFILTER_LIST_CHANNELS)) \ + _doSubChannels=2; \ + else {\ + filter_mode |= ANIMFILTER_TMP_PEEK; \ + } + /* ... standard sub-channel filtering can go on here now ... */ +#define END_ANIMFILTER_SUBCHANNELS \ + filter_mode = _filter; \ + } + +/* ............................... */ + /* quick macro to test if AnimData is usable */ #define ANIMDATA_HAS_KEYS(id) ((id)->adt && (id)->adt->action) @@ -336,8 +372,7 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) /* quick macro to test if AnimData is usable for NLA */ #define ANIMDATA_HAS_NLA(id) ((id)->adt && (id)->adt->nla_tracks.first) - -/* Quick macro to test for all three avove usability tests, performing the appropriate provided +/* Quick macro to test for all three above usability tests, performing the appropriate provided * action for each when the AnimData context is appropriate. * * Priority order for this goes (most important, to least): AnimData blocks, NLA, Drivers, Keyframes. @@ -347,7 +382,7 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) * - ListBase anim_data; * - bDopeSheet *ads; * - bAnimListElem *ale; - * - int items; + * - size_t items; * * - id: ID block which should have an AnimData pointer following it immediately, to use * - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA) @@ -367,7 +402,7 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) #define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, keysOk) \ {\ if ((id)->adt) {\ - if (!(filter_mode & ANIMFILTER_CURVEVISIBLE) || !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) {\ + if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) {\ if (filter_mode & ANIMFILTER_ANIMDATA) {\ adtOk\ }\ @@ -393,17 +428,31 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) }\ } +/* ............................... */ -/* quick macro to add a pointer to an AnimData block as a channel */ -#define ANIMDATA_ADD_ANIMDATA(id) \ - {\ - ale= make_new_animlistelem((id)->adt, ANIMTYPE_ANIMDATA, NULL, ANIMTYPE_NONE, (ID *)id);\ +/* Add a new animation channel, taking into account the "peek" flag, which is used to just check + * whether any channels will be added (but without needing them to actually get created). + * + * ! This causes the calling function to return early if we're only "peeking" for channels + */ +// XXX: ale_statement stuff is really a hack for one special case. It shouldn't really be needed... +#define ANIMCHANNEL_NEW_CHANNEL_FULL(channel_data, channel_type, owner_id, ale_statement) \ + if (filter_mode & ANIMFILTER_TMP_PEEK) \ + return 1; \ + else { \ + bAnimListElem *ale= make_new_animlistelem(channel_data, channel_type, (ID *)owner_id); \ if (ale) {\ - BLI_addtail(anim_data, ale);\ - items++;\ - }\ + BLI_addtail(anim_data, ale); \ + items++; \ + ale_statement \ + } \ } +#define ANIMCHANNEL_NEW_CHANNEL(channel_data, channel_type, owner_id) \ + ANIMCHANNEL_NEW_CHANNEL_FULL(channel_data, channel_type, owner_id, {}) + +/* ............................... */ + /* quick macro to test if an anim-channel representing an AnimData block is suitably active */ #define ANIMCHANNEL_ACTIVEOK(ale) \ ( !(filter_mode & ANIMFILTER_ACTIVE) || !(ale->adt) || (ale->adt->flag & ADT_UI_ACTIVE) ) @@ -432,7 +481,7 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) /* this function allocates memory for a new bAnimListElem struct for the * provided animation channel-data. */ -static bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, short ownertype, ID *owner_id) +static bAnimListElem *make_new_animlistelem (void *data, short datatype, ID *owner_id) { bAnimListElem *ale= NULL; @@ -443,10 +492,6 @@ static bAnimListElem *make_new_animlistelem (void *data, short datatype, void *o ale->data= data; ale->type= datatype; - // XXX what is the point of the owner data? - // xxx try and use this to simplify the problem of finding whether parent channels are working... - ale->owner= owner; - ale->ownertype= ownertype; ale->id= owner_id; ale->adt= BKE_animdata_from_id(owner_id); @@ -509,55 +554,6 @@ static bAnimListElem *make_new_animlistelem (void *data, short datatype, void *o ale->datatype= ALE_NONE; } break; - case ANIMTYPE_FILLMATD: - { - Object *ob= (Object *)data; - - ale->flag= FILTER_MAT_OBJC(ob); - - ale->key_data= NULL; - ale->datatype= ALE_NONE; - } - break; - case ANIMTYPE_FILLPARTD: - { - Object *ob= (Object *)data; - - ale->flag= FILTER_PART_OBJC(ob); - - ale->key_data= NULL; - ale->datatype= ALE_NONE; - } - break; - case ANIMTYPE_FILLTEXD: - { - ID *id= (ID *)data; - - switch (GS(id->name)) { - case ID_MA: - { - Material *ma= (Material *)id; - ale->flag= FILTER_TEX_MATC(ma); - } - break; - case ID_LA: - { - Lamp *la= (Lamp *)id; - ale->flag= FILTER_TEX_LAMC(la); - } - break; - case ID_WO: - { - World *wo= (World *)id; - ale->flag= FILTER_TEX_WORC(wo); - } - break; - } - - ale->key_data= NULL; - ale->datatype= ALE_NONE; - } - break; case ANIMTYPE_DSMAT: { @@ -681,7 +677,7 @@ static bAnimListElem *make_new_animlistelem (void *data, short datatype, void *o bNodeTree *ntree= (bNodeTree *)data; AnimData *adt= ntree->adt; - ale->flag= FILTER_NTREE_SCED(ntree); + ale->flag= FILTER_NTREE_DATA(ntree); ale->key_data= (adt) ? adt->action : NULL; ale->datatype= ALE_ACT; @@ -807,7 +803,7 @@ static bAnimListElem *make_new_animlistelem (void *data, short datatype, void *o /* 'Only Selected' selected data filtering * NOTE: when this function returns true, the F-Curve is to be skipped */ -static int skip_fcurve_selected_data (bDopeSheet *ads, FCurve *fcu, ID *owner_id, int filter_mode) +static size_t skip_fcurve_selected_data (bDopeSheet *ads, FCurve *fcu, ID *owner_id, int filter_mode) { if (GS(owner_id->name) == ID_OB) { Object *ob= (Object *)owner_id; @@ -825,11 +821,12 @@ static int skip_fcurve_selected_data (bDopeSheet *ads, FCurve *fcu, ID *owner_id /* check whether to continue or skip */ if ((pchan) && (pchan->bone)) { /* if only visible channels, skip if bone not visible unless user wants channels from hidden data too */ - if ((filter_mode & ANIMFILTER_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { + if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { bArmature *arm= (bArmature *)ob->data; if ((arm->layer & pchan->bone->layer) == 0) return 1; + // TODO: manually hidden using flags } /* can only add this F-Curve if it is selected */ @@ -910,7 +907,7 @@ static short skip_fcurve_with_name (bDopeSheet *ads, FCurve *fcu, ID *owner_id) } /* find the next F-Curve that is usable for inclusion */ -static FCurve *animdata_filter_fcurve_next (bDopeSheet *ads, FCurve *first, bActionGroup *grp, int filter_mode, ID *owner_id) +static FCurve *animfilter_fcurve_next (bDopeSheet *ads, FCurve *first, bActionGroup *grp, int filter_mode, ID *owner_id) { FCurve *fcu = NULL; @@ -932,7 +929,7 @@ static FCurve *animdata_filter_fcurve_next (bDopeSheet *ads, FCurve *first, bAct } /* only include if visible (Graph Editor check, not channels check) */ - if (!(filter_mode & ANIMFILTER_CURVEVISIBLE) || (fcu->flag & FCURVE_VISIBLE)) { + if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || (fcu->flag & FCURVE_VISIBLE)) { /* only work with this channel and its subchannels if it is editable */ if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_FCU(fcu)) { /* only include this curve if selected in a way consistent with the filtering requirements */ @@ -957,10 +954,10 @@ static FCurve *animdata_filter_fcurve_next (bDopeSheet *ads, FCurve *first, bAct return NULL; } -static int animdata_filter_fcurves (ListBase *anim_data, bDopeSheet *ads, FCurve *first, bActionGroup *grp, void *owner, short ownertype, int filter_mode, ID *owner_id) +static size_t animfilter_fcurves (ListBase *anim_data, bDopeSheet *ads, FCurve *first, bActionGroup *grp, int filter_mode, ID *owner_id) { FCurve *fcu; - int items = 0; + size_t items = 0; /* loop over every F-Curve able to be included * - this for-loop works like this: @@ -971,26 +968,98 @@ static int animdata_filter_fcurves (ListBase *anim_data, bDopeSheet *ads, FCurve * 4) the fcu pointer is set to the F-Curve after the one we just added, so that we can keep going through * the rest of the F-Curve list without an eternal loop. Back to step 2 :) */ - for (fcu=first; ( (fcu = animdata_filter_fcurve_next(ads, fcu, grp, filter_mode, owner_id)) ); fcu=fcu->next) + for (fcu=first; ( (fcu = animfilter_fcurve_next(ads, fcu, grp, filter_mode, owner_id)) ); fcu=fcu->next) + { + ANIMCHANNEL_NEW_CHANNEL(fcu, ANIMTYPE_FCURVE, owner_id); + } + + /* return the number of items added to the list */ + return items; +} + +static size_t animfilter_act_group (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bAction *act, bActionGroup *agrp, int filter_mode, ID *owner_id) +{ + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items = 0; + //int ofilter = filter_mode; + + /* if we care about the selection status of the channels, + * but the group isn't expanded (1)... + * (1) this only matters if we actually care about the hierarchy though. + * - Hierarchy matters: this hack should be applied + * - Hierarchy ignored: cases like [#21276] won't work properly, unless we skip this hack + */ + if ( ((filter_mode & ANIMFILTER_LIST_VISIBLE) && EXPANDED_AGRP(ac, agrp)==0) && /* care about hierarchy but group isn't expanded */ + (filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) ) /* care about selection status */ { - bAnimListElem *ale = make_new_animlistelem(fcu, ANIMTYPE_FCURVE, owner, ownertype, owner_id); + /* if the group itself isn't selected appropriately, we shouldn't consider it's children either */ + if (ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) == 0) + return 0; - if (ale) { - BLI_addtail(anim_data, ale); - items++; + /* if we're still here, then the selection status of the curves within this group should not matter, + * since this creates too much overhead for animators (i.e. making a slow workflow) + * + * Tools affected by this at time of coding (2010 Feb 09): + * - inserting keyframes on selected channels only + * - pasting keyframes + * - creating ghost curves in Graph Editor + */ + filter_mode &= ~(ANIMFILTER_SEL|ANIMFILTER_UNSEL|ANIMFILTER_LIST_VISIBLE); + } + + /* add grouped F-Curves */ + BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_AGRP(ac, agrp)) + { + /* special filter so that we can get just the F-Curves within the active group */ + if (!(filter_mode & ANIMFILTER_ACTGROUPED) || (agrp->flag & AGRP_ACTIVE)) { + /* for the Graph Editor, curves may be set to not be visible in the view to lessen clutter, + * but to do this, we need to check that the group doesn't have it's not-visible flag set preventing + * all its sub-curves to be shown + */ + if ( !(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !(agrp->flag & AGRP_NOTVISIBLE) ) + { + /* group must be editable for its children to be editable (if we care about this) */ + if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) { + /* get first F-Curve which can be used here */ + FCurve *first_fcu = animfilter_fcurve_next(ads, agrp->channels.first, agrp, filter_mode, owner_id); + + /* filter list, starting from this F-Curve */ + tmp_items += animfilter_fcurves(&tmp_data, ads, first_fcu, agrp, filter_mode, owner_id); + } + } + } + } + END_ANIMFILTER_SUBCHANNELS; + + /* did we find anything? */ + if (tmp_items) { + /* add this group as a channel first */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + /* restore original filter mode so that this next step works ok... */ + //filter_mode = ofilter; + + /* filter selection of channel specially here again, since may be open and not subject to previous test */ + if ( ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) ) { + ANIMCHANNEL_NEW_CHANNEL(agrp, ANIMTYPE_GROUP, owner_id); + } } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); + items += tmp_items; } /* return the number of items added to the list */ return items; } -static int animdata_filter_action (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bAction *act, int filter_mode, void *owner, short ownertype, ID *owner_id) +static size_t animfilter_action (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bAction *act, int filter_mode, ID *owner_id) { - bAnimListElem *ale=NULL; bActionGroup *agrp; - FCurve *lastchan=NULL; - int items = 0; + FCurve *lastchan = NULL; + size_t items = 0; /* don't include anything from this action if it is linked in from another file, * and we're getting stuff for editing... @@ -998,106 +1067,22 @@ static int animdata_filter_action (bAnimContext *ac, ListBase *anim_data, bDopeS // TODO: need a way of tagging other channels that may also be affected... if ((filter_mode & ANIMFILTER_FOREDIT) && (act->id.lib)) return 0; - - /* loop over groups */ - // TODO: in future, should we expect to need nested groups? - for (agrp= act->groups.first; agrp; agrp= agrp->next) { - FCurve *first_fcu; - int filter_gmode; + /* do groups */ + // TODO: do nested groups? + for (agrp = act->groups.first; agrp; agrp = agrp->next) { /* store reference to last channel of group */ if (agrp->channels.last) lastchan= agrp->channels.last; - - - /* make a copy of filtering flags for use by the sub-channels of this group */ - filter_gmode= filter_mode; - - /* if we care about the selection status of the channels, - * but the group isn't expanded... - */ - if ( (filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) && /* care about selection status */ - (EXPANDED_AGRP(ac, agrp)==0) ) /* group isn't expanded */ - { - /* if the group itself isn't selected appropriately, we shouldn't consider it's children either */ - if (ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) == 0) - continue; - - /* if we're still here, then the selection status of the curves within this group should not matter, - * since this creates too much overhead for animators (i.e. making a slow workflow) - * - * Tools affected by this at time of coding (2010 Feb 09): - * - inserting keyframes on selected channels only - * - pasting keyframes - * - creating ghost curves in Graph Editor - */ - filter_gmode &= ~(ANIMFILTER_SEL|ANIMFILTER_UNSEL); - } - - - /* 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 use this group at all... - * - * NOTE: use filter_gmode here not filter_mode, since there may be some flags we shouldn't consider under certain circumstances - */ - first_fcu = animdata_filter_fcurve_next(ads, agrp->channels.first, agrp, filter_gmode, owner_id); - - /* Bug note: - * Selecting open group to toggle visbility of the group, where the F-Curves of the group are not suitable - * for inclusion due to their selection status (vs visibility status of bones/etc., as is usually the case), - * will not work, since the group gets skipped. However, fixing this can easily reintroduce the bugs whereby - * hidden groups (due to visibility status of bones/etc.) that were selected before becoming invisible, can - * easily get deleted accidentally as they'd be included in the list filtered for that purpose. - * - * So, for now, best solution is to just leave this note here, and hope to find a solution at a later date. - * -- Joshua Leung, 2010 Feb 10 - */ - if (first_fcu) { - /* add this group as a channel first */ - if ((filter_mode & ANIMFILTER_CHANNELS) || !(filter_mode & ANIMFILTER_CURVESONLY)) { - /* filter selection of channel specially here again, since may be open and not subject to previous test */ - if ( ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) ) { - ale= make_new_animlistelem(agrp, ANIMTYPE_GROUP, NULL, ANIMTYPE_NONE, owner_id); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } - } - } - /* there are some situations, where only the channels of the action group should get considered */ - if (!(filter_mode & ANIMFILTER_ACTGROUPED) || (agrp->flag & AGRP_ACTIVE)) { - /* filters here are a bit convoulted... - * - groups show a "summary" of keyframes beside their name which must accessable for tools which handle keyframes - * - groups can be collapsed (and those tools which are only interested in channels rely on knowing that group is closed) - * - * cases when we should include F-Curves inside group: - * - we don't care about visibility - * - group is expanded - * - we just need the F-Curves present - */ - if ( (!(filter_mode & ANIMFILTER_VISIBLE) || EXPANDED_AGRP(ac, agrp)) || (filter_mode & ANIMFILTER_CURVESONLY) ) - { - /* for the Graph Editor, curves may be set to not be visible in the view to lessen clutter, - * but to do this, we need to check that the group doesn't have it's not-visible flag set preventing - * all its sub-curves to be shown - */ - if ( !(filter_mode & ANIMFILTER_CURVEVISIBLE) || !(agrp->flag & AGRP_NOTVISIBLE) ) - { - if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) { - /* NOTE: filter_gmode is used here, not standard filter_mode, since there may be some flags that shouldn't apply */ - items += animdata_filter_fcurves(anim_data, ads, first_fcu, agrp, owner, ownertype, filter_gmode, owner_id); - } - } - } - } - } + /* action group's channels */ + items += animfilter_act_group(ac, anim_data, ads, act, agrp, filter_mode, owner_id); } - /* loop over un-grouped F-Curves (only if we're not only considering those channels in the animive group) */ + /* un-grouped F-Curves (only if we're not only considering those channels in the active group) */ if (!(filter_mode & ANIMFILTER_ACTGROUPED)) { - // XXX the 'owner' info here needs review... - items += animdata_filter_fcurves(anim_data, ads, (lastchan)?(lastchan->next):(act->curves.first), NULL, owner, ownertype, filter_mode, owner_id); + FCurve *firstfcu = (lastchan)? (lastchan->next) : (act->curves.first); + items += animfilter_fcurves(anim_data, ads, firstfcu, NULL, filter_mode, owner_id); } /* return the number of items added to the list */ @@ -1105,36 +1090,31 @@ static int animdata_filter_action (bAnimContext *ac, ListBase *anim_data, bDopeS } /* Include NLA-Data for NLA-Editor: - * - when ANIMFILTER_CHANNELS is used, that means we should be filtering the list for display + * - when ANIMFILTER_LIST_CHANNELS is used, that means we should be filtering the list for display * Although the evaluation order is from the first track to the last and then apply the Action on top, * we present this in the UI as the Active Action followed by the last track to the first so that we * get the evaluation order presented as per a stack. * - for normal filtering (i.e. for editing), we only need the NLA-tracks but they can be in 'normal' evaluation * order, i.e. first to last. Otherwise, some tools may get screwed up. */ -static int animdata_filter_nla (bAnimContext *UNUSED(ac), ListBase *anim_data, bDopeSheet *UNUSED(ads), AnimData *adt, int filter_mode, void *owner, short ownertype, ID *owner_id) +static size_t animfilter_nla (bAnimContext *UNUSED(ac), ListBase *anim_data, bDopeSheet *UNUSED(ads), AnimData *adt, int filter_mode, ID *owner_id) { - bAnimListElem *ale; NlaTrack *nlt; NlaTrack *first=NULL, *next=NULL; - int items = 0; + size_t items = 0; /* if showing channels, include active action */ - if (filter_mode & ANIMFILTER_CHANNELS) { + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { /* there isn't really anything editable here, so skip if need editable */ - // TODO: currently, selection isn't checked since it doesn't matter if ((filter_mode & ANIMFILTER_FOREDIT) == 0) { /* just add the action track now (this MUST appear for drawing) * - as AnimData may not have an action, we pass a dummy pointer just to get the list elem created, then * overwrite this with the real value - REVIEW THIS... */ - ale= make_new_animlistelem((void *)(&adt->action), ANIMTYPE_NLAACTION, owner, ownertype, owner_id); - ale->data= (adt->action) ? adt->action : NULL; - - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } + ANIMCHANNEL_NEW_CHANNEL_FULL((void *)(&adt->action), ANIMTYPE_NLAACTION, owner_id, + { + ale->data= adt->action ? adt->action : NULL; + }); } /* first track to include will be the last one if we're filtering by channels */ @@ -1148,7 +1128,7 @@ static int animdata_filter_nla (bAnimContext *UNUSED(ac), ListBase *anim_data, b /* loop over NLA Tracks - assume that the caller of this has already checked that these should be included */ for (nlt= first; nlt; nlt= next) { /* 'next' NLA-Track to use depends on whether we're filtering for drawing or not */ - if (filter_mode & ANIMFILTER_CHANNELS) + if (filter_mode & ANIMFILTER_LIST_CHANNELS) next= nlt->prev; else next= nlt->next; @@ -1166,12 +1146,7 @@ static int animdata_filter_nla (bAnimContext *UNUSED(ac), ListBase *anim_data, b if ( ANIMCHANNEL_SELOK(SEL_NLT(nlt)) ) { /* only include if this track is active */ if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) { - ale= make_new_animlistelem(nlt, ANIMTYPE_NLATRACK, owner, ownertype, owner_id); - - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } + ANIMCHANNEL_NEW_CHANNEL(nlt, ANIMTYPE_NLATRACK, owner_id); } } } @@ -1181,14 +1156,44 @@ static int animdata_filter_nla (bAnimContext *UNUSED(ac), ListBase *anim_data, b 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) +{ + IdAdtTemplate *iat = (IdAdtTemplate*)id; + AnimData *adt = BKE_animdata_from_id(id); + size_t items = 0; + + /* NOTE: this macro is used instead of inlining the logic here, since this sort of filtering is still needed + * in a few places in he rest of the code still - notably for the few cases where special mode-based + * different types of data expanders are required. + */ + ANIMDATA_FILTER_CASES(iat, + { /* AnimData */ + /* specifically filter animdata block */ + ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_ANIMDATA, id); + }, + { /* NLA */ + items += animfilter_nla(ac, anim_data, ads, adt, filter_mode, id); + }, + { /* Drivers */ + items += animfilter_fcurves(anim_data, ads, adt->drivers.first, NULL, filter_mode, id); + }, + { /* Keyframes */ + items += animfilter_action(ac, anim_data, ads, adt->action, filter_mode, id); + }); + + return items; +} + + + /* Include ShapeKey Data for ShapeKey Editor */ -static int animdata_filter_shapekey (bAnimContext *ac, ListBase *anim_data, Key *key, int filter_mode) +static size_t animdata_filter_shapekey (bAnimContext *ac, ListBase *anim_data, Key *key, int filter_mode) { - bAnimListElem *ale; - int items = 0; + size_t items = 0; /* check if channels or only F-Curves */ - if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) { + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { KeyBlock *kb; /* loop through the channels adding ShapeKeys as appropriate */ @@ -1204,24 +1209,21 @@ static int animdata_filter_shapekey (bAnimContext *ac, ListBase *anim_data, Key // TODO: consider 'active' too? /* owner-id here must be key so that the F-Curve can be resolved... */ - ale= make_new_animlistelem(kb, ANIMTYPE_SHAPEKEY, NULL, ANIMTYPE_NONE, (ID *)key); - - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } + ANIMCHANNEL_NEW_CHANNEL(kb, ANIMTYPE_SHAPEKEY, key); } } } } else { /* just use the action associated with the shapekey */ - // FIXME: is owner-id and having no owner/dopesheet really fine? + // TODO: somehow manage to pass dopesheet info down here too? if (key->adt) { - if (filter_mode & ANIMFILTER_ANIMDATA) - ANIMDATA_ADD_ANIMDATA(key) - else if (key->adt->action) - items= animdata_filter_action(ac, anim_data, NULL, key->adt->action, filter_mode, NULL, ANIMTYPE_NONE, (ID *)key); + if (filter_mode & ANIMFILTER_ANIMDATA) { + ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, key); + } + else if (key->adt->action) { + items= animfilter_action(ac, anim_data, NULL, key->adt->action, filter_mode, (ID *)key); + } } } @@ -1231,15 +1233,13 @@ static int animdata_filter_shapekey (bAnimContext *ac, ListBase *anim_data, Key /* Grab all Grase Pencil datablocks in file */ // TODO: should this be amalgamated with the dopesheet filtering code? -static int animdata_filter_gpencil (ListBase *anim_data, void *UNUSED(data), int filter_mode) +static size_t animdata_filter_gpencil (ListBase *anim_data, void *UNUSED(data), int filter_mode) { - bAnimListElem *ale; bGPdata *gpd; bGPDlayer *gpl; - int items = 0; + size_t items = 0; /* check if filtering types are appropriate */ - if (!(filter_mode & (ANIMFILTER_ACTGROUPED|ANIMFILTER_CURVESONLY))) { /* for now, grab grease pencil datablocks directly from main*/ for (gpd = G.main->gpencil.first; gpd; gpd = gpd->id.next) { @@ -1248,17 +1248,13 @@ static int animdata_filter_gpencil (ListBase *anim_data, void *UNUSED(data), int continue; /* add gpd as channel too (if for drawing, and it has layers) */ - if ((filter_mode & ANIMFILTER_CHANNELS) && (gpd->layers.first)) { + if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && (gpd->layers.first)) { /* add to list */ - ale= make_new_animlistelem(gpd, ANIMTYPE_GPDATABLOCK, NULL, ANIMTYPE_NONE, NULL); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } + ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL); } /* only add layers if they will be visible (if drawing channels) */ - if ( !(filter_mode & ANIMFILTER_VISIBLE) || (EXPANDED_GPD(gpd)) ) { + if ( !(filter_mode & ANIMFILTER_LIST_VISIBLE) || (EXPANDED_GPD(gpd)) ) { /* loop over layers as the conditions are acceptable */ for (gpl= gpd->layers.first; gpl; gpl= gpl->next) { /* only if selected */ @@ -1266,11 +1262,7 @@ static int animdata_filter_gpencil (ListBase *anim_data, void *UNUSED(data), int /* only if editable */ if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_GPL(gpl)) { /* add to list */ - ale= make_new_animlistelem(gpl, ANIMTYPE_GPLAYER, gpd, ANIMTYPE_GPDATABLOCK, (ID*)gpd); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } + ANIMCHANNEL_NEW_CHANNEL(gpl, ANIMTYPE_GPLAYER, gpd); } } } @@ -1282,17 +1274,48 @@ static int animdata_filter_gpencil (ListBase *anim_data, void *UNUSED(data), int return items; } +/* NOTE: owner_id is scene, material, or texture block, which is the direct owner of the node tree in question */ +// TODO: how to handle group nodes is still unclear... +static size_t animdata_filter_ds_nodetree (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, bNodeTree *ntree, int filter_mode) +{ + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items = 0; + + /* add nodetree animation channels */ + BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_NTREE_DATA(ntree)) + { + /* animation data filtering */ + tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ntree, filter_mode); + } + END_ANIMFILTER_SUBCHANNELS; + + /* did we find anything? */ + if (tmp_items) { + /* include data-expand widget first */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + /* check if filtering by active status */ + if ANIMCHANNEL_ACTIVEOK(ntree) { + ANIMCHANNEL_NEW_CHANNEL(ntree, ANIMTYPE_DSNTREE, owner_id); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); + items += tmp_items; + } + + /* return the number of items added to the list */ + return items; +} + /* NOTE: owner_id is either material, lamp, or world block, which is the direct owner of the texture stack in question */ -static int animdata_filter_dopesheet_texs (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, int filter_mode) +static size_t animdata_filter_ds_textures (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, int filter_mode) { - ListBase texs = {NULL, NULL}; - LinkData *ld; MTex **mtex = NULL; - short expanded=0; - int ownertype = ANIMTYPE_NONE; - - bAnimListElem *ale=NULL; - int items=0, a=0; + size_t items=0; + int a=0; /* get datatype specific data first */ if (owner_id == NULL) @@ -1302,28 +1325,19 @@ static int animdata_filter_dopesheet_texs (bAnimContext *ac, ListBase *anim_data case ID_MA: { Material *ma= (Material *)owner_id; - mtex= (MTex**)(&ma->mtex); - expanded= FILTER_TEX_MATC(ma); - ownertype= ANIMTYPE_DSMAT; } break; case ID_LA: { Lamp *la= (Lamp *)owner_id; - mtex= (MTex**)(&la->mtex); - expanded= FILTER_TEX_LAMC(la); - ownertype= ANIMTYPE_DSLAM; } break; case ID_WO: { World *wo= (World *)owner_id; - mtex= (MTex**)(&wo->mtex); - expanded= FILTER_TEX_WORC(wo); - ownertype= ANIMTYPE_DSWOR; } break; default: @@ -1338,235 +1352,137 @@ static int animdata_filter_dopesheet_texs (bAnimContext *ac, ListBase *anim_data /* firstly check that we actuallly have some textures, by gathering all textures in a temp list */ for (a=0; a < MAX_MTEX; a++) { Tex *tex= (mtex[a]) ? mtex[a]->tex : NULL; - short ok = 0; + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; /* for now, if no texture returned, skip (this shouldn't confuse the user I hope) */ - if (ELEM(NULL, tex, tex->adt)) + if (tex == NULL) continue; - /* check if ok */ - ANIMDATA_FILTER_CASES(tex, - { /* AnimData blocks - do nothing... */ }, - ok=1;, - ok=1;, - ok=1;) - if (ok == 0) continue; - - /* make a temp list elem for this */ - ld= MEM_callocN(sizeof(LinkData), "DopeSheet-TextureCache"); - ld->data= tex; - BLI_addtail(&texs, ld); - } - - /* if there were no channels found, no need to carry on */ - if (texs.first == NULL) - return 0; - - /* include textures-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(owner_id, ANIMTYPE_FILLTEXD, owner_id, ownertype, owner_id); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } - } - - /* add textures */ - if ((expanded) || (filter_mode & ANIMFILTER_CURVESONLY)) { - /* for each texture in cache, add channels */ - for (ld= texs.first; ld; ld= ld->next) { - Tex *tex= (Tex *)ld->data; + /* add texture's animation data to temp collection */ + BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_TEX_DATA(tex)) + { + /* texture animdata */ + tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)tex, filter_mode); + /* nodes */ + if ((tex->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) { + /* owner_id as id instead of texture, since it'll otherwise be impossible to track the depth */ + // FIXME: perhaps as a result, textures should NOT be included under materials, but under their own section instead + // so that free-floating textures can also be animated + tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)tex, tex->nodetree, filter_mode); + } + } + END_ANIMFILTER_SUBCHANNELS; + + /* did we find anything? */ + if (tmp_items) { /* include texture-expand widget? */ - if (filter_mode & ANIMFILTER_CHANNELS) { + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { /* check if filtering by active status */ if ANIMCHANNEL_ACTIVEOK(tex) { - ale= make_new_animlistelem(tex, ANIMTYPE_DSTEX, owner_id, ownertype, owner_id); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } + ANIMCHANNEL_NEW_CHANNEL(tex, ANIMTYPE_DSTEX, owner_id); } } - /* add texture's animation data - * NOTE: for these, we make the owner/ownertype the material/lamp/etc. not the texture, otherwise the - * drawing code cannot resolve the indention easily - */ - if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_TEX_DATA(tex) || (filter_mode & ANIMFILTER_CURVESONLY)) { - ANIMDATA_FILTER_CASES(tex, - { /* AnimData blocks - do nothing... */ }, - items += animdata_filter_nla(ac, anim_data, ads, tex->adt, filter_mode, owner_id, ownertype, (ID *)tex);, - items += animdata_filter_fcurves(anim_data, ads, tex->adt->drivers.first, NULL, owner_id, ownertype, filter_mode, (ID *)tex);, - items += animdata_filter_action(ac, anim_data, ads, tex->adt->action, filter_mode, owner_id, ownertype, (ID *)tex);) - } + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); + items += tmp_items; } } - /* free cache */ - BLI_freelistN(&texs); - /* return the number of items added to the list */ return items; } -static int animdata_filter_dopesheet_mats (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) +static size_t animdata_filter_ds_materials (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode) { - ListBase mats = {NULL, NULL}; - LinkData *ld; - - bAnimListElem *ale=NULL; - Object *ob= base->object; - int items=0, a=0; + size_t items=0; + int a=0; /* firstly check that we actuallly have some materials, by gathering all materials in a temp list */ for (a=1; a <= ob->totcol; a++) { Material *ma= give_current_material(ob, a); - short ok = 0; + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; - /* for now, if no material returned, skip (this shouldn't confuse the user I hope) */ + /* if no material returned, skip - so that we don't get weird blank entries... */ if (ma == NULL) continue; - - /* check if ok */ - ANIMDATA_FILTER_CASES(ma, - { /* AnimData blocks - do nothing... */ }, - ok=1;, - ok=1;, - ok=1;) - - /* need to check textures */ - if (ok == 0 && !(ads->filterflag & ADS_FILTER_NOTEX)) { - int mtInd; - - for (mtInd=0; mtInd < MAX_MTEX; mtInd++) { - MTex *mtex = ma->mtex[mtInd]; - - if(mtex && mtex->tex) { - ANIMDATA_FILTER_CASES(mtex->tex, - { /* AnimData blocks - do nothing... */ }, - ok=1;, - ok=1;, - ok=1;) - } - - if(ok) - break; - } - } - if (ok == 0) continue; - - /* make a temp list elem for this */ - ld= MEM_callocN(sizeof(LinkData), "DopeSheet-MaterialCache"); - ld->data= ma; - BLI_addtail(&mats, ld); - } - - /* if there were no channels found, no need to carry on */ - if (mats.first == NULL) - return 0; - - /* include materials-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(ob, ANIMTYPE_FILLMATD, base, ANIMTYPE_OBJECT, (ID *)ob); - if (ale) { - BLI_addtail(anim_data, ale); - items++; + /* add material's animation data to temp collection */ + BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_MAT_OBJD(ma)) + { + /* material's animation data */ + tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ma, filter_mode); + + /* textures */ + if (!(ads->filterflag & ADS_FILTER_NOTEX)) + tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)ma, filter_mode); + + /* nodes */ + if ((ma->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) + tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)ma, ma->nodetree, filter_mode); } - } - - /* add materials? */ - if (FILTER_MAT_OBJC(ob) || (filter_mode & ANIMFILTER_CURVESONLY)) { - /* for each material in cache, add channels */ - for (ld= mats.first; ld; ld= ld->next) { - Material *ma= (Material *)ld->data; - - /* include material-expand widget? */ + END_ANIMFILTER_SUBCHANNELS; + + /* did we find anything? */ + if (tmp_items) { + /* include material-expand widget first */ // hmm... do we need to store the index of this material in the array anywhere? - if (filter_mode & ANIMFILTER_CHANNELS) { + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { /* check if filtering by active status */ if ANIMCHANNEL_ACTIVEOK(ma) { - ale= make_new_animlistelem(ma, ANIMTYPE_DSMAT, base, ANIMTYPE_OBJECT, (ID *)ma); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } + ANIMCHANNEL_NEW_CHANNEL(ma, ANIMTYPE_DSMAT, ma); } } - /* add material's animation data */ - if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_MAT_OBJD(ma) || (filter_mode & ANIMFILTER_CURVESONLY)) { - /* material's animation data */ - ANIMDATA_FILTER_CASES(ma, - { /* AnimData blocks - do nothing... */ }, - items += animdata_filter_nla(ac, anim_data, ads, ma->adt, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);, - items += animdata_filter_fcurves(anim_data, ads, ma->adt->drivers.first, NULL, ma, ANIMTYPE_DSMAT, filter_mode, (ID *)ma);, - items += animdata_filter_action(ac, anim_data, ads, ma->adt->action, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);) - - /* textures */ - if (!(ads->filterflag & ADS_FILTER_NOTEX)) - items += animdata_filter_dopesheet_texs(ac, anim_data, ads, (ID *)ma, filter_mode); - } + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); + items += tmp_items; } } - /* free cache */ - BLI_freelistN(&mats); - /* return the number of items added to the list */ return items; } -static int animdata_filter_dopesheet_particles (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) +static size_t animdata_filter_ds_particles (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode) { - bAnimListElem *ale=NULL; - Object *ob= base->object; - ParticleSystem *psys = ob->particlesystem.first; - int items= 0, first = 1; - - for(; psys; psys=psys->next) { - short ok = 0; + ParticleSystem *psys; + size_t items= 0; - if(ELEM(NULL, psys->part, psys->part->adt)) + for (psys = ob->particlesystem.first; psys; psys=psys->next) { + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + + /* if no material returned, skip - so that we don't get weird blank entries... */ + if (ELEM(NULL, psys->part, psys->part->adt)) continue; - - ANIMDATA_FILTER_CASES(psys->part, - { /* AnimData blocks - do nothing... */ }, - ok=1;, - ok=1;, - ok=1;) - if (ok == 0) continue; - - /* include particles-expand widget? */ - if (first && (filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(ob, ANIMTYPE_FILLPARTD, base, ANIMTYPE_OBJECT, (ID *)ob); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } - first = 0; + + /* add particle-system's animation data to temp collection */ + BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_PART_OBJD(psys->part)) + { + /* material's animation data */ + tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)psys->part, filter_mode); } + END_ANIMFILTER_SUBCHANNELS; - /* add particle settings? */ - if (FILTER_PART_OBJC(ob) || (filter_mode & ANIMFILTER_CURVESONLY)) { - if ((filter_mode & ANIMFILTER_CHANNELS)) { + /* did we find anything? */ + if (tmp_items) { + /* include particle-expand widget first */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { /* check if filtering by active status */ if ANIMCHANNEL_ACTIVEOK(psys->part) { - ale = make_new_animlistelem(psys->part, ANIMTYPE_DSPART, base, ANIMTYPE_OBJECT, (ID *)psys->part); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } + ANIMCHANNEL_NEW_CHANNEL(psys->part, ANIMTYPE_DSPART, psys->part); } } - if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_PART_OBJD(psys->part) || (filter_mode & ANIMFILTER_CURVESONLY)) { - ANIMDATA_FILTER_CASES(psys->part, - { /* AnimData blocks - do nothing... */ }, - items += animdata_filter_nla(ac, anim_data, ads, psys->part->adt, filter_mode, psys->part, ANIMTYPE_DSPART, (ID *)psys->part);, - items += animdata_filter_fcurves(anim_data, ads, psys->part->adt->drivers.first, NULL, psys->part, ANIMTYPE_DSPART, filter_mode, (ID *)psys->part);, - items += animdata_filter_action(ac, anim_data, ads, psys->part->adt->action, filter_mode, psys->part, ANIMTYPE_DSPART, (ID *)psys->part);) - } + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); + items += tmp_items; } } @@ -1574,14 +1490,14 @@ static int animdata_filter_dopesheet_particles (bAnimContext *ac, ListBase *anim return items; } -static int animdata_filter_dopesheet_obdata (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) +static size_t animdata_filter_ds_obdata (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode) { - bAnimListElem *ale=NULL; - Object *ob= base->object; + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items= 0; + IdAdtTemplate *iat= ob->data; - AnimData *adt= iat->adt; short type=0, expanded=0; - int items= 0; /* get settings based on data type */ switch (ob->type) { @@ -1589,6 +1505,9 @@ static int animdata_filter_dopesheet_obdata (bAnimContext *ac, ListBase *anim_da { Camera *ca= (Camera *)ob->data; + if (ads->filterflag & ADS_FILTER_NOCAM) + return 0; + type= ANIMTYPE_DSCAM; expanded= FILTER_CAM_OBJD(ca); } @@ -1597,6 +1516,9 @@ static int animdata_filter_dopesheet_obdata (bAnimContext *ac, ListBase *anim_da { Lamp *la= (Lamp *)ob->data; + if (ads->filterflag & ADS_FILTER_NOLAM) + return 0; + type= ANIMTYPE_DSLAM; expanded= FILTER_LAM_OBJD(la); } @@ -1607,6 +1529,9 @@ static int animdata_filter_dopesheet_obdata (bAnimContext *ac, ListBase *anim_da { Curve *cu= (Curve *)ob->data; + if (ads->filterflag & ADS_FILTER_NOCUR) + return 0; + type= ANIMTYPE_DSCUR; expanded= FILTER_CUR_OBJD(cu); } @@ -1615,6 +1540,9 @@ static int animdata_filter_dopesheet_obdata (bAnimContext *ac, ListBase *anim_da { MetaBall *mb= (MetaBall *)ob->data; + if (ads->filterflag & ADS_FILTER_NOMBA) + return 0; + type= ANIMTYPE_DSMBALL; expanded= FILTER_MBALL_OBJD(mb); } @@ -1623,6 +1551,9 @@ static int animdata_filter_dopesheet_obdata (bAnimContext *ac, ListBase *anim_da { bArmature *arm= (bArmature *)ob->data; + if (ads->filterflag & ADS_FILTER_NOARM) + return 0; + type= ANIMTYPE_DSARM; expanded= FILTER_ARM_OBJD(arm); } @@ -1631,6 +1562,9 @@ static int animdata_filter_dopesheet_obdata (bAnimContext *ac, ListBase *anim_da { Mesh *me= (Mesh *)ob->data; + if (ads->filterflag & ADS_FILTER_NOMESH) + return 0; + type= ANIMTYPE_DSMESH; expanded= FILTER_MESH_OBJD(me); } @@ -1639,463 +1573,358 @@ static int animdata_filter_dopesheet_obdata (bAnimContext *ac, ListBase *anim_da { Lattice *lt = (Lattice *)ob->data; + if (ads->filterflag & ADS_FILTER_NOLAT) + return 0; + type= ANIMTYPE_DSLAT; expanded= FILTER_LATTICE_OBJD(lt); } break; } - /* include data-expand widget? */ - if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) { - /* check if filtering by active status */ - if ANIMCHANNEL_ACTIVEOK(iat) { - ale= make_new_animlistelem(iat, type, base, ANIMTYPE_OBJECT, (ID *)iat); - if (ale) BLI_addtail(anim_data, ale); - } - } - - /* add object-data animation channels? */ - if (!(filter_mode & ANIMFILTER_VISIBLE) || (expanded) || (filter_mode & ANIMFILTER_CURVESONLY)) { - /* filtering for channels - nla, drivers, keyframes */ - ANIMDATA_FILTER_CASES(iat, - { /* AnimData blocks - do nothing... */ }, - items+= animdata_filter_nla(ac, anim_data, ads, iat->adt, filter_mode, iat, type, (ID *)iat);, - items+= animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, iat, type, filter_mode, (ID *)iat);, - items+= animdata_filter_action(ac, anim_data, ads, iat->adt->action, filter_mode, iat, type, (ID *)iat);) - + /* add object data animation channels */ + BEGIN_ANIMFILTER_SUBCHANNELS(expanded) + { + /* animation data filtering */ + tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)iat, filter_mode); + /* sub-data filtering... */ switch (ob->type) { case OB_LAMP: /* lamp - textures */ { /* textures */ if (!(ads->filterflag & ADS_FILTER_NOTEX)) - items += animdata_filter_dopesheet_texs(ac, anim_data, ads, ob->data, filter_mode); + tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, ob->data, filter_mode); } break; } } + END_ANIMFILTER_SUBCHANNELS; + + /* did we find anything? */ + if (tmp_items) { + /* include data-expand widget first */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + /* check if filtering by active status */ + if ANIMCHANNEL_ACTIVEOK(iat) { + ANIMCHANNEL_NEW_CHANNEL(iat, type, iat); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); + items += tmp_items; + } /* return the number of items added to the list */ return items; } -static int animdata_filter_dopesheet_ob (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) +/* shapekey-level animation */ +static size_t animdata_filter_ds_keyanim (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, Key *key, int filter_mode) { - bAnimListElem *ale=NULL; - AnimData *adt = NULL; - Object *ob= base->object; - Key *key= ob_get_key(ob); - short obdata_ok = 0; - int items = 0; - - /* add this object as a channel first */ - if ((filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) == 0) { - /* check if filtering by selection */ - if ANIMCHANNEL_SELOK((base->flag & SELECT)) { - /* check if filtering by active status */ - if ANIMCHANNEL_ACTIVEOK(ob) { - ale= make_new_animlistelem(base, ANIMTYPE_OBJECT, NULL, ANIMTYPE_NONE, (ID *)ob); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } - } - } + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items = 0; + + /* add shapekey-level animation channels */ + BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_SKE_OBJD(key)) + { + /* animation data filtering */ + tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)key, filter_mode); } + END_ANIMFILTER_SUBCHANNELS; - /* if collapsed, don't go any further (unless adding keyframes only) */ - if ( ((filter_mode & ANIMFILTER_VISIBLE) && EXPANDED_OBJC(ob) == 0) && - !(filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) ) - return items; - - /* Action, Drivers, or NLA */ - if (ob->adt && !(ads->filterflag & ADS_FILTER_NOOBJ)) { - adt= ob->adt; - ANIMDATA_FILTER_CASES(ob, - { /* AnimData blocks - do nothing... */ }, - { /* nla */ - /* add NLA tracks */ - items += animdata_filter_nla(ac, anim_data, ads, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); - }, - { /* drivers */ - /* include drivers-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, base, ANIMTYPE_OBJECT, (ID *)ob); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } - } - - /* add F-Curve channels (drivers are F-Curves) */ - if (!(filter_mode & ANIMFILTER_VISIBLE) || EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) { - // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?) - items += animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, ob, ANIMTYPE_OBJECT, filter_mode, (ID *)ob); - } - }, - { /* action (keyframes) */ - /* include action-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, base, ANIMTYPE_OBJECT, (ID *)ob); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } - } - - /* add F-Curve channels? */ - if (!(filter_mode & ANIMFILTER_VISIBLE) || EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) { - // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?) - items += animdata_filter_action(ac, anim_data, ads, adt->action, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); - } + /* did we find anything? */ + if (tmp_items) { + /* include key-expand widget first */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + if ANIMCHANNEL_ACTIVEOK(key) { + ANIMCHANNEL_NEW_CHANNEL(key, ANIMTYPE_DSSKEY, ob); } - ); + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); + items += tmp_items; } + /* return the number of items added to the list */ + return items; +} + +/* object-level animation */ +static size_t animdata_filter_ds_obanim (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode) +{ + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items = 0; + + AnimData *adt = ob->adt; + short type=0, expanded=1; + void *cdata = NULL; + + /* determine the type of expander channels to use */ + // this is the best way to do this for now... + ANIMDATA_FILTER_CASES(ob, + {/* AnimData - no channel, but consider data */}, + {/* NLA - no channel, but consider data */}, + {/* Drivers */ + type = ANIMTYPE_FILLDRIVERS; + cdata = adt; + expanded = EXPANDED_DRVD(adt); + }, + {/* Keyframes */ + type = ANIMTYPE_FILLACTD; + cdata = adt->action; + expanded = EXPANDED_ACTC(adt->action); + }); + + /* add object-level animation channels */ + BEGIN_ANIMFILTER_SUBCHANNELS(expanded) + { + /* animation data filtering */ + tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ob, filter_mode); + } + END_ANIMFILTER_SUBCHANNELS; - /* ShapeKeys? */ - if ((key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) { - adt= key->adt; - ANIMDATA_FILTER_CASES(key, - { /* AnimData blocks - do nothing... */ }, - { /* nla */ - /* include shapekey-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - /* check if filtering by active status */ - if ANIMCHANNEL_ACTIVEOK(key) { - ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } - } - } - - /* add NLA tracks - only if expanded or so */ - if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) - items += animdata_filter_nla(ac, anim_data, ads, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)key); - }, - { /* drivers */ - /* include shapekey-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } - } - - /* add channels */ - if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) { - items += animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, key, ANIMTYPE_DSSKEY, filter_mode, (ID *)key); - } - }, - { /* action (keyframes) */ - /* include shapekey-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - /* check if filtering by active status */ - if ANIMCHANNEL_ACTIVEOK(key) { - ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } - } - } - - /* add channels */ - if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) { - items += animdata_filter_action(ac, anim_data, ads, adt->action, filter_mode, key, ANIMTYPE_DSSKEY, (ID *)key); - } + /* did we find anything? */ + if (tmp_items) { + /* include anim-expand widget first */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + if (type != ANIMTYPE_NONE) { + /* NOTE: active-status (and the associated checks) don't apply here... */ + ANIMCHANNEL_NEW_CHANNEL(cdata, type, ob); } - ); + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); + items += tmp_items; } + + /* return the number of items added to the list */ + return items; +} - /* Materials? */ - if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT)) - items += animdata_filter_dopesheet_mats(ac, anim_data, ads, base, filter_mode); +/* get animation channels from object2 */ +static size_t animdata_filter_dopesheet_ob (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) +{ + ListBase tmp_data = {NULL, NULL}; + Object *ob= base->object; + size_t tmp_items = 0; + size_t items = 0; - /* Object Data */ - switch (ob->type) { - case OB_CAMERA: /* ------- Camera ------------ */ - { - Camera *ca= (Camera *)ob->data; - - if ((ads->filterflag & ADS_FILTER_NOCAM) == 0) { - ANIMDATA_FILTER_CASES(ca, - { /* AnimData blocks - do nothing... */ }, - obdata_ok= 1;, - obdata_ok= 1;, - obdata_ok= 1;) - } - } - break; - case OB_LAMP: /* ---------- Lamp ----------- */ - { - Lamp *la= (Lamp *)ob->data; - - if ((ads->filterflag & ADS_FILTER_NOLAM) == 0) { - ANIMDATA_FILTER_CASES(la, - { /* AnimData blocks - do nothing... */ }, - obdata_ok= 1;, - obdata_ok= 1;, - obdata_ok= 1;) - } + /* filter data contained under object first */ + BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_OBJC(ob)) + { + Key *key= ob_get_key(ob); + + /* object-level animation */ + if ((ob->adt) && !(ads->filterflag & ADS_FILTER_NOOBJ)) { + tmp_items += animdata_filter_ds_obanim(ac, &tmp_data, ads, ob, filter_mode); } - break; - case OB_CURVE: /* ------- Curve ---------- */ - case OB_SURF: /* ------- Nurbs Surface ---------- */ - case OB_FONT: /* ------- Text Curve ---------- */ - { - Curve *cu= (Curve *)ob->data; - - if ((ads->filterflag & ADS_FILTER_NOCUR) == 0) { - ANIMDATA_FILTER_CASES(cu, - { /* AnimData blocks - do nothing... */ }, - obdata_ok= 1;, - obdata_ok= 1;, - obdata_ok= 1;) - } + + /* shape-key */ + if ((key && key->adt) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) { + tmp_items += animdata_filter_ds_keyanim(ac, &tmp_data, ads, ob, key, filter_mode); } - break; - case OB_MBALL: /* ------- MetaBall ---------- */ - { - MetaBall *mb= (MetaBall *)ob->data; - - if ((ads->filterflag & ADS_FILTER_NOMBA) == 0) { - ANIMDATA_FILTER_CASES(mb, - { /* AnimData blocks - do nothing... */ }, - obdata_ok= 1;, - obdata_ok= 1;, - obdata_ok= 1;) - } + + /* materials */ + if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT)) { + tmp_items += animdata_filter_ds_materials(ac, &tmp_data, ads, ob, filter_mode); } - break; - case OB_ARMATURE: /* ------- Armature ---------- */ - { - bArmature *arm= (bArmature *)ob->data; - - if ((ads->filterflag & ADS_FILTER_NOARM) == 0) { - ANIMDATA_FILTER_CASES(arm, - { /* AnimData blocks - do nothing... */ }, - obdata_ok= 1;, - obdata_ok= 1;, - obdata_ok= 1;) - } + + /* object data */ + if (ob->data) { + tmp_items += animdata_filter_ds_obdata(ac, &tmp_data, ads, ob, filter_mode); } - break; - case OB_MESH: /* ------- Mesh ---------- */ - { - Mesh *me= (Mesh *)ob->data; - - if ((ads->filterflag & ADS_FILTER_NOMESH) == 0) { - ANIMDATA_FILTER_CASES(me, - { /* AnimData blocks - do nothing... */ }, - obdata_ok= 1;, - obdata_ok= 1;, - obdata_ok= 1;) - } + + /* particles */ + if ((ob->particlesystem.first) && !(ads->filterflag & ADS_FILTER_NOPART)) { + tmp_items += animdata_filter_ds_particles(ac, &tmp_data, ads, ob, filter_mode); } - break; - case OB_LATTICE: /* ------- Lattice ---------- */ - { - Lattice *lt= (Lattice *)ob->data; - - if ((ads->filterflag & ADS_FILTER_NOLAT) == 0) { - ANIMDATA_FILTER_CASES(lt, - { /* AnimData blocks - do nothing... */ }, - obdata_ok= 1;, - obdata_ok= 1;, - obdata_ok= 1;) + } + END_ANIMFILTER_SUBCHANNELS; + + + /* if we collected some channels, add these to the new list... */ + if (tmp_items) { + /* firstly add object expander if required */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + /* check if filtering by selection */ + // XXX: double-check on this - most of the time, a lot of tools need to filter out these channels! + if ANIMCHANNEL_SELOK((base->flag & SELECT)) { + /* check if filtering by active status */ + if (ANIMCHANNEL_ACTIVEOK(ob)) { + ANIMCHANNEL_NEW_CHANNEL(base, ANIMTYPE_OBJECT, ob); + } } } - break; + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); + items += tmp_items; } - if (obdata_ok) - items += animdata_filter_dopesheet_obdata(ac, anim_data, ads, base, filter_mode); - - /* particles */ - if (ob->particlesystem.first && !(ads->filterflag & ADS_FILTER_NOPART)) - items += animdata_filter_dopesheet_particles(ac, anim_data, ads, base, filter_mode); - /* return the number of items added to the list */ + /* return the number of items added */ return items; -} +} -static int animdata_filter_dopesheet_scene (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode) +static size_t animdata_filter_ds_world (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, World *wo, int filter_mode) { - World *wo= sce->world; - bNodeTree *ntree= sce->nodetree; - AnimData *adt= NULL; - bAnimListElem *ale; - int items = 0; - - /* add scene as a channel first (even if we aren't showing scenes we still need to show the scene's sub-data */ - if ((filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) == 0) { - /* check if filtering by selection */ - if (ANIMCHANNEL_SELOK( (sce->flag & SCE_DS_SELECTED) )) { - ale= make_new_animlistelem(sce, ANIMTYPE_SCENE, NULL, ANIMTYPE_NONE, NULL); - if (ale) { - BLI_addtail(anim_data, ale); - items++; + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items = 0; + + /* add world animation channels */ + BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_WOR_SCED(wo)) + { + /* animation data filtering */ + tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)wo, filter_mode); + + /* textures for world */ + if (!(ads->filterflag & ADS_FILTER_NOTEX)) + items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)wo, filter_mode); + } + END_ANIMFILTER_SUBCHANNELS; + + /* did we find anything? */ + if (tmp_items) { + /* include data-expand widget first */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + /* check if filtering by active status */ + if ANIMCHANNEL_ACTIVEOK(wo) { + ANIMCHANNEL_NEW_CHANNEL(wo, ANIMTYPE_DSWOR, sce); } } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); + items += tmp_items; } - /* if collapsed, don't go any further (unless adding keyframes only) */ - if ( (EXPANDED_SCEC(sce) == 0) && !(filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) ) - return items; + /* return the number of items added to the list */ + return items; +} + +static size_t animdata_filter_ds_scene (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode) +{ + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items = 0; + + AnimData *adt = sce->adt; + short type=0, expanded=1; + void *cdata = NULL; + + /* determine the type of expander channels to use */ + // this is the best way to do this for now... + ANIMDATA_FILTER_CASES(sce, + {/* AnimData - no channel, but consider data */}, + {/* NLA - no channel, but consider data */}, + {/* Drivers */ + type = ANIMTYPE_FILLDRIVERS; + cdata = adt; + expanded = EXPANDED_DRVD(adt); + }, + {/* Keyframes */ + type = ANIMTYPE_FILLACTD; + cdata = adt->action; + expanded = EXPANDED_ACTC(adt->action); + }); - /* Action, Drivers, or NLA for Scene */ - if ((ads->filterflag & ADS_FILTER_NOSCE) == 0) { - adt= sce->adt; - ANIMDATA_FILTER_CASES(sce, - { /* AnimData blocks - do nothing... */ }, - { /* nla */ - /* add NLA tracks */ - items += animdata_filter_nla(ac, anim_data, ads, adt, filter_mode, sce, ANIMTYPE_SCENE, (ID *)sce); - }, - { /* drivers */ - /* include drivers-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, sce, ANIMTYPE_SCENE, (ID *)sce); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } - } - - /* add F-Curve channels (drivers are F-Curves) */ - if (EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) { - items += animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, sce, ANIMTYPE_SCENE, filter_mode, (ID *)sce); - } - }, - { /* action */ - /* include action-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, sce, ANIMTYPE_SCENE, (ID *)sce); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } - } - - /* add F-Curve channels? */ - if (EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) { - items += animdata_filter_action(ac, anim_data, ads, adt->action, filter_mode, sce, ANIMTYPE_SCENE, (ID *)sce); - } - } - ) + /* add scene-level animation channels */ + BEGIN_ANIMFILTER_SUBCHANNELS(expanded) + { + /* animation data filtering */ + tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)sce, filter_mode); } + END_ANIMFILTER_SUBCHANNELS; - /* world */ - if ((wo && wo->adt) && !(ads->filterflag & ADS_FILTER_NOWOR)) { - /* Action, Drivers, or NLA for World */ - adt= wo->adt; - ANIMDATA_FILTER_CASES(wo, - { /* AnimData blocks - do nothing... */ }, - { /* nla */ - /* add NLA tracks */ - items += animdata_filter_nla(ac, anim_data, ads, adt, filter_mode, wo, ANIMTYPE_DSWOR, (ID *)wo); - }, - { /* drivers */ - /* include world-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(wo, ANIMTYPE_DSWOR, sce, ANIMTYPE_SCENE, (ID *)wo); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } - } - - /* add F-Curve channels (drivers are F-Curves) */ - if (FILTER_WOR_SCED(wo)/*EXPANDED_DRVD(adt)*/ || !(filter_mode & ANIMFILTER_CHANNELS)) { - // XXX owner info is messed up now... - items += animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, wo, ANIMTYPE_DSWOR, filter_mode, (ID *)wo); - } - }, - { /* action */ - /* include world-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(wo, ANIMTYPE_DSWOR, sce, ANIMTYPE_SCENE, (ID *)sce); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } - } - - /* add channels */ - if (FILTER_WOR_SCED(wo) || (filter_mode & ANIMFILTER_CURVESONLY)) { - items += animdata_filter_action(ac, anim_data, ads, adt->action, filter_mode, wo, ANIMTYPE_DSWOR, (ID *)wo); - } + /* did we find anything? */ + if (tmp_items) { + /* include anim-expand widget first */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + if (type != ANIMTYPE_NONE) { + /* NOTE: active-status (and the associated checks) don't apply here... */ + ANIMCHANNEL_NEW_CHANNEL(cdata, type, sce); } - ) + } - /* if expanded, check world textures too */ - if (FILTER_WOR_SCED(wo) || (filter_mode & ANIMFILTER_CURVESONLY)) { - /* textures for world */ - if (!(ads->filterflag & ADS_FILTER_NOTEX)) - items += animdata_filter_dopesheet_texs(ac, anim_data, ads, (ID *)wo, filter_mode); + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); + items += tmp_items; + } + + /* return the number of items added to the list */ + return items; +} + +static size_t animdata_filter_dopesheet_scene (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode) +{ + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items = 0; + + /* filter data contained under object first */ + BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_SCEC(sce)) + { + bNodeTree *ntree= sce->nodetree; + World *wo= sce->world; + + /* Action, Drivers, or NLA for Scene */ + if ((ads->filterflag & ADS_FILTER_NOSCE) == 0) { + tmp_items += animdata_filter_ds_scene(ac, &tmp_data, ads, sce, filter_mode); + } + + /* world */ + if ((wo && wo->adt) && !(ads->filterflag & ADS_FILTER_NOWOR)) { + tmp_items += animdata_filter_ds_world(ac, &tmp_data, ads, sce, wo, filter_mode); } + + /* nodetree */ + if ((ntree && ntree->adt) && !(ads->filterflag & ADS_FILTER_NONTREE)) { + tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)sce, ntree, filter_mode); + } + + // TODO: one day, when sequencer becomes its own datatype, perhaps it should be included here } - /* nodetree */ - if ((ntree && ntree->adt) && !(ads->filterflag & ADS_FILTER_NONTREE)) { - /* Action, Drivers, or NLA for Nodetree */ - adt= ntree->adt; - ANIMDATA_FILTER_CASES(ntree, - { /* AnimData blocks - do nothing... */ }, - { /* nla */ - /* add NLA tracks */ - items += animdata_filter_nla(ac, anim_data, ads, adt, filter_mode, ntree, ANIMTYPE_DSNTREE, (ID *)ntree); - }, - { /* drivers */ - /* include nodetree-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(ntree, ANIMTYPE_DSNTREE, sce, ANIMTYPE_SCENE, (ID *)ntree); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } - } - - /* add F-Curve channels (drivers are F-Curves) */ - if (FILTER_NTREE_SCED(ntree)/*EXPANDED_DRVD(adt)*/ || !(filter_mode & ANIMFILTER_CHANNELS)) { - // XXX owner info is messed up now... - items += animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, ntree, ANIMTYPE_DSNTREE, filter_mode, (ID *)ntree); - } - }, - { /* action */ - /* include nodetree-expand widget? */ - if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) { - ale= make_new_animlistelem(ntree, ANIMTYPE_DSNTREE, sce, ANIMTYPE_SCENE, (ID *)sce); - if (ale) { - BLI_addtail(anim_data, ale); - items++; - } - } - - /* add channels */ - if (FILTER_NTREE_SCED(ntree) || (filter_mode & ANIMFILTER_CURVESONLY)) { - items += animdata_filter_action(ac, anim_data, ads, adt->action, filter_mode, ntree, ANIMTYPE_DSNTREE, (ID *)ntree); - } + END_ANIMFILTER_SUBCHANNELS; + + /* if we collected some channels, add these to the new list... */ + if (tmp_items) { + /* firstly add object expander if required */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + /* check if filtering by selection */ + if ANIMCHANNEL_SELOK((sce->flag & SCE_DS_SELECTED)) { + /* NOTE: active-status doesn't matter for this! */ + ANIMCHANNEL_NEW_CHANNEL(sce, ANIMTYPE_SCENE, sce); } - ) + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); + items += tmp_items; } - - // TODO: scene compositing nodes (these aren't standard node-trees) - - /* return the number of items added to the list */ + /* return the number of items added */ return items; } // 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 (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, int filter_mode) +static size_t animdata_filter_dopesheet (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, int filter_mode) { Scene *sce= (Scene *)ads->source; Base *base; - bAnimListElem *ale; - int items = 0; + size_t items = 0; /* check that we do indeed have a scene */ if ((ads->source == NULL) || (GS(ads->source->name)!=ID_SCE)) { @@ -2113,73 +1942,14 @@ static int animdata_filter_dopesheet (bAnimContext *ac, ListBase *anim_data, bDo filter_mode |= ANIMFILTER_SELEDIT; } - /* scene-linked animation */ - // TODO: sequencer, composite nodes - are we to include those here too? - { - short sceOk= 0, worOk= 0, nodeOk=0; - - /* check filtering-flags if ok */ - ANIMDATA_FILTER_CASES(sce, - { - /* for the special AnimData blocks only case, we only need to add - * the block if it is valid... then other cases just get skipped (hence ok=0) - */ - ANIMDATA_ADD_ANIMDATA(sce); - sceOk=0; - }, - sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);, - sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);, - sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);) - if (sce->world) { - ANIMDATA_FILTER_CASES(sce->world, - { - /* for the special AnimData blocks only case, we only need to add - * the block if it is valid... then other cases just get skipped (hence ok=0) - */ - ANIMDATA_ADD_ANIMDATA(sce->world); - worOk=0; - }, - worOk= !(ads->filterflag & ADS_FILTER_NOWOR);, - worOk= !(ads->filterflag & ADS_FILTER_NOWOR);, - worOk= !(ads->filterflag & ADS_FILTER_NOWOR);) - } - if (sce->nodetree) { - ANIMDATA_FILTER_CASES(sce->nodetree, - { - /* for the special AnimData blocks only case, we only need to add - * the block if it is valid... then other cases just get skipped (hence ok=0) - */ - ANIMDATA_ADD_ANIMDATA(sce->nodetree); - nodeOk=0; - }, - nodeOk= !(ads->filterflag & ADS_FILTER_NONTREE);, - nodeOk= !(ads->filterflag & ADS_FILTER_NONTREE);, - nodeOk= !(ads->filterflag & ADS_FILTER_NONTREE);) - } - - /* if only F-Curves with visible flags set can be shown, check that - * datablocks haven't been set to invisible - */ - if (filter_mode & ANIMFILTER_CURVEVISIBLE) { - if ((sce->adt) && (sce->adt->flag & ADT_CURVES_NOT_VISIBLE)) - sceOk= worOk= nodeOk= 0; - } - - /* check if not all bad (i.e. so there is something to show) */ - if ( !(!sceOk && !worOk && !nodeOk) ) { - /* add scene data to the list of filtered channels */ - items += animdata_filter_dopesheet_scene(ac, anim_data, ads, sce, filter_mode); - } - } - + /* scene-linked animation - e.g. world, compositing nodes, scene anim (including sequencer currently) */ + items += animdata_filter_dopesheet_scene(ac, anim_data, ads, sce, filter_mode); - /* loop over all bases in the scene */ + /* loop over all bases (i.e.objects) in the scene */ for (base= sce->base.first; base; base= base->next) { /* check if there's an object (all the relevant checks are done in the ob-function) */ if (base->object) { Object *ob= base->object; - Key *key= ob_get_key(ob); - short actOk=1, keyOk=1, dataOk=1, matOk=1, partOk=1; /* firstly, check if object can be included, by the following factors: * - if only visible, must check for layer and also viewport visibility @@ -2187,10 +1957,10 @@ static int animdata_filter_dopesheet (bAnimContext *ac, ListBase *anim_data, bDo * as user option controls whether sets of channels get included while * tool-flag takes into account collapsed/open channels too * - if only selected, must check if object is selected - * - there must be animation data to edit + * - there must be animation data to edit (this is done recursively as we + * try to add the channels) */ - // TODO: if cache is implemented, just check name here, and then - if ((filter_mode & ANIMFILTER_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { + if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { /* layer visibility - we check both object and base, since these may not be in sync yet */ if ((sce->lay & (ob->lay|base->lay))==0) continue; @@ -2201,280 +1971,26 @@ static int animdata_filter_dopesheet (bAnimContext *ac, ListBase *anim_data, bDo /* if only F-Curves with visible flags set can be shown, check that * datablock hasn't been set to invisible */ - if (filter_mode & ANIMFILTER_CURVEVISIBLE) { + if (filter_mode & ANIMFILTER_CURVE_VISIBLE) { if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE)) continue; } - /* additionally, dopesheet filtering also affects what objects to consider */ - { - /* check selection and object type filters */ - if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/) ) { - /* only selected should be shown */ - continue; - } - - /* check if object belongs to the filtering group if option to filter - * objects by the grouped status is on - * - used to ease the process of doing multiple-character choreographies - */ - if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) { - if (object_in_group(ob, ads->filter_grp) == 0) - continue; - } - - /* check filters for datatypes */ - /* object */ - actOk= 0; - if (!(ads->filterflag & ADS_FILTER_NOOBJ)) { - ANIMDATA_FILTER_CASES(ob, - { - /* for the special AnimData blocks only case, we only need to add - * the block if it is valid... then other cases just get skipped (hence ok=0) - */ - ANIMDATA_ADD_ANIMDATA(ob); - actOk=0; - }, - actOk= 1;, - actOk= 1;, - actOk= 1;) - } - - keyOk= 0; - if ((key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) { - /* shapekeys */ - ANIMDATA_FILTER_CASES(key, - { - /* for the special AnimData blocks only case, we only need to add - * the block if it is valid... then other cases just get skipped (hence ok=0) - */ - ANIMDATA_ADD_ANIMDATA(key); - keyOk=0; - }, - keyOk= 1;, - keyOk= 1;, - keyOk= 1;) - } - - /* materials - only for geometric types */ - matOk= 0; /* by default, not ok... */ - if ( !(ads->filterflag & ADS_FILTER_NOMAT) && (ob->totcol) && - ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL) ) - { - int a; - - /* firstly check that we actuallly have some materials */ - for (a=1; a <= ob->totcol; a++) { - Material *ma= give_current_material(ob, a); - - if (ma) { - /* if material has relevant animation data, break */ - ANIMDATA_FILTER_CASES(ma, - { - /* for the special AnimData blocks only case, we only need to add - * the block if it is valid... then other cases just get skipped (hence ok=0) - */ - ANIMDATA_ADD_ANIMDATA(ma); - matOk=0; - }, - matOk= 1;, - matOk= 1;, - matOk= 1;) - - if (matOk) - break; - - /* textures? */ - // TODO: make this a macro that is used in the other checks too - // NOTE: this has little use on its own, since the actual filtering still ignores if no anim on the data - if (!(ads->filterflag & ADS_FILTER_NOTEX)) { - int mtInd; - - for (mtInd= 0; mtInd < MAX_MTEX; mtInd++) { - MTex *mtex= ma->mtex[mtInd]; - - if (mtex && mtex->tex) { - /* if texture has relevant animation data, break */ - ANIMDATA_FILTER_CASES(mtex->tex, - { - /* for the special AnimData blocks only case, we only need to add - * the block if it is valid... then other cases just get skipped (hence ok=0) - */ - ANIMDATA_ADD_ANIMDATA(mtex->tex); - matOk=0; - }, - matOk= 1;, - matOk= 1;, - matOk= 1;) - - if (matOk) - break; - } - } - } - - } - } - } - - /* data */ - switch (ob->type) { - case OB_CAMERA: /* ------- Camera ------------ */ - { - Camera *ca= (Camera *)ob->data; - dataOk= 0; - ANIMDATA_FILTER_CASES(ca, - if ((ads->filterflag & ADS_FILTER_NOCAM)==0) { - /* for the special AnimData blocks only case, we only need to add - * the block if it is valid... then other cases just get skipped (hence ok=0) - */ - ANIMDATA_ADD_ANIMDATA(ca); - dataOk=0; - }, - dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);, - dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);, - dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);) - } - break; - case OB_LAMP: /* ---------- Lamp ----------- */ - { - Lamp *la= (Lamp *)ob->data; - dataOk= 0; - ANIMDATA_FILTER_CASES(la, - if ((ads->filterflag & ADS_FILTER_NOLAM)==0) { - /* for the special AnimData blocks only case, we only need to add - * the block if it is valid... then other cases just get skipped (hence ok=0) - */ - ANIMDATA_ADD_ANIMDATA(la); - dataOk=0; - }, - dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);, - dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);, - dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);) - } - break; - case OB_CURVE: /* ------- Curve ---------- */ - case OB_SURF: /* ------- Nurbs Surface ---------- */ - case OB_FONT: /* ------- Text Curve ---------- */ - { - Curve *cu= (Curve *)ob->data; - dataOk= 0; - ANIMDATA_FILTER_CASES(cu, - if ((ads->filterflag & ADS_FILTER_NOCUR)==0) { - /* for the special AnimData blocks only case, we only need to add - * the block if it is valid... then other cases just get skipped (hence ok=0) - */ - ANIMDATA_ADD_ANIMDATA(cu); - dataOk=0; - }, - dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);, - dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);, - dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);) - } - break; - case OB_MBALL: /* ------- MetaBall ---------- */ - { - MetaBall *mb= (MetaBall *)ob->data; - dataOk= 0; - ANIMDATA_FILTER_CASES(mb, - if ((ads->filterflag & ADS_FILTER_NOMBA)==0) { - /* for the special AnimData blocks only case, we only need to add - * the block if it is valid... then other cases just get skipped (hence ok=0) - */ - ANIMDATA_ADD_ANIMDATA(mb); - dataOk=0; - }, - dataOk= !(ads->filterflag & ADS_FILTER_NOMBA);, - dataOk= !(ads->filterflag & ADS_FILTER_NOMBA);, - dataOk= !(ads->filterflag & ADS_FILTER_NOMBA);) - } - break; - case OB_ARMATURE: /* ------- Armature ---------- */ - { - bArmature *arm= (bArmature *)ob->data; - dataOk= 0; - ANIMDATA_FILTER_CASES(arm, - if ((ads->filterflag & ADS_FILTER_NOARM)==0) { - /* for the special AnimData blocks only case, we only need to add - * the block if it is valid... then other cases just get skipped (hence ok=0) - */ - ANIMDATA_ADD_ANIMDATA(arm); - dataOk=0; - }, - dataOk= !(ads->filterflag & ADS_FILTER_NOARM);, - dataOk= !(ads->filterflag & ADS_FILTER_NOARM);, - dataOk= !(ads->filterflag & ADS_FILTER_NOARM);) - } - break; - case OB_MESH: /* ------- Mesh ---------- */ - { - Mesh *me= (Mesh *)ob->data; - dataOk= 0; - ANIMDATA_FILTER_CASES(me, - if ((ads->filterflag & ADS_FILTER_NOMESH)==0) { - /* for the special AnimData blocks only case, we only need to add - * the block if it is valid... then other cases just get skipped (hence ok=0) - */ - ANIMDATA_ADD_ANIMDATA(me); - dataOk=0; - }, - dataOk= !(ads->filterflag & ADS_FILTER_NOMESH);, - dataOk= !(ads->filterflag & ADS_FILTER_NOMESH);, - dataOk= !(ads->filterflag & ADS_FILTER_NOMESH);) - } - break; - case OB_LATTICE: /* ------- Lattice ---------- */ - { - Lattice *lt= (Lattice *)ob->data; - dataOk= 0; - ANIMDATA_FILTER_CASES(lt, - if ((ads->filterflag & ADS_FILTER_NOLAT)==0) { - /* for the special AnimData blocks only case, we only need to add - * the block if it is valid... then other cases just get skipped (hence ok=0) - */ - ANIMDATA_ADD_ANIMDATA(lt); - dataOk=0; - }, - dataOk= !(ads->filterflag & ADS_FILTER_NOLAT);, - dataOk= !(ads->filterflag & ADS_FILTER_NOLAT);, - dataOk= !(ads->filterflag & ADS_FILTER_NOLAT);) - } - break; - default: /* --- other --- */ - dataOk= 0; - break; - } - - /* particles */ - partOk = 0; - if (!(ads->filterflag & ADS_FILTER_NOPART) && ob->particlesystem.first) { - ParticleSystem *psys = ob->particlesystem.first; - for(; psys; psys=psys->next) { - if (psys->part) { - /* if particlesettings has relevant animation data, break */ - ANIMDATA_FILTER_CASES(psys->part, - { - /* for the special AnimData blocks only case, we only need to add - * the block if it is valid... then other cases just get skipped (hence ok=0) - */ - ANIMDATA_ADD_ANIMDATA(psys->part); - partOk=0; - }, - partOk= 1;, - partOk= 1;, - partOk= 1;) - } - - if (partOk) - break; - } - } - - /* check if all bad (i.e. nothing to show) */ - if (!actOk && !keyOk && !dataOk && !matOk && !partOk) - continue; + /* check selection and object type filters */ + if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/) ) { + /* only selected should be shown */ + continue; } + /* check if object belongs to the filtering group if option to filter + * objects by the grouped status is on + * - used to ease the process of doing multiple-character choreographies + */ + if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) { + if (object_in_group(ob, ads->filter_grp) == 0) + continue; + } + /* since we're still here, this object should be usable */ items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode); } @@ -2487,7 +2003,7 @@ static int animdata_filter_dopesheet (bAnimContext *ac, ListBase *anim_data, bDo /* Summary track for DopeSheet/Action Editor * - return code is whether the summary lets the other channels get drawn */ -static short animdata_filter_dopesheet_summary (bAnimContext *ac, ListBase *anim_data, int filter_mode, int *items) +static short animdata_filter_dopesheet_summary (bAnimContext *ac, ListBase *anim_data, int filter_mode, size_t *items) { bDopeSheet *ads = NULL; @@ -2496,8 +2012,8 @@ static short animdata_filter_dopesheet_summary (bAnimContext *ac, ListBase *anim * since all the other Animation Editors won't have this concept * being applicable. */ - if ((ac && ac->sa) && (ac->sa->spacetype == SPACE_ACTION)) { - SpaceAction *saction= (SpaceAction *)ac->sa->spacedata.first; + if ((ac && ac->sl) && (ac->spacetype == SPACE_ACTION)) { + SpaceAction *saction= (SpaceAction *)ac->sl; ads= &saction->ads; } else { @@ -2509,9 +2025,8 @@ static short animdata_filter_dopesheet_summary (bAnimContext *ac, ListBase *anim * - only for drawing and/or selecting keyframes in channels, but not for real editing * - only useful for DopeSheet/Action/etc. editors where it is actually 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)) { - bAnimListElem *ale= make_new_animlistelem(ac, ANIMTYPE_SUMMARY, NULL, ANIMTYPE_NONE, NULL); + if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && (ads->filterflag & ADS_FILTER_SUMMARY)) { + bAnimListElem *ale= make_new_animlistelem(ac, ANIMTYPE_SUMMARY, NULL); if (ale) { BLI_addtail(anim_data, ale); (*items)++; @@ -2528,13 +2043,39 @@ static short animdata_filter_dopesheet_summary (bAnimContext *ac, ListBase *anim return 1; } +/* ......................... */ + +/* filter data associated with a channel - usually for handling summary-channels in DopeSheet */ +static size_t animdata_filter_animchan (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bAnimListElem *channel, int filter_mode) +{ + size_t items = 0; + + /* data to filter depends on channel type */ + // XXX: only common channel-types have been handled for now + switch (channel->type) { + case ANIMTYPE_SUMMARY: + items += animdata_filter_dopesheet(ac, anim_data, ads, filter_mode); + break; + + case ANIMTYPE_SCENE: + items += animdata_filter_dopesheet_scene(ac, anim_data, ads, channel->data, filter_mode); + break; + + case ANIMTYPE_OBJECT: + items += animdata_filter_dopesheet_ob(ac, anim_data, ads, channel->data, filter_mode); + break; + } + + return items; +} + /* ----------- Cleanup API --------------- */ /* Remove entries with invalid types in animation channel list */ -static int animdata_filter_remove_invalid (ListBase *anim_data) +static size_t animdata_filter_remove_invalid (ListBase *anim_data) { bAnimListElem *ale, *next; - int items = 0; + size_t items = 0; /* only keep entries with valid types */ for (ale= anim_data->first; ale; ale= next) { @@ -2550,11 +2091,11 @@ static int animdata_filter_remove_invalid (ListBase *anim_data) } /* Remove duplicate entries in animation channel list */ -static int animdata_filter_remove_duplis (ListBase *anim_data) +static size_t animdata_filter_remove_duplis (ListBase *anim_data) { bAnimListElem *ale, *next; GHash *gh; - int items = 0; + size_t items = 0; /* build new hashtable to efficiently store and retrieve which entries have been * encountered already while searching @@ -2596,9 +2137,9 @@ static int animdata_filter_remove_duplis (ListBase *anim_data) * will be placed for use. * filter_mode: how should the data be filtered - bitmapping accessed flags */ -int ANIM_animdata_filter (bAnimContext *ac, ListBase *anim_data, int filter_mode, void *data, short datatype) +size_t ANIM_animdata_filter (bAnimContext *ac, ListBase *anim_data, int filter_mode, void *data, short datatype) { - int items = 0; + size_t items = 0; /* only filter data if there's somewhere to put it */ if (data && anim_data) { @@ -2608,12 +2149,12 @@ int ANIM_animdata_filter (bAnimContext *ac, ListBase *anim_data, int filter_mode switch (datatype) { case ANIMCONT_ACTION: /* 'Action Editor' */ { - SpaceAction *saction = (SpaceAction *)ac->sa->spacedata.first; + SpaceAction *saction = (SpaceAction *)ac->sl; bDopeSheet *ads = (saction)? &saction->ads : NULL; /* the check for the DopeSheet summary is included here since the summary works here too */ if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) - items += animdata_filter_action(ac, anim_data, ads, data, filter_mode, NULL, ANIMTYPE_NONE, (ID *)obact); + items += animfilter_action(ac, anim_data, ads, data, filter_mode, (ID *)obact); } break; @@ -2647,6 +2188,15 @@ int ANIM_animdata_filter (bAnimContext *ac, ListBase *anim_data, int filter_mode items = animdata_filter_dopesheet(ac, anim_data, data, filter_mode); } break; + + case ANIMCONT_CHANNEL: /* animation channel */ + { + bDopeSheet *ads = ac->ads; + + /* based on the channel type, filter relevant data for this */ + items = animdata_filter_animchan(ac, anim_data, ads, data, filter_mode); + } + break; } /* remove any 'weedy' entries */ diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index 209210435e6..fc05f46929b 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -100,6 +100,8 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) * - as base, we use a custom name from the structs if one is available * - however, if we're showing subdata of bones (probably there will be other exceptions later) * need to include that info too since it gets confusing otherwise + * - if a pointer just refers to the ID-block, then don't repeat this info + * since this just introduces clutter */ if (strstr(fcu->rna_path, "bones") && strstr(fcu->rna_path, "constraints")) { /* perform string 'chopping' to get "Bone Name : Constraint Name" */ @@ -114,7 +116,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) if (pchanName) MEM_freeN(pchanName); if (constName) MEM_freeN(constName); } - else { + else if (ptr.data != ptr.id.data) { PropertyRNA *nameprop= RNA_struct_name_property(ptr.type); if (nameprop) { /* this gets a string which will need to be freed */ @@ -145,7 +147,11 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) /* putting this all together into the buffer */ // XXX we need to check for invalid names... - BLI_snprintf(name, 256, "%s%s (%s)", arrayname, propname, structname); + // XXX the name length limit needs to be passed in or as some define + if (structname) + BLI_snprintf(name, 256, "%s%s (%s)", arrayname, propname, structname); + else + BLI_snprintf(name, 256, "%s%s", arrayname, propname); /* free temp name if nameprop is set */ if (free_structname) diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index b3338396598..732fc0bd267 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -1508,3 +1508,14 @@ void ED_marker_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "MARKER_OT_camera_bind", BKEY, KM_PRESS, KM_CTRL, 0); #endif } + +/* to be called from animation editor keymaps, see note below */ +void ED_marker_keymap_animedit_conflictfree(wmKeyMap *keymap) +{ + /* duplicate of some marker-hotkeys but without the bounds checking + * since these are handy to be able to do unrestricted and won't conflict + * with primary function hotkeys (Usability tweak [#27469]) + */ + WM_keymap_add_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0); +} diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 75b54a7529a..c9e422baa3e 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -80,7 +80,7 @@ void free_anim_drivers_copybuf (void); * 1 - add new Driver FCurve, * -1 - add new Driver FCurve without driver stuff (for pasting) */ -static FCurve *verify_driver_fcurve (ID *id, const char rna_path[], const int array_index, short add) +FCurve *verify_driver_fcurve (ID *id, const char rna_path[], const int array_index, short add) { AnimData *adt; FCurve *fcu; diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c index 954928fc486..8197d6b25dd 100644 --- a/source/blender/editors/animation/fmodifier_ui.c +++ b/source/blender/editors/animation/fmodifier_ui.c @@ -604,7 +604,7 @@ static void draw_modifier__stepped(uiLayout *layout, ID *id, FModifier *fcm, sho void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm) { FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); - uiLayout *box, *row, *subrow; + uiLayout *box, *row, *subrow, *col; uiBlock *block; uiBut *but; short width= 314; @@ -622,7 +622,7 @@ void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifie block= uiLayoutGetBlock(row); // err... /* left-align -------------------------------------------- */ - subrow= uiLayoutRow(row, 0); + subrow= uiLayoutRow(row, 1); uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_LEFT); uiBlockSetEmboss(block, UI_EMBOSSN); @@ -640,7 +640,7 @@ void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifie uiItemL(subrow, "<Unknown Modifier>", ICON_NONE); /* right-align ------------------------------------------- */ - subrow= uiLayoutRow(row, 0); + subrow= uiLayoutRow(row, 1); uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_RIGHT); @@ -694,6 +694,44 @@ void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifie default: /* unknown type */ break; } + + /* one last panel below this: FModifier range */ + // TODO: experiment with placement of this + { + box = uiLayoutBox(layout); + + /* restricted range ----------------------------------------------------- */ + col = uiLayoutColumn(box, 1); + + /* top row: use restricted range */ + row= uiLayoutRow(col, 1); + uiItemR(row, &ptr, "use_restricted_range", 0, NULL, ICON_NONE); + + if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) { + /* second row: settings */ + row = uiLayoutRow(col, 1); + + uiItemR(row, &ptr, "frame_start", 0, "Start", ICON_NONE); + uiItemR(row, &ptr, "frame_end", 0, "End", ICON_NONE); + + /* third row: blending influence */ + row = uiLayoutRow(col, 1); + + uiItemR(row, &ptr, "blend_in", 0, "In", ICON_NONE); + uiItemR(row, &ptr, "blend_out", 0, "Out", ICON_NONE); + } + + /* influence -------------------------------------------------------------- */ + col = uiLayoutColumn(box, 1); + + /* top row: use influence */ + uiItemR(col, &ptr, "use_influence", 0, NULL, ICON_NONE); + + if (fcm->flag & FMODIFIER_FLAG_USEINFLUENCE) { + /* second row: influence value */ + uiItemR(col, &ptr, "influence", 0, NULL, ICON_NONE); + } + } } } diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index 00e11d8b1a4..b774bc947e4 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -773,7 +773,7 @@ void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, DLRBT_Tree *blocks) int filter; /* get F-Curves to take keyframes from */ - filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY); + filter= ANIMFILTER_DATA_VISIBLE; // curves only ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* loop through each F-Curve, grabbing the keyframes */ @@ -786,150 +786,71 @@ void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, DLRBT_Tree *blocks) void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, DLRBT_Tree *blocks) { - if (sce) { - AnimData *adt; - int filterflag; - - /* get filterflag */ - if (ads) - filterflag= ads->filterflag; - else - filterflag= 0; - - /* scene animdata */ - if ((sce->adt) && !(filterflag & ADS_FILTER_NOSCE)) { - adt= sce->adt; - - if (adt->action) - action_to_keylist(adt, adt->action, keys, blocks); - } - - /* world animdata */ - if ((sce->world) && (sce->world->adt) && !(filterflag & ADS_FILTER_NOWOR)) { - adt= sce->world->adt; - - if (adt->action) - action_to_keylist(adt, adt->action, keys, blocks); - } - - /* nodetree animdata */ - if ((sce->nodetree) && (sce->nodetree->adt) && !(filterflag & ADS_FILTER_NONTREE)) { - adt= sce->nodetree->adt; - - if (adt->action) - action_to_keylist(adt, adt->action, keys, blocks); - } - } + bAnimContext ac = {NULL}; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + bAnimListElem dummychan = {0}; + + if (sce == NULL) + return; + + /* create a dummy wrapper data to work with */ + dummychan.type = ANIMTYPE_SCENE; + dummychan.data = sce; + dummychan.id = &sce->id; + dummychan.adt = sce->adt; + + ac.ads = ads; + ac.data = &dummychan; + ac.datatype = ANIMCONT_CHANNEL; + + /* get F-Curves to take keyframes from */ + filter= ANIMFILTER_DATA_VISIBLE; // curves only + 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 ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, DLRBT_Tree *blocks) -{ - Key *key= ob_get_key(ob); - int filterflag= (ads)? ads->filterflag : 0; +{ + bAnimContext ac = {NULL}; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + bAnimListElem dummychan = {0}; + Base dummybase = {0}; - /* sanity check */ if (ob == NULL) return; - - /* Add action keyframes */ - if (ob->adt && ob->adt->action) - action_to_keylist(ob->adt, ob->adt->action, keys, blocks); - /* Add shapekey keyframes (only if dopesheet allows, if it is available) */ - if ((key && key->adt && key->adt->action) && !(filterflag & ADS_FILTER_NOSHAPEKEYS)) - action_to_keylist(key->adt, key->adt->action, keys, blocks); + /* create a dummy wrapper data to work with */ + dummybase.object = ob; - /* Add material keyframes */ - if ((ob->totcol) && !(filterflag & ADS_FILTER_NOMAT)) { - int a; - - for (a=1; a <= ob->totcol; a++) { - Material *ma= give_current_material(ob, a); - - /* there might not be a material */ - if (ELEM(NULL, ma, ma->adt)) - continue; - - /* add material's data */ - action_to_keylist(ma->adt, ma->adt->action, keys, blocks); - - // TODO: textures... - } - } + dummychan.type = ANIMTYPE_OBJECT; + dummychan.data = &dummybase; + dummychan.id = &ob->id; + dummychan.adt = ob->adt; - /* Add object data keyframes */ - switch (ob->type) { - case OB_CAMERA: /* ------- Camera ------------ */ - { - Camera *ca= (Camera *)ob->data; - - if ((ca->adt) && !(filterflag & ADS_FILTER_NOCAM)) - action_to_keylist(ca->adt, ca->adt->action, keys, blocks); - } - break; - case OB_LAMP: /* ---------- Lamp ----------- */ - { - Lamp *la= (Lamp *)ob->data; - - if ((la->adt) && !(filterflag & ADS_FILTER_NOLAM)) - action_to_keylist(la->adt, la->adt->action, keys, blocks); - } - break; - case OB_CURVE: /* ------- Curve ---------- */ - case OB_SURF: /* ------- Nurbs Surface ---------- */ - case OB_FONT: /* ------- Text Curve ---------- */ - { - Curve *cu= (Curve *)ob->data; - - if ((cu->adt) && !(filterflag & ADS_FILTER_NOCUR)) - action_to_keylist(cu->adt, cu->adt->action, keys, blocks); - } - break; - case OB_MBALL: /* ------- MetaBall ---------- */ - { - MetaBall *mb= (MetaBall *)ob->data; - - if ((mb->adt) && !(filterflag & ADS_FILTER_NOMBA)) - action_to_keylist(mb->adt, mb->adt->action, keys, blocks); - } - break; - case OB_ARMATURE: /* ------- Armature ---------- */ - { - bArmature *arm= (bArmature *)ob->data; - - if ((arm->adt) && !(filterflag & ADS_FILTER_NOARM)) - action_to_keylist(arm->adt, arm->adt->action, keys, blocks); - } - break; - case OB_MESH: /* ------- Mesh ---------- */ - { - Mesh *me= (Mesh *)ob->data; - - if ((me->adt) && !(filterflag & ADS_FILTER_NOMESH)) - action_to_keylist(me->adt, me->adt->action, keys, blocks); - } - break; - case OB_LATTICE: /* ------- Lattice ---------- */ - { - Lattice *lt= (Lattice *)ob->data; - - if ((lt->adt) && !(filterflag & ADS_FILTER_NOLAT)) - action_to_keylist(lt->adt, lt->adt->action, keys, blocks); - } - break; - } + ac.ads = ads; + ac.data = &dummychan; + ac.datatype = ANIMCONT_CHANNEL; - /* Add Particle System Keyframes */ - if ((ob->particlesystem.first) && !(filterflag & ADS_FILTER_NOPART)) { - ParticleSystem *psys = ob->particlesystem.first; - - for(; psys; psys=psys->next) { - if (ELEM(NULL, psys->part, psys->part->adt)) - continue; - else - action_to_keylist(psys->part->adt, psys->part->adt->action, keys, blocks); - } - } + /* get F-Curves to take keyframes from */ + filter= ANIMFILTER_DATA_VISIBLE; // curves only + 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 fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, DLRBT_Tree *blocks) diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index e50203cbc28..9f3d40a5709 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -197,196 +197,95 @@ static short act_keyframes_loop(KeyframeEditData *ked, bAction *act, KeyframeEdi return 0; } -/* This function is used to loop over the keyframe data of an AnimData block */ -static short adt_keyframes_loop(KeyframeEditData *ked, AnimData *adt, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb, int filterflag) -{ - /* sanity check */ - if (adt == NULL) - return 0; - - /* drivers or actions? */ - if (filterflag & ADS_FILTER_ONLYDRIVERS) { - FCurve *fcu; - - /* just loop through all F-Curves acting as Drivers */ - for (fcu= adt->drivers.first; fcu; fcu= fcu->next) { - if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb)) - return 1; - } - } - else if (adt->action) { - /* call the function for actions */ - if (act_keyframes_loop(ked, adt->action, key_ok, key_cb, fcu_cb)) - return 1; - } - - return 0; -} - /* This function is used to loop over the keyframe data in an Object */ -static short ob_keyframes_loop(KeyframeEditData *ked, Object *ob, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb, int filterflag) +static short ob_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, Object *ob, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb) { - Key *key= ob_get_key(ob); + bAnimContext ac = {NULL}; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + int ret=0; + + bAnimListElem dummychan = {0}; + Base dummybase = {0}; - /* sanity check */ if (ob == NULL) return 0; - /* firstly, Object's own AnimData */ - if (ob->adt) { - if (adt_keyframes_loop(ked, ob->adt, key_ok, key_cb, fcu_cb, filterflag)) - return 1; - } + /* create a dummy wrapper data to work with */ + dummybase.object = ob; - /* shapekeys */ - if ((key && key->adt) && !(filterflag & ADS_FILTER_NOSHAPEKEYS)) { - if (adt_keyframes_loop(ked, key->adt, key_ok, key_cb, fcu_cb, filterflag)) - return 1; - } - - /* Add material keyframes */ - if ((ob->totcol) && !(filterflag & ADS_FILTER_NOMAT)) { - int a; - - for (a=1; a <= ob->totcol; a++) { - Material *ma= give_current_material(ob, a); - - /* there might not be a material */ - if (ELEM(NULL, ma, ma->adt)) - continue; - - /* add material's data */ - if (adt_keyframes_loop(ked, ma->adt, key_ok, key_cb, fcu_cb, filterflag)) - return 1; - } - } + dummychan.type = ANIMTYPE_OBJECT; + dummychan.data = &dummybase; + dummychan.id = &ob->id; + dummychan.adt = ob->adt; - /* Add object data keyframes */ - switch (ob->type) { - case OB_CAMERA: /* ------- Camera ------------ */ - { - Camera *ca= (Camera *)ob->data; - - if ((ca->adt) && !(filterflag & ADS_FILTER_NOCAM)) { - if (adt_keyframes_loop(ked, ca->adt, key_ok, key_cb, fcu_cb, filterflag)) - return 1; - } - } - break; - case OB_LAMP: /* ---------- Lamp ----------- */ - { - Lamp *la= (Lamp *)ob->data; - - if ((la->adt) && !(filterflag & ADS_FILTER_NOLAM)) { - if (adt_keyframes_loop(ked, la->adt, key_ok, key_cb, fcu_cb, filterflag)) - return 1; - } - } - break; - case OB_CURVE: /* ------- Curve ---------- */ - case OB_SURF: /* ------- Nurbs Surface ---------- */ - case OB_FONT: /* ------- Text Curve ---------- */ - { - Curve *cu= (Curve *)ob->data; - - if ((cu->adt) && !(filterflag & ADS_FILTER_NOCUR)) { - if (adt_keyframes_loop(ked, cu->adt, key_ok, key_cb, fcu_cb, filterflag)) - return 1; - } - } - break; - case OB_MBALL: /* ------- MetaBall ---------- */ - { - MetaBall *mb= (MetaBall *)ob->data; - - if ((mb->adt) && !(filterflag & ADS_FILTER_NOMBA)) { - if (adt_keyframes_loop(ked, mb->adt, key_ok, key_cb, fcu_cb, filterflag)) - return 1; - } - } - break; - case OB_ARMATURE: /* ------- Armature ---------- */ - { - bArmature *arm= (bArmature *)ob->data; - - if ((arm->adt) && !(filterflag & ADS_FILTER_NOARM)) { - if (adt_keyframes_loop(ked, arm->adt, key_ok, key_cb, fcu_cb, filterflag)) - return 1; - } - } - break; - case OB_MESH: /* ------- Mesh ---------- */ - { - Mesh *me= (Mesh *)ob->data; - - if ((me->adt) && !(filterflag & ADS_FILTER_NOMESH)) { - if (adt_keyframes_loop(ked, me->adt, key_ok, key_cb, fcu_cb, filterflag)) - return 1; - } - } + ac.ads = ads; + ac.data = &dummychan; + ac.datatype = ANIMCONT_CHANNEL; + + /* get F-Curves to take keyframes from */ + filter= ANIMFILTER_DATA_VISIBLE; // curves only + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* loop through each F-Curve, applying the operation as required, but stopping on the first one */ + for (ale= anim_data.first; ale; ale= ale->next) { + if (ANIM_fcurve_keyframes_loop(ked, (FCurve*)ale->data, key_ok, key_cb, fcu_cb)) { + ret = 1; break; - case OB_LATTICE: /* ---- Lattice ------ */ - { - Lattice *lt= (Lattice *)ob->data; - - if ((lt->adt) && !(filterflag & ADS_FILTER_NOLAT)) { - if (adt_keyframes_loop(ked, lt->adt, key_ok, key_cb, fcu_cb, filterflag)) - return 1; - } } - break; } - /* Add Particle System Keyframes */ - if ((ob->particlesystem.first) && !(filterflag & ADS_FILTER_NOPART)) { - ParticleSystem *psys = ob->particlesystem.first; - - for(; psys; psys=psys->next) { - if (ELEM(NULL, psys->part, psys->part->adt)) - continue; - - if (adt_keyframes_loop(ked, psys->part->adt, key_ok, key_cb, fcu_cb, filterflag)) - return 1; - } - } + BLI_freelistN(&anim_data); - return 0; + /* return return code - defaults to zero if nothing happened */ + return ret; } /* This function is used to loop over the keyframe data in a Scene */ -static short scene_keyframes_loop(KeyframeEditData *ked, Scene *sce, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb, int filterflag) +static short scene_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, Scene *sce, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb) { - World *wo= (sce) ? sce->world : NULL; - bNodeTree *ntree= (sce) ? sce->nodetree : NULL; + bAnimContext ac = {NULL}; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + int ret=0; + + bAnimListElem dummychan = {0}; - /* sanity check */ if (sce == NULL) return 0; - /* Scene's own animation */ - if (sce->adt) { - if (adt_keyframes_loop(ked, sce->adt, key_ok, key_cb, fcu_cb, filterflag)) - return 1; - } + /* create a dummy wrapper data to work with */ + dummychan.type = ANIMTYPE_SCENE; + dummychan.data = sce; + dummychan.id = &sce->id; + dummychan.adt = sce->adt; - /* World */ - if (wo && wo->adt) { - if (adt_keyframes_loop(ked, wo->adt, key_ok, key_cb, fcu_cb, filterflag)) - return 1; - } + ac.ads = ads; + ac.data = &dummychan; + ac.datatype = ANIMCONT_CHANNEL; - /* NodeTree */ - if (ntree && ntree->adt) { - if (adt_keyframes_loop(ked, ntree->adt, key_ok, key_cb, fcu_cb, filterflag)) - return 1; + /* get F-Curves to take keyframes from */ + filter= ANIMFILTER_DATA_VISIBLE; // curves only + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* loop through each F-Curve, applying the operation as required, but stopping on the first one */ + for (ale= anim_data.first; ale; ale= ale->next) { + if (ANIM_fcurve_keyframes_loop(ked, (FCurve*)ale->data, key_ok, key_cb, fcu_cb)) { + ret = 1; + break; + } } + BLI_freelistN(&anim_data); - return 0; + /* return return code - defaults to zero if nothing happened */ + return ret; } /* This function is used to loop over the keyframe data in a DopeSheet summary */ -static short summary_keyframes_loop(KeyframeEditData *ked, bAnimContext *ac, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb, int UNUSED(filterflag)) +static short summary_keyframes_loop(KeyframeEditData *ked, bAnimContext *ac, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; @@ -397,7 +296,7 @@ static short summary_keyframes_loop(KeyframeEditData *ked, bAnimContext *ac, Key return 0; /* get F-Curves to take keyframes from */ - filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY); + filter= ANIMFILTER_DATA_VISIBLE; 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 */ @@ -416,7 +315,7 @@ static short summary_keyframes_loop(KeyframeEditData *ked, bAnimContext *ac, Key /* --- */ /* This function is used to apply operation to all keyframes, regardless of the type */ -short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked, bAnimListElem *ale, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb, int filterflag) +short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, bAnimListElem *ale, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb) { /* sanity checks */ if (ale == NULL) @@ -437,18 +336,18 @@ short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked, bAnimListElem *ale, return act_keyframes_loop(ked, (bAction *)ale->key_data, key_ok, key_cb, fcu_cb); case ALE_OB: /* object */ - return ob_keyframes_loop(ked, (Object *)ale->key_data, key_ok, key_cb, fcu_cb, filterflag); + return ob_keyframes_loop(ked, ads, (Object *)ale->key_data, key_ok, key_cb, fcu_cb); case ALE_SCE: /* scene */ - return scene_keyframes_loop(ked, (Scene *)ale->data, key_ok, key_cb, fcu_cb, filterflag); + return scene_keyframes_loop(ked, ads, (Scene *)ale->data, key_ok, key_cb, fcu_cb); case ALE_ALL: /* 'all' (DopeSheet summary) */ - return summary_keyframes_loop(ked, (bAnimContext *)ale->data, key_ok, key_cb, fcu_cb, filterflag); + return summary_keyframes_loop(ked, (bAnimContext *)ale->data, key_ok, key_cb, fcu_cb); } return 0; } /* This function is used to apply operation to all keyframes, regardless of the type without needed an AnimListElem wrapper */ -short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked, void *data, int keytype, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb, int filterflag) +short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, void *data, int keytype, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb) { /* sanity checks */ if (data == NULL) @@ -469,11 +368,11 @@ short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked, void *data, int return act_keyframes_loop(ked, (bAction *)data, key_ok, key_cb, fcu_cb); case ALE_OB: /* object */ - return ob_keyframes_loop(ked, (Object *)data, key_ok, key_cb, fcu_cb, filterflag); + return ob_keyframes_loop(ked, ads, (Object *)data, key_ok, key_cb, fcu_cb); case ALE_SCE: /* scene */ - return scene_keyframes_loop(ked, (Scene *)data, key_ok, key_cb, fcu_cb, filterflag); + return scene_keyframes_loop(ked, ads, (Scene *)data, key_ok, key_cb, fcu_cb); case ALE_ALL: /* 'all' (DopeSheet summary) */ - return summary_keyframes_loop(ked, (bAnimContext *)data, key_ok, key_cb, fcu_cb, filterflag); + return summary_keyframes_loop(ked, (bAnimContext *)data, key_ok, key_cb, fcu_cb); } return 0; @@ -491,7 +390,7 @@ void ANIM_editkeyframes_refresh(bAnimContext *ac) int filter; /* filter animation data */ - filter= ANIMFILTER_CURVESONLY; + filter= ANIMFILTER_DATA_VISIBLE; ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* loop over F-Curves that are likely to have been edited, and check them */ diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index f111339b963..e2afda04d30 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -111,7 +111,7 @@ void delete_fcurve_keys(FCurve *fcu) { int i; - if(fcu->bezt==NULL) /* ignore baked curves */ + if (fcu->bezt==NULL) /* ignore baked curves */ return; /* Delete selected BezTriples */ @@ -124,7 +124,7 @@ void delete_fcurve_keys(FCurve *fcu) } /* Free the array of BezTriples if there are not keyframes */ - if(fcu->totvert == 0) + if (fcu->totvert == 0) clear_fcurve_keys(fcu); } diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index c525c9af626..69e7c4eb73a 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -224,6 +224,7 @@ static int add_empty_ks_path_exec (bContext *C, wmOperator *op) ksp->groupmode= KSP_GROUP_KSNAME; // XXX? ksp->idtype= ID_OB; + ksp->flag= KSP_FLAG_WHOLE_ARRAY; return OPERATOR_FINISHED; } @@ -782,19 +783,19 @@ void ANIM_keying_sets_menu_setup (bContext *C, const char title[], const char op * - these are listed in the order in which they were defined for the active scene */ if (scene->keyingsets.first) { - for (ks= scene->keyingsets.first; ks; ks= ks->next) { + for (ks= scene->keyingsets.first; ks; ks=ks->next, i++) { if (ANIM_keyingset_context_ok_poll(C, ks)) - uiItemIntO(layout, ks->name, ICON_NONE, op_name, "type", i++); + uiItemIntO(layout, ks->name, ICON_NONE, op_name, "type", i); } uiItemS(layout); } /* builtin Keying Sets */ i= -1; - for (ks= builtin_keyingsets.first; ks; ks= ks->next) { + for (ks= builtin_keyingsets.first; ks; ks=ks->next, i--) { /* only show KeyingSet if context is suitable */ if (ANIM_keyingset_context_ok_poll(C, ks)) - uiItemEnumO_value(layout, ks->name, ICON_NONE, op_name, "type", i--); + uiItemEnumO_value(layout, ks->name, ICON_NONE, op_name, "type", i); } uiPupMenuEnd(C, pup); |