diff options
Diffstat (limited to 'source/blender/editors/animation')
18 files changed, 1943 insertions, 2332 deletions
diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt index 66ec9cf75d6..a3c1d035d9b 100644 --- a/source/blender/editors/animation/CMakeLists.txt +++ b/source/blender/editors/animation/CMakeLists.txt @@ -22,6 +22,7 @@ set(INC ../include ../../blenkernel + ../../blenloader ../../blenlib ../../makesdna ../../makesrna @@ -29,6 +30,10 @@ set(INC ../../../../intern/guardedalloc ) +set(INC_SYS + ${GLEW_INCLUDE_PATH} +) + set(SRC anim_channels_defines.c anim_channels_edit.c @@ -49,4 +54,4 @@ set(SRC anim_intern.h ) -blender_add_lib(bf_editor_animation "${SRC}" "${INC}") +blender_add_lib(bf_editor_animation "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/animation/SConscript b/source/blender/editors/animation/SConscript index 4597a612c7c..96b05b8bccc 100644 --- a/source/blender/editors/animation/SConscript +++ b/source/blender/editors/animation/SConscript @@ -4,6 +4,6 @@ Import ('env') sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../makesrna ../../imbuf' -incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' +incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include ../../blenloader' env.BlenderLib ( 'bf_editors_animation', sources, Split(incs), [], libtype=['core'], priority=[125] ) diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index b2ee2f008f5..5e23b49fc22 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -25,6 +25,11 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/editors/animation/anim_channels_defines.c + * \ingroup edanimation + */ + + #include <stdio.h> #include "MEM_guardedalloc.h" @@ -154,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; @@ -230,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; @@ -261,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 */ @@ -319,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) { @@ -454,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 */ @@ -464,7 +439,7 @@ static void *acf_summary_setting_ptr(bAnimListElem *ale, int setting, short *typ else { /* can't return anything useful - unsupported */ *type= 0; - return 0; + return NULL; } } @@ -565,7 +540,7 @@ static void *acf_scene_setting_ptr(bAnimListElem *ale, int setting, short *type) return NULL; default: /* unsupported */ - return 0; + return NULL; } } @@ -709,7 +684,7 @@ static void *acf_object_setting_ptr(bAnimListElem *ale, int setting, short *type return NULL; default: /* unsupported */ - return 0; + return NULL; } } @@ -777,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; @@ -874,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: @@ -990,13 +965,13 @@ static void *acf_fillactd_setting_ptr(bAnimListElem *ale, int setting, short *ty GET_ACF_FLAG_PTR(adt->flag); } else - return 0; + return NULL; case ACHANNEL_SETTING_EXPAND: /* expanded */ GET_ACF_FLAG_PTR(act->flag); default: /* unsupported */ - return 0; + return NULL; } } @@ -1023,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) @@ -1074,7 +1049,7 @@ static void *acf_filldrivers_setting_ptr(bAnimListElem *ale, int setting, short GET_ACF_FLAG_PTR(adt->flag); default: /* unsupported */ - return 0; + return NULL; } } @@ -1096,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 ------------------------------------------- */ @@ -1302,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) { @@ -1363,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 */ @@ -1461,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 */ @@ -1529,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 */ @@ -2097,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) { @@ -2154,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 */ @@ -2564,7 +2335,7 @@ static bAnimChannelType *animchannelTypeInfo[ANIMTYPE_NUM_TYPES]; static short ACF_INIT= 1; /* when non-zero, the list needs to be updated */ /* Initialise type info definitions */ -void ANIM_init_channel_typeinfo_data (void) +static void ANIM_init_channel_typeinfo_data (void) { int type= 0; @@ -2585,9 +2356,6 @@ 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 */ @@ -2855,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) { @@ -2887,6 +2655,7 @@ void ANIM_channel_draw (bAnimContext *ac, bAnimListElem *ale, float yminc, float char name[ANIM_CHAN_NAME_SIZE]; /* hopefully this will be enough! */ /* set text color */ + // XXX: if active, highlight differently? if (selected) UI_ThemeColor(TH_TEXT_HI); else @@ -2925,17 +2694,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; @@ -3008,11 +2777,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 */ @@ -3122,9 +2888,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."; @@ -3153,7 +2919,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; @@ -3219,7 +2985,7 @@ void ANIM_channel_draw_widgets (bAnimContext *ac, bAnimListElem *ale, uiBlock *b { bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale); View2D *v2d= &ac->ar->v2d; - float y, ymid, ytext; + float y, ymid /*, ytext*/; short offset; /* sanity checks - don't draw anything */ @@ -3238,7 +3004,7 @@ void ANIM_channel_draw_widgets (bAnimContext *ac, bAnimListElem *ale, uiBlock *b y= (ymaxc - yminc)/2 + yminc; ymid= y - 7; /* y-coordinates for text is only 4 down from middle */ - ytext= y - 4; + /* ytext= y - 4; */ /* no button backdrop behind icons */ uiBlockSetEmboss(block, UI_EMBOSSN); @@ -3259,7 +3025,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); @@ -3270,6 +3036,7 @@ void ANIM_channel_draw_widgets (bAnimContext *ac, bAnimListElem *ale, uiBlock *b draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_SOLO); offset += ICON_WIDTH; } + (void)offset; } /* step 4) draw text... */ @@ -3285,17 +3052,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; @@ -3364,7 +3131,7 @@ void ANIM_channel_draw_widgets (bAnimContext *ac, bAnimListElem *ale, uiBlock *b uiBut *but; /* create the slider button, and assign relevant callback to ensure keyframes are inserted... */ - but= uiDefAutoButR(block, &ptr, prop, array_index, "", ICON_NULL, (int)v2d->cur.xmax-offset, ymid, SLIDER_WIDTH, (int)ymaxc-yminc); + but= uiDefAutoButR(block, &ptr, prop, array_index, "", ICON_NONE, (int)v2d->cur.xmax-offset, ymid, SLIDER_WIDTH, (int)ymaxc-yminc); /* assign keyframing function according to slider type */ if (ale->type == ANIMTYPE_SHAPEKEY) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index c5d32492f87..eee7fb0badd 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -25,6 +25,11 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/editors/animation/anim_channels_edit.c + * \ingroup edanimation + */ + + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -33,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" @@ -46,6 +51,7 @@ #include "BKE_action.h" #include "BKE_fcurve.h" +#include "BKE_gpencil.h" #include "BKE_context.h" #include "BKE_global.h" @@ -164,9 +170,9 @@ void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int case ANIMTYPE_DSLAT: { /* need to verify that this data is valid for now */ - // XXX: ale may be null! - if (ale->adt) + if (ale && ale->adt) { ale->adt->flag |= ADT_UI_ACTIVE; + } } break; } @@ -189,7 +195,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 */ @@ -510,12 +517,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); @@ -527,7 +556,7 @@ void ANIM_fcurve_delete_from_animdata (bAnimContext *ac, AnimData *adt, FCurve * /* ****************** Operator Utilities ********************************** */ /* poll callback for being in an Animation Editor channels list region */ -int animedit_poll_channels_active (bContext *C) +static int animedit_poll_channels_active (bContext *C) { ScrArea *sa= CTX_wm_area(C); @@ -543,7 +572,7 @@ int animedit_poll_channels_active (bContext *C) } /* poll callback for Animation Editor channels list region + not in NLA-tweakmode for NLA */ -int animedit_poll_channels_nla_tweakmode_off (bContext *C) +static int animedit_poll_channels_nla_tweakmode_off (bContext *C) { ScrArea *sa= CTX_wm_area(C); Scene *scene = CTX_data_scene(C); @@ -577,7 +606,7 @@ enum { }; /* defines for rearranging channels */ -EnumPropertyItem prop_animchannel_rearrange_types[] = { +static EnumPropertyItem prop_animchannel_rearrange_types[] = { {REARRANGE_ANIMCHAN_TOP, "TOP", 0, "To Top", ""}, {REARRANGE_ANIMCHAN_UP, "UP", 0, "Up", ""}, {REARRANGE_ANIMCHAN_DOWN, "DOWN", 0, "Down", ""}, @@ -585,57 +614,46 @@ EnumPropertyItem prop_animchannel_rearrange_types[] = { {0, NULL, 0, NULL, NULL} }; -/* Rearrange Utilities --------------------------------------------- */ +/* Reordering "Islands" Defines ----------------------------------- */ -/* checks if a channel should be considered for moving */ -static short rearrange_animchannel_is_ok (Link *channel, short type) -{ - if (type == ANIMTYPE_GROUP) { - bActionGroup *agrp= (bActionGroup *)channel; - - if (SEL_AGRP(agrp) && !(agrp->flag & AGRP_MOVED)) - return 1; - } - else if (type == ANIMTYPE_FCURVE) { - FCurve *fcu= (FCurve *)channel; - - // FIXME: F-Curve visibility is difficult... needs special filtering tests these days... - if (SEL_FCU(fcu) && !(fcu->flag & FCURVE_TAGGED)) - return 1; - } - else if (type == ANIMTYPE_NLATRACK) { - NlaTrack *nlt = (NlaTrack *)channel; - - if (SEL_NLT(nlt) && !(nlt->flag & NLASTRIP_FLAG_EDIT_TOUCHED)) - return 1; - } +/* Island definition - just a listbase container */ +typedef struct tReorderChannelIsland { + struct tReorderChannelIsland *next, *prev; - return 0; -} + ListBase channels; /* channels within this region with the same state */ + int flag; /* eReorderIslandFlag */ +} tReorderChannelIsland; + +/* flags for channel reordering islands */ +typedef enum eReorderIslandFlag { + REORDER_ISLAND_SELECTED = (1<<0), /* island is selected */ + REORDER_ISLAND_UNTOUCHABLE = (1<<1), /* island should be ignored */ + REORDER_ISLAND_MOVED = (1<<2) /* island has already been moved */ +} eReorderIslandFlag; -/* checks if another channel can be placed after the given one */ -static short rearrange_animchannel_after_ok (Link *channel, short type) + +/* Rearrange Methods --------------------------------------------- */ + +static short rearrange_island_ok (tReorderChannelIsland *island) { - if (type == ANIMTYPE_GROUP) { - bActionGroup *agrp= (bActionGroup *)channel; - - if (agrp->flag & AGRP_TEMP) - return 0; - } + /* island must not be untouchable */ + if (island->flag & REORDER_ISLAND_UNTOUCHABLE) + return 0; - return 1; + /* island should be selected to be moved */ + return (island->flag & REORDER_ISLAND_SELECTED) && !(island->flag & REORDER_ISLAND_MOVED); } -/* Rearrange Methods --------------------------------------------- */ +/* ............................. */ -static short rearrange_animchannel_top (ListBase *list, Link *channel, short type) +static short rearrange_island_top (ListBase *list, tReorderChannelIsland *island) { - if (rearrange_animchannel_is_ok(channel, type)) { - /* take it out off the chain keep data */ - BLI_remlink(list, channel); + if (rearrange_island_ok(island)) { + /* remove from current position */ + BLI_remlink(list, island); /* make it first element */ - BLI_insertlinkbefore(list, list->first, channel); + BLI_insertlinkbefore(list, list->first, island); return 1; } @@ -643,17 +661,18 @@ static short rearrange_animchannel_top (ListBase *list, Link *channel, short typ return 0; } -static short rearrange_animchannel_up (ListBase *list, Link *channel, short type) +static short rearrange_island_up (ListBase *list, tReorderChannelIsland *island) { - if (rearrange_animchannel_is_ok(channel, type)) { - Link *prev= channel->prev; + if (rearrange_island_ok(island)) { + /* moving up = moving before the previous island, otherwise we're in the same place */ + tReorderChannelIsland *prev= island->prev; if (prev) { - /* take it out off the chain keep data */ - BLI_remlink(list, channel); + /* remove from current position */ + BLI_remlink(list, island); /* push it up */ - BLI_insertlinkbefore(list, prev, channel); + BLI_insertlinkbefore(list, prev, island); return 1; } @@ -662,110 +681,200 @@ static short rearrange_animchannel_up (ListBase *list, Link *channel, short type return 0; } -static short rearrange_animchannel_down (ListBase *list, Link *channel, short type) +static short rearrange_island_down (ListBase *list, tReorderChannelIsland *island) { - if (rearrange_animchannel_is_ok(channel, type)) { - Link *next = (channel->next) ? channel->next->next : NULL; + if (rearrange_island_ok(island)) { + /* moving down = moving after the next island, otherwise we're in the same place */ + tReorderChannelIsland *next = island->next; if (next) { - /* take it out off the chain keep data */ - BLI_remlink(list, channel); - - /* move it down */ - BLI_insertlinkbefore(list, next, channel); - - return 1; - } - else if (rearrange_animchannel_after_ok(list->last, type)) { - /* take it out off the chain keep data */ - BLI_remlink(list, channel); - - /* add at end */ - BLI_addtail(list, channel); - - return 1; - } - else { - /* take it out off the chain keep data */ - BLI_remlink(list, channel); - - /* add just before end */ - BLI_insertlinkbefore(list, list->last, channel); - - return 1; + /* can only move past if next is not untouchable (i.e. nothing can go after it) */ + if ((next->flag & REORDER_ISLAND_UNTOUCHABLE)==0) { + /* remove from current position */ + BLI_remlink(list, island); + + /* push it down */ + BLI_insertlinkafter(list, next, island); + + return 1; + } } + /* else: no next channel, so we're at the bottom already, so can't move */ } return 0; } -static short rearrange_animchannel_bottom (ListBase *list, Link *channel, short type) +static short rearrange_island_bottom (ListBase *list, tReorderChannelIsland *island) { - if (rearrange_animchannel_is_ok(channel, type)) { - if (rearrange_animchannel_after_ok(list->last, type)) { - /* take it out off the chain keep data */ - BLI_remlink(list, channel); - - /* add at end */ - BLI_addtail(list, channel); + if (rearrange_island_ok(island)) { + tReorderChannelIsland *last = list->last; + + /* remove island from current position */ + BLI_remlink(list, island); + + /* add before or after the last channel? */ + if ((last->flag & REORDER_ISLAND_UNTOUCHABLE)==0) { + /* can add after it */ + BLI_addtail(list, island); + } + else { + /* can at most go just before it, since last cannot be moved */ + BLI_insertlinkbefore(list, last, island); - return 1; } + + return 1; } return 0; } -/* Generic Stuff ---------------------------------------------------------- */ +/* ............................. */ /* typedef for channel rearranging function * < list: list that channels belong to - * < channel: channel to be moved - * < type: type of channel (eAnim_ChannelType) + * < island: island to be moved * > return[0]: whether operation was a success */ -typedef short (*AnimChanRearrangeFp)(ListBase *list, Link *channel, short type); +typedef short (*AnimChanRearrangeFp)(ListBase *list, tReorderChannelIsland *island); /* get rearranging function, given 'rearrange' mode */ static AnimChanRearrangeFp rearrange_get_mode_func (short mode) { switch (mode) { case REARRANGE_ANIMCHAN_TOP: - return rearrange_animchannel_top; + return rearrange_island_top; case REARRANGE_ANIMCHAN_UP: - return rearrange_animchannel_up; + return rearrange_island_up; case REARRANGE_ANIMCHAN_DOWN: - return rearrange_animchannel_down; + return rearrange_island_down; case REARRANGE_ANIMCHAN_BOTTOM: - return rearrange_animchannel_bottom; + return rearrange_island_bottom; default: return NULL; } } -/* ........ */ - -/* These iteration helpers (ideally should be inlined, but probably not necessary) */ +/* Rearrange Islands Generics ------------------------------------- */ -static Link *rearrange_iter_first (ListBase *list, short mode) +/* add channel into list of islands */ +static void rearrange_animchannel_add_to_islands (ListBase *islands, ListBase *srcList, Link *channel, short type) { - return (mode > 0) ? list->first : list->last; + tReorderChannelIsland *island = islands->last; /* always try to add to last island if possible */ + short is_sel=0, is_untouchable=0; + + /* get flags - selected and untouchable from the channel */ + switch (type) { + case ANIMTYPE_GROUP: + { + bActionGroup *agrp= (bActionGroup *)channel; + + is_sel= SEL_AGRP(agrp); + is_untouchable= (agrp->flag & AGRP_TEMP) != 0; + } + break; + case ANIMTYPE_FCURVE: + { + FCurve *fcu= (FCurve *)channel; + + is_sel= SEL_FCU(fcu); + } + break; + case ANIMTYPE_NLATRACK: + { + NlaTrack *nlt= (NlaTrack *)channel; + + is_sel= SEL_NLT(nlt); + } + break; + + default: + printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %d\n", type); + return; + } + + /* do we need to add to a new island? */ + if ((island == NULL) || /* 1) no islands yet */ + ((island->flag & REORDER_ISLAND_SELECTED) == 0) || /* 2) unselected islands have single channels only - to allow up/down movement */ + (is_sel == 0)) /* 3) if channel is unselected, stop existing island (it was either wrong sel status, or full already) */ + { + /* create a new island now */ + island = MEM_callocN(sizeof(tReorderChannelIsland), "tReorderChannelIsland"); + BLI_addtail(islands, island); + + if (is_sel) + island->flag |= REORDER_ISLAND_SELECTED; + if (is_untouchable) + island->flag |= REORDER_ISLAND_UNTOUCHABLE; + } + + /* add channel to island - need to remove it from its existing list first though */ + BLI_remlink(srcList, channel); + BLI_addtail(&island->channels, channel); } -static Link *rearrange_iter_next (Link *item, short mode) +/* flatten islands out into a single list again */ +static void rearrange_animchannel_flatten_islands (ListBase *islands, ListBase *srcList) { - return (mode > 0) ? item->next : item->prev; + tReorderChannelIsland *island, *isn=NULL; + + /* make sure srcList is empty now */ + BLI_assert(srcList->first == NULL); + + /* go through merging islands */ + for (island = islands->first; island; island = isn) { + isn = island->next; + + /* merge island channels back to main list, then delete the island */ + BLI_movelisttolist(srcList, &island->channels); + BLI_freelinkN(islands, island); + } } -/* ........ */ +/* ............................. */ -/* Clear 'tag' on all F-Curves */ -static void rearrange_clear_fcurve_tags (ListBase *list) +/* performing rearranging of channels using islands */ +static short rearrange_animchannel_islands (ListBase *list, AnimChanRearrangeFp rearrange_func, short mode, short type) { - FCurve *fcu; + ListBase islands = {NULL, NULL}; + Link *channel, *chanNext=NULL; + short done = 0; - for (fcu = list->first; fcu; fcu = fcu->next) - fcu->flag &= ~FCURVE_TAGGED; + /* don't waste effort on an empty list */ + if (list->first == NULL) + return 0; + + /* group channels into islands */ + for (channel = list->first; channel; channel = chanNext) { + chanNext = channel->next; + rearrange_animchannel_add_to_islands(&islands, list, channel, type); + } + + /* perform moving of selected islands now, but only if there is more than one of 'em so that something will happen + * - scanning of the list is performed in the opposite direction to the direction we're moving things, so that we + * shouldn't need to encounter items we've moved already + */ + if (islands.first != islands.last) { + tReorderChannelIsland *first = (mode > 0) ? islands.last : islands.first; + tReorderChannelIsland *island, *isn=NULL; + + for (island = first; island; island = isn) { + isn = (mode > 0) ? island->prev : island->next; + + /* perform rearranging */ + if (rearrange_func(&islands, island)) { + island->flag |= REORDER_ISLAND_MOVED; + done = 1; + } + } + } + + /* ungroup islands */ + rearrange_animchannel_flatten_islands(&islands, list); + + /* did we do anything? */ + return done; } /* NLA Specific Stuff ----------------------------------------------------- */ @@ -776,8 +885,6 @@ static void rearrange_clear_fcurve_tags (ListBase *list) */ static void rearrange_nla_channels (bAnimContext *UNUSED(ac), AnimData *adt, short mode) { - NlaTrack *nlt, *track; - AnimChanRearrangeFp rearrange_func; /* hack: invert mode so that functions will work in right order */ @@ -792,23 +899,8 @@ static void rearrange_nla_channels (bAnimContext *UNUSED(ac), AnimData *adt, sho //if (EXPANDED_DRVD(adt) == 0) // return; - /* clear "moved" flag from all tracks */ - for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) - nlt->flag &= ~NLASTRIP_FLAG_EDIT_TOUCHED; - - /* reorder all selected tracks */ - for (nlt= (NlaTrack *)rearrange_iter_first(&adt->nla_tracks, mode); nlt; nlt= track) { - /* Get next channel to consider */ - track= (NlaTrack *)rearrange_iter_next((Link *)nlt, mode); - - /* Try to do channel */ - if (rearrange_func(&adt->nla_tracks, (Link *)nlt, ANIMTYPE_NLATRACK)) - nlt->flag |= NLASTRIP_FLAG_EDIT_TOUCHED; - } - - /* clear "moved" flag from all tracks */ - for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) - nlt->flag &= ~NLASTRIP_FLAG_EDIT_TOUCHED; + /* perform rearranging on tracks list */ + rearrange_animchannel_islands(&adt->nla_tracks, rearrange_func, mode, ANIMTYPE_NLATRACK); } /* Drivers Specific Stuff ------------------------------------------------- */ @@ -818,8 +910,6 @@ static void rearrange_nla_channels (bAnimContext *UNUSED(ac), AnimData *adt, sho */ static void rearrange_driver_channels (bAnimContext *UNUSED(ac), AnimData *adt, short mode) { - FCurve *fcu, *fcun; - /* get rearranging function */ AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); @@ -830,19 +920,8 @@ static void rearrange_driver_channels (bAnimContext *UNUSED(ac), AnimData *adt, if (EXPANDED_DRVD(adt) == 0) return; - rearrange_clear_fcurve_tags(&adt->drivers); - - /* reorder all selected driver F-Curves */ - for (fcu= (FCurve *)rearrange_iter_first(&adt->drivers, mode); fcu; fcu= fcun) { - /* Get next channel to consider */ - fcun= (FCurve *)rearrange_iter_next((Link *)fcu, mode); - - /* Try to do channel */ - if (rearrange_func(&adt->drivers, (Link *)fcu, ANIMTYPE_FCURVE)) - fcu->flag |= FCURVE_TAGGED; - } - - rearrange_clear_fcurve_tags(&adt->drivers); + /* perform rearranging on drivers list (drivers are really just F-Curves) */ + rearrange_animchannel_islands(&adt->drivers, rearrange_func, mode, ANIMTYPE_FCURVE); } /* Action Specific Stuff ------------------------------------------------- */ @@ -856,9 +935,6 @@ static void split_groups_action_temp (bAction *act, bActionGroup *tgrp) if (act == NULL) return; - /* clear "moved" flag from all FCurves */ - rearrange_clear_fcurve_tags(&act->curves); - /* Separate F-Curves into lists per group */ for (agrp= act->groups.first; agrp; agrp= agrp->next) { if (agrp->channels.first) { @@ -919,9 +995,6 @@ static void join_groups_action_temp (bAction *act) break; } } - - /* clear "moved" flag from all fcurve's */ - rearrange_clear_fcurve_tags(&act->curves); } /* Change the order of anim-channels within action @@ -929,10 +1002,8 @@ static void join_groups_action_temp (bAction *act) */ static void rearrange_action_channels (bAnimContext *ac, bAction *act, short mode) { - bActionGroup *agrp, *grp; bActionGroup tgrp; - FCurve *fcu, *fcun; - short do_channels = 1; + short do_channels; /* get rearranging function */ AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); @@ -940,36 +1011,22 @@ static void rearrange_action_channels (bAnimContext *ac, bAction *act, short mod if (rearrange_func == NULL) return; - /* make sure we're only operating with groups */ + /* make sure we're only operating with groups (vs a mixture of groups+curves) */ split_groups_action_temp(act, &tgrp); - /* rearrange groups first (and then, only consider channels if the groups weren't moved) */ - for (agrp= (bActionGroup *)rearrange_iter_first(&act->groups, mode); agrp; agrp= grp) { - /* Get next group to consider */ - grp= (bActionGroup *)rearrange_iter_next((Link *)agrp, mode); - - /* try to do group first */ - if (rearrange_func(&act->groups, (Link *)agrp, ANIMTYPE_GROUP)) { - do_channels= 0; - agrp->flag |= AGRP_MOVED; - } - } + /* rearrange groups first + * - the group's channels will only get considered if nothing happened when rearranging the groups + * i.e. the rearrange function returned 0 + */ + do_channels = rearrange_animchannel_islands(&act->groups, rearrange_func, mode, ANIMTYPE_GROUP) == 0; if (do_channels) { - for (agrp= (bActionGroup *)rearrange_iter_first(&act->groups, mode); agrp; agrp= grp) { - /* Get next group to consider */ - grp= (bActionGroup *)rearrange_iter_next((Link *)agrp, mode); - + bActionGroup *agrp; + + for (agrp= act->groups.first; agrp; agrp= agrp->next) { /* only consider F-Curves if they're visible (group expanded) */ - if (EXPANDED_AGRP(agrp)) { - for (fcu= (FCurve *)rearrange_iter_first(&agrp->channels, mode); fcu; fcu= fcun) { - /* Get next channel to consider */ - fcun= (FCurve *)rearrange_iter_next((Link *)fcu, mode); - - /* Try to do channel */ - if (rearrange_func(&agrp->channels, (Link *)fcu, ANIMTYPE_FCURVE)) - fcu->flag |= FCURVE_TAGGED; - } + if (EXPANDED_AGRP(ac, agrp)) { + rearrange_animchannel_islands(&agrp->channels, rearrange_func, mode, ANIMTYPE_FCURVE); } } } @@ -998,7 +1055,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) { @@ -1024,7 +1082,7 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op) // FIXME: actions should only be considered once! if (adt->action) rearrange_action_channels(&ac, adt->action, mode); - else + else if (G.f & G_DEBUG) printf("animdata has no action\n"); break; } @@ -1039,7 +1097,7 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void ANIM_OT_channels_move (wmOperatorType *ot) +static void ANIM_OT_channels_move (wmOperatorType *ot) { /* identifiers */ ot->name= "Move Channels"; @@ -1054,7 +1112,7 @@ void ANIM_OT_channels_move (wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; /* props */ - RNA_def_enum(ot->srna, "direction", prop_animchannel_rearrange_types, REARRANGE_ANIMCHAN_DOWN, "Direction", ""); + ot->prop= RNA_def_enum(ot->srna, "direction", prop_animchannel_rearrange_types, REARRANGE_ANIMCHAN_DOWN, "Direction", ""); } /* ******************** Delete Channel Operator *********************** */ @@ -1078,7 +1136,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 */ @@ -1114,35 +1172,48 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op)) BLI_freelistN(&anim_data); } - /* now do F-Curves */ - if (ac.datatype != ANIMCONT_GPENCIL) { - /* filter data */ - filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - - /* delete selected F-Curves */ - for (ale= anim_data.first; ale; ale= ale->next) { - /* only F-Curves, and only if we can identify its parent */ - if (ale->type == ANIMTYPE_FCURVE) { + /* filter data */ + 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 data channels */ + for (ale= anim_data.first; ale; ale= ale->next) { + switch (ale->type) { + case ANIMTYPE_FCURVE: + { + /* F-Curves if we can identify its parent */ AnimData *adt= ale->adt; FCurve *fcu= (FCurve *)ale->data; /* try to free F-Curve */ ANIM_fcurve_delete_from_animdata(&ac, adt, fcu); } + break; + + case ANIMTYPE_GPLAYER: + { + /* Grease Pencil layer */ + bGPdata *gpd= (bGPdata *)ale->id; + bGPDlayer *gpl= (bGPDlayer *)ale->data; + + /* try to delete the layer's data and the layer itself */ + free_gpencil_frames(gpl); + BLI_freelinkN(&gpd->layers, gpl); + } + break; } - - /* cleanup */ - BLI_freelistN(&anim_data); } + /* cleanup */ + BLI_freelistN(&anim_data); + /* send notifier that things have changed */ WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL); return OPERATOR_FINISHED; } -void ANIM_OT_channels_delete (wmOperatorType *ot) +static void ANIM_OT_channels_delete (wmOperatorType *ot) { /* identifiers */ ot->name= "Delete Channels"; @@ -1172,12 +1243,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) { @@ -1219,7 +1305,7 @@ static int animchannels_visibility_set_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -void ANIM_OT_channels_visibility_set (wmOperatorType *ot) +static void ANIM_OT_channels_visibility_set (wmOperatorType *ot) { /* identifiers */ ot->name= "Set Visibility"; @@ -1251,12 +1337,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 */ @@ -1292,7 +1382,7 @@ static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *UNUSED(o return OPERATOR_FINISHED; } -void ANIM_OT_channels_visibility_toggle (wmOperatorType *ot) +static void ANIM_OT_channels_visibility_toggle (wmOperatorType *ot) { /* identifiers */ ot->name= "Toggle Visibility"; @@ -1310,7 +1400,7 @@ void ANIM_OT_channels_visibility_toggle (wmOperatorType *ot) /* ********************** Set Flags Operator *********************** */ /* defines for setting animation-channel flags */ -EnumPropertyItem prop_animchannel_setflag_types[] = { +static EnumPropertyItem prop_animchannel_setflag_types[] = { {ACHANNEL_SETFLAG_TOGGLE, "TOGGLE", 0, "Toggle", ""}, {ACHANNEL_SETFLAG_CLEAR, "DISABLE", 0, "Disable", ""}, {ACHANNEL_SETFLAG_ADD, "ENABLE", 0, "Enable", ""}, @@ -1320,7 +1410,7 @@ EnumPropertyItem prop_animchannel_setflag_types[] = { /* defines for set animation-channel settings */ // TODO: could add some more types, but those are really quite dependent on the mode... -EnumPropertyItem prop_animchannel_settings_types[] = { +static EnumPropertyItem prop_animchannel_settings_types[] = { {ACHANNEL_SETTING_PROTECT, "PROTECT", 0, "Protect", ""}, {ACHANNEL_SETTING_MUTE, "MUTE", 0, "Mute", ""}, {0, NULL, 0, NULL, NULL} @@ -1329,10 +1419,6 @@ 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 @@ -1348,14 +1434,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); @@ -1424,7 +1525,7 @@ static int animchannels_setflag_exec(bContext *C, wmOperator *op) } -void ANIM_OT_channels_setting_enable (wmOperatorType *ot) +static void ANIM_OT_channels_setting_enable (wmOperatorType *ot) { /* identifiers */ ot->name= "Enable Channel Setting"; @@ -1446,7 +1547,7 @@ void ANIM_OT_channels_setting_enable (wmOperatorType *ot) ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", ""); } -void ANIM_OT_channels_setting_disable (wmOperatorType *ot) +static void ANIM_OT_channels_setting_disable (wmOperatorType *ot) { /* identifiers */ ot->name= "Disable Channel Setting"; @@ -1468,7 +1569,7 @@ void ANIM_OT_channels_setting_disable (wmOperatorType *ot) ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", ""); } -void ANIM_OT_channels_setting_invert (wmOperatorType *ot) +static void ANIM_OT_channels_setting_invert (wmOperatorType *ot) { /* identifiers */ ot->name= "Invert Channel Setting"; @@ -1490,7 +1591,7 @@ void ANIM_OT_channels_setting_invert (wmOperatorType *ot) ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", ""); } -void ANIM_OT_channels_setting_toggle (wmOperatorType *ot) +static void ANIM_OT_channels_setting_toggle (wmOperatorType *ot) { /* identifiers */ ot->name= "Toggle Channel Setting"; @@ -1512,7 +1613,7 @@ void ANIM_OT_channels_setting_toggle (wmOperatorType *ot) ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", ""); } -void ANIM_OT_channels_editable_toggle (wmOperatorType *ot) +static void ANIM_OT_channels_editable_toggle (wmOperatorType *ot) { /* identifiers */ ot->name= "Toggle Channel Editability"; @@ -1557,7 +1658,7 @@ static int animchannels_expand_exec (bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void ANIM_OT_channels_expand (wmOperatorType *ot) +static void ANIM_OT_channels_expand (wmOperatorType *ot) { /* identifiers */ ot->name= "Expand Channels"; @@ -1599,7 +1700,7 @@ static int animchannels_collapse_exec (bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void ANIM_OT_channels_collapse (wmOperatorType *ot) +static void ANIM_OT_channels_collapse (wmOperatorType *ot) { /* identifiers */ ot->name= "Collapse Channels"; @@ -1648,13 +1749,22 @@ 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 */ for (ale= anim_data.first; ale; ale= ale->next) { FCurve *fcu = (FCurve *)ale->data; + + /* remove disabled flags from F-Curves */ fcu->flag &= ~FCURVE_DISABLED; + + /* for drivers, let's do the same too */ + if (fcu->driver) + fcu->driver->flag &= ~DRIVER_FLAG_INVALID; + + /* tag everything for updates - in particular, this is needed to get drivers working again */ + ANIM_list_elem_update(ac.scene, ale); } /* free temp data */ @@ -1666,7 +1776,7 @@ static int animchannels_enable_exec (bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -void ANIM_OT_channels_fcurves_enable (wmOperatorType *ot) +static void ANIM_OT_channels_fcurves_enable (wmOperatorType *ot) { /* identifiers */ ot->name= "Revive Disabled F-Curves"; @@ -1703,7 +1813,7 @@ static int animchannels_deselectall_exec (bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void ANIM_OT_channels_select_all_toggle (wmOperatorType *ot) +static void ANIM_OT_channels_select_all_toggle (wmOperatorType *ot) { /* identifiers */ ot->name= "Select All"; @@ -1729,13 +1839,14 @@ static void borderselect_anim_channels (bAnimContext *ac, rcti *rect, short sele bAnimListElem *ale; int filter; + SpaceNla *snla = (SpaceNla *)ac->sl; View2D *v2d= &ac->ar->v2d; rctf rectf; float ymin, ymax; /* set initial y extents */ if (ac->datatype == ANIMCONT_NLA) { - ymin = (float)(-NLACHANNEL_HEIGHT); + ymin = (float)(-NLACHANNEL_HEIGHT(snla)); ymax = 0.0f; } else { @@ -1748,13 +1859,13 @@ 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 */ for (ale= anim_data.first; ale; ale= ale->next) { if (ac->datatype == ANIMCONT_NLA) - ymin= ymax - NLACHANNEL_STEP; + ymin= ymax - NLACHANNEL_STEP(snla); else ymin= ymax - ACHANNEL_STEP; @@ -1828,7 +1939,7 @@ static int animchannels_borderselect_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void ANIM_OT_channels_select_border(wmOperatorType *ot) +static void ANIM_OT_channels_select_border(wmOperatorType *ot) { /* identifiers */ ot->name= "Border Select"; @@ -1839,6 +1950,7 @@ void ANIM_OT_channels_select_border(wmOperatorType *ot) ot->invoke= WM_border_select_invoke; ot->exec= animchannels_borderselect_exec; ot->modal= WM_border_select_modal; + ot->cancel= WM_border_select_cancel; ot->poll= animedit_poll_channels_nla_tweakmode_off; @@ -1861,7 +1973,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 */ @@ -2106,7 +2218,7 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent * bAnimContext ac; ARegion *ar; View2D *v2d; - int mval[2], channel_index; + int channel_index; int notifierFlags = 0; short selectmode; float x, y; @@ -2120,10 +2232,6 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent * ar= ac.ar; v2d= &ar->v2d; - /* get mouse coordinates (in region coordinates) */ - mval[0]= (event->x - ar->winrct.xmin); - mval[1]= (event->y - ar->winrct.ymin); - /* select mode is either replace (deselect all, then add) or add/extend */ if (RNA_boolean_get(op->ptr, "extend")) selectmode= SELECT_INVERT; @@ -2137,7 +2245,7 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent * * so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use * ACHANNEL_HEIGHT_HALF. */ - UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y); UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index); /* handle mouse-click in the relevant channel then */ @@ -2149,7 +2257,7 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent * return OPERATOR_FINISHED; } -void ANIM_OT_channels_click (wmOperatorType *ot) +static void ANIM_OT_channels_click (wmOperatorType *ot) { /* identifiers */ ot->name= "Mouse Click on Channels"; diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index 340101612b9..13061113926 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -26,6 +26,11 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/editors/animation/anim_deps.c + * \ingroup edanimation + */ + + #include <string.h> #include "MEM_guardedalloc.h" @@ -252,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_draw.c b/source/blender/editors/animation/anim_draw.c index dd27de883b3..22ab419de2e 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -25,6 +25,11 @@ * * ***** END GPL LICENSE BLOCK ***** */ + +/** \file blender/editors/animation/anim_draw.c + * \ingroup edanimation + */ + #include "BLO_sys_types.h" #include "DNA_anim_types.h" @@ -95,7 +100,7 @@ void ANIM_timecode_string_from_frame (char *str, Scene *scene, int power, short * to cope with 'half' frames, etc., which should be fine in most cases */ seconds= (int)cfra; - frames= (int)floor( ((cfra - seconds) * FPS) + 0.5f ); + frames= (int)floor( (((double)cfra - (double)seconds) * FPS) + 0.5 ); } else { /* seconds (with pixel offset rounding) */ @@ -220,7 +225,10 @@ void ANIM_draw_cfra (const bContext *C, View2D *v2d, short flag) vec[0]= (float)(scene->r.cfra * scene->r.framelen); UI_ThemeColor(TH_CFRAME); - glLineWidth(2.0); + if (flag & DRAWCFRA_WIDE) + glLineWidth(3.0); + else + glLineWidth(2.0); glBegin(GL_LINE_STRIP); vec[1]= v2d->cur.ymin-500.0f; /* XXX arbitrary... want it go to bottom */ @@ -232,19 +240,19 @@ void ANIM_draw_cfra (const bContext *C, View2D *v2d, short flag) /* Draw dark green line if slow-parenting/time-offset is enabled */ if (flag & DRAWCFRA_SHOW_TIMEOFS) { - Object *ob= (scene->basact) ? (scene->basact->object) : 0; + Object *ob= OBACT; if(ob) { float timeoffset= give_timeoffset(ob); // XXX ob->ipoflag is depreceated! if ((ob->ipoflag & OB_OFFS_OB) && (timeoffset != 0.0f)) { vec[0]-= timeoffset; /* could avoid calling twice */ - + UI_ThemeColorShade(TH_CFRAME, -30); - + glBegin(GL_LINE_STRIP); /*vec[1]= v2d->cur.ymax;*/ // this is set already. this line is only included glVertex2fv(vec); - + vec[1]= v2d->cur.ymin; glVertex2fv(vec); glEnd(); @@ -352,7 +360,7 @@ static short bezt_nlamapping_apply(KeyframeEditData *ked, BezTriple *bezt) */ void ANIM_nla_mapping_apply_fcurve (AnimData *adt, FCurve *fcu, short restore, short only_keys) { - KeyframeEditData ked= {{0}}; + KeyframeEditData ked= {{NULL}}; KeyframeEditFunc map_cb; /* init edit data @@ -394,9 +402,9 @@ float ANIM_unit_mapping_get_factor (Scene *scene, ID *id, FCurve *fcu, short res /* if the radians flag is not set, default to using degrees which need conversions */ if ((scene) && (scene->unit.system_rotation == USER_UNIT_ROT_RADIANS) == 0) { if (restore) - return M_PI / 180.0f; /* degrees to radians */ + return M_PI / 180.0; /* degrees to radians */ else - return 180.0f / M_PI; /* radians to degrees */ + return 180.0 / M_PI; /* radians to degrees */ } } @@ -465,7 +473,7 @@ void ANIM_unit_mapping_apply_fcurve (Scene *scene, ID *id, FCurve *fcu, short fl // TODO: only sel? if (fcu->fpt) { FPoint *fpt; - int i; + unsigned int i; for (i=0, fpt=fcu->fpt; i < fcu->totvert; i++, fpt++) { /* apply unit mapping */ diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 6d36daa854c..047a7763fd8 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -26,6 +26,11 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/editors/animation/anim_filter.c + * \ingroup edanimation + */ + + /* This file contains a system used to provide a layer of abstraction between sources * of animation data and tools in Animation Editors. The method used here involves * generating a list of edit structures which enable tools to naively perform the actions @@ -122,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' */ @@ -185,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) @@ -233,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) */ @@ -253,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; @@ -298,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 */ @@ -312,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; @@ -322,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) @@ -331,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. @@ -342,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) @@ -362,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\ }\ @@ -388,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) ) @@ -427,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. */ -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; @@ -438,10 +492,6 @@ bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, s 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); @@ -504,55 +554,6 @@ bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, s 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: { @@ -676,7 +677,7 @@ bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, s 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; @@ -799,8 +800,10 @@ bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, s /* ----------------------------------------- */ -/* 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) +/* 'Only Selected' selected data filtering + * NOTE: when this function returns true, the F-Curve is to be skipped + */ +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; @@ -818,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 */ @@ -871,8 +875,39 @@ static int skip_fcurve_selected_data (bDopeSheet *ads, FCurve *fcu, ID *owner_id return 0; } +/* (Display-)Name-based F-Curve filtering + * NOTE: when this function returns true, the F-Curve is to be skipped + */ +static short skip_fcurve_with_name (bDopeSheet *ads, FCurve *fcu, ID *owner_id) +{ + bAnimListElem ale_dummy = {0}; + bAnimChannelType *acf; + + /* create a dummy wrapper for the F-Curve */ + ale_dummy.type = ANIMTYPE_FCURVE; + ale_dummy.id = owner_id; + ale_dummy.data = fcu; + + /* get type info for channel */ + acf = ANIM_channel_get_typeinfo(&ale_dummy); + if (acf && acf->name) { + char name[256]; /* hopefully this will be enough! */ + + /* get name */ + acf->name(&ale_dummy, name); + + /* check for partial match with the match string, assuming case insensitive filtering + * if match, this channel shouldn't be ignored! + */ + return BLI_strcasestr(name, ads->searchstr) == NULL; + } + + /* just let this go... */ + return 1; +} + /* 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; @@ -880,7 +915,7 @@ static FCurve *animdata_filter_fcurve_next (bDopeSheet *ads, FCurve *first, bAct * NOTE: we need to check if the F-Curves belong to the same group, as this gets called for groups too... */ for (fcu= first; ((fcu) && (fcu->grp==grp)); fcu= fcu->next) { - /* special exception for Pose-Channel Based F-Curves: + /* special exception for Pose-Channel/Sequence-Strip/Node Based F-Curves: * - the 'Only Selected' data filter should be applied to Pose-Channel data too, but those are * represented as F-Curves. The way the filter for objects worked was to be the first check * after 'normal' visibility, so this is done first here too... @@ -892,15 +927,21 @@ static FCurve *animdata_filter_fcurve_next (bDopeSheet *ads, FCurve *first, bAct if (skip_fcurve_selected_data(ads, fcu, owner_id, filter_mode)) continue; } - + /* 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 */ if ( ANIMCHANNEL_SELOK(SEL_FCU(fcu)) && ANIMCHANNEL_SELEDITOK(SEL_FCU(fcu)) ) { /* only include if this curve is active */ if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) { + /* name based filtering... */ + if ( ((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) && (owner_id) ) { + if (skip_fcurve_with_name(ads, fcu, owner_id)) + continue; + } + /* this F-Curve can be used, so return it */ return fcu; } @@ -913,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: @@ -927,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... @@ -954,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(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(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 */ @@ -1061,35 +1090,35 @@ 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 *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) { - /* 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++; + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + /* if NLA action-line filtering is off, don't show unless there are keyframes, + * in order to keep things more compact for doing transforms + */ + if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) || (adt->action)) { + /* there isn't really anything editable here, so skip if need editable */ + 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... + */ + ANIMCHANNEL_NEW_CHANNEL_FULL((void *)(&adt->action), ANIMTYPE_NLAACTION, owner_id, + { + ale->data= adt->action ? adt->action : NULL; + }); } } @@ -1104,7 +1133,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; @@ -1122,12 +1151,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); } } } @@ -1137,14 +1161,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 */ @@ -1160,24 +1214,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); + } } } @@ -1185,53 +1236,102 @@ static int animdata_filter_shapekey (bAnimContext *ac, ListBase *anim_data, Key return items; } +static size_t animdata_filter_gpencil_data (ListBase *anim_data, bGPdata *gpd, int filter_mode) +{ + bGPDlayer *gpl; + size_t items = 0; + + /* loop over layers as the conditions are acceptable */ + for (gpl= gpd->layers.first; gpl; gpl= gpl->next) { + /* only if selected */ + if ( ANIMCHANNEL_SELOK(SEL_GPL(gpl)) ) { + /* only if editable */ + if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_GPL(gpl)) { + /* active... */ + if (!(filter_mode & ANIMFILTER_ACTIVE) || (gpl->flag & GP_LAYER_ACTIVE)) { + /* add to list */ + ANIMCHANNEL_NEW_CHANNEL(gpl, ANIMTYPE_GPLAYER, gpd); + } + } + } + } + + return items; +} + /* 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) { - /* only show if gpd is used by something... */ - if (ID_REAL_USERS(gpd) < 1) - continue; + /* for now, grab grease pencil datablocks directly from main */ + // XXX: this is not good... + for (gpd = G.main->gpencil.first; gpd; gpd = gpd->id.next) { + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + + /* only show if gpd is used by something... */ + if (ID_REAL_USERS(gpd) < 1) + continue; - /* add gpd as channel too (if for drawing, and it has layers) */ - if ((filter_mode & ANIMFILTER_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++; - } + /* add gpencil animation channels */ + BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd)) + { + tmp_items += animdata_filter_gpencil_data(&tmp_data, gpd, filter_mode); + } + END_ANIMFILTER_SUBCHANNELS; + + /* did we find anything? */ + if (tmp_items) { + /* include data-expand widget first */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + /* add gpd as channel too (if for drawing, and it has layers) */ + 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)) ) { - /* loop over layers as the conditions are acceptable */ - for (gpl= gpd->layers.first; gpl; gpl= gpl->next) { - /* only if selected */ - if ( ANIMCHANNEL_SELOK(SEL_GPL(gpl)) ) { - /* 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++; - } - } - } - } + /* 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 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 */ @@ -1239,16 +1339,11 @@ static int animdata_filter_gpencil (ListBase *anim_data, void *UNUSED(data), int } /* 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) @@ -1258,28 +1353,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: @@ -1294,235 +1380,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; } } @@ -1530,14 +1518,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) { @@ -1545,6 +1533,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); } @@ -1553,6 +1544,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); } @@ -1563,6 +1557,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); } @@ -1571,6 +1568,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); } @@ -1579,6 +1579,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); } @@ -1587,6 +1590,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); } @@ -1595,467 +1601,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; } - /* special exception for drivers instead of action */ - if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) - expanded= EXPANDED_DRVD(adt); - - /* 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)) { @@ -2073,73 +1970,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 @@ -2147,10 +1985,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; @@ -2161,280 +1999,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); } @@ -2447,7 +2031,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; @@ -2456,8 +2040,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 { @@ -2469,9 +2053,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)++; @@ -2488,13 +2071,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) { @@ -2510,11 +2119,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 @@ -2556,9 +2165,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) { @@ -2568,12 +2177,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; @@ -2607,6 +2216,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_intern.h b/source/blender/editors/animation/anim_intern.h index 274d33e4833..7818e8118a3 100644 --- a/source/blender/editors/animation/anim_intern.h +++ b/source/blender/editors/animation/anim_intern.h @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -24,6 +24,11 @@ * * ***** END GPL LICENSE BLOCK ***** */ + +/** \file blender/editors/animation/anim_intern.h + * \ingroup edanimation + */ + #ifndef ANIM_INTERN_H #define ANIM_INTERN_H diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index 3e2212c15bb..fc05f46929b 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -26,6 +26,11 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/editors/animation/anim_ipo_utils.c + * \ingroup edanimation + */ + + /* This file contains code for presenting F-Curves and other animation data * in the UI (especially for use in the Animation Editors). * @@ -41,10 +46,10 @@ #include "DNA_anim_types.h" - - #include "RNA_access.h" +#include "ED_anim_api.h" + /* ----------------------- Getter functions ----------------------- */ /* Write into "name" buffer, the name of the property (retrieved using RNA from the curve's settings), @@ -95,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" */ @@ -109,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 */ @@ -140,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 58dc5008959..732fc0bd267 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -26,6 +26,11 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/editors/animation/anim_markers.c + * \ingroup edanimation + */ + + #include <math.h> #include "MEM_guardedalloc.h" @@ -45,6 +50,7 @@ #include "BKE_main.h" #include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_screen.h" #include "WM_api.h" #include "WM_types.h" @@ -63,6 +69,7 @@ #include "ED_util.h" #include "ED_numinput.h" #include "ED_object.h" +#include "ED_transform.h" #include "ED_types.h" /* ************* Marker API **************** */ @@ -109,6 +116,57 @@ ListBase *ED_animcontext_get_markers(const bAnimContext *ac) /* --------------------------------- */ +/* Apply some transformation to markers after the fact + * < markers: list of markers to affect - this may or may not be the scene markers list, so don't assume anything + * < scene: current scene (for getting current frame) + * < mode: (TfmMode) transform mode that this transform is for + * < value: from the transform code, this is t->vec[0] (which is delta transform for grab/extend, and scale factor for scale) + * < side: (B/L/R) for 'extend' functionality, which side of current frame to use + */ +int ED_markers_post_apply_transform (ListBase *markers, Scene *scene, int mode, float value, char side) +{ + TimeMarker *marker; + float cfra = (float)CFRA; + int changed = 0; + + /* sanity check */ + if (markers == NULL) + return changed; + + /* affect selected markers - it's unlikely that we will want to affect all in this way? */ + for (marker = markers->first; marker; marker = marker->next) { + if (marker->flag & SELECT) { + switch (mode) { + case TFM_TIME_TRANSLATE: + case TFM_TIME_EXTEND: + { + /* apply delta if marker is on the right side of the current frame */ + if ((side=='B') || + (side=='L' && marker->frame < cfra) || + (side=='R' && marker->frame >= cfra)) + { + marker->frame += (int)floorf(value + 0.5f); + changed++; + } + } + break; + + case TFM_TIME_SCALE: + { + /* rescale the distance between the marker and the current frame */ + marker->frame= cfra + (int)floorf(((float)(marker->frame - cfra) * value) + 0.5f); + changed++; + } + break; + } + } + } + + return changed; +} + +/* --------------------------------- */ + /* Get the marker that is closest to this point */ /* XXX for select, the min_dist should be small */ TimeMarker *ED_markers_find_nearest_marker (ListBase *markers, float x) @@ -205,7 +263,7 @@ void ED_markers_get_minmax (ListBase *markers, short sel, float *first, float *l /* --------------------------------- */ /* Adds a marker to list of cfra elems */ -void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only_sel) +static void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only_sel) { CfraElem *ce, *cen; @@ -264,6 +322,29 @@ TimeMarker *ED_markers_get_first_selected(ListBase *markers) return NULL; } +/* --------------------------------- */ + +/* Print debugging prints of list of markers + * BSI's: do NOT make static or put in if-defs as "unused code". That's too much trouble when we need to use for quick debuggging! + */ +void debug_markers_print_list(ListBase *markers) +{ + TimeMarker *marker; + + if (markers == NULL) { + printf("No markers list to print debug for\n"); + return; + } + + printf("List of markers follows: -----\n"); + + for (marker = markers->first; marker; marker = marker->next) { + printf("\t'%s' on %d at %p with %d\n", marker->name, marker->frame, (void *)marker, marker->flag); + } + + printf("End of list ------------------\n"); +} + /* ************* Marker Drawing ************ */ /* function to draw markers */ @@ -318,7 +399,6 @@ static void draw_marker(View2D *v2d, TimeMarker *marker, int cfra, int flag) UI_icon_draw(xpos*xscale-5.0f, 16.0f, icon_id); - glBlendFunc(GL_ONE, GL_ZERO); glDisable(GL_BLEND); /* and the marker name too, shifted slightly to the top-right */ @@ -343,7 +423,7 @@ static void draw_marker(View2D *v2d, TimeMarker *marker, int cfra, int flag) } #ifdef DURIAN_CAMERA_SWITCH - if(marker->camera && marker->camera->restrictflag & OB_RESTRICT_RENDER) { + if(marker->camera && (marker->camera->restrictflag & OB_RESTRICT_RENDER)) { float col[4]; glGetFloatv(GL_CURRENT_COLOR, col); col[3]= 0.4; @@ -386,9 +466,6 @@ void draw_markers_time(const bContext *C, int flag) * primary operations of those editors. */ -/* maximum y-axis value (in region screen-space) that marker events should still be accepted for */ -#define ANIMEDIT_MARKER_YAXIS_MAX 40 - /* ------------------------ */ /* special poll() which checks if there are selected markers first */ @@ -433,15 +510,7 @@ static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, wmEvent ScrArea *sa = CTX_wm_area(C); int retval = OPERATOR_PASS_THROUGH; - /* only timeline view doesn't need calling-location validation as it's the only dedicated view */ - if (sa->spacetype != SPACE_TIME) { - /* restrict y-values to within ANIMEDIT_MARKER_YAXIS_MAX of the view's vertical extents, including scrollbars */ - if (evt->mval[1] > ANIMEDIT_MARKER_YAXIS_MAX) { - /* not ok... "pass-through" to let normal editor's operators have a chance at tackling this event... */ - //printf("MARKER-WRAPPER-DEBUG: event mval[1] = %d, so over accepted tolerance\n", evt->mval[1]); - return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH; - } - } + /* removed check for Y coord of event, keymap has bounbox now */ /* allow operator to run now */ if (invoke_func) @@ -496,7 +565,7 @@ static int ed_marker_add(bContext *C, wmOperator *UNUSED(op)) marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker"); marker->flag= SELECT; marker->frame= frame; - sprintf(marker->name, "F_%02d", frame); // XXX - temp code only + BLI_snprintf(marker->name, sizeof(marker->name), "F_%02d", frame); // XXX - temp code only BLI_addtail(markers, marker); WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL); @@ -649,7 +718,7 @@ static void ed_marker_move_apply(wmOperator *op) } /* only for modal */ -static void ed_marker_move_cancel(bContext *C, wmOperator *op) +static int ed_marker_move_cancel(bContext *C, wmOperator *op) { RNA_int_set(op->ptr, "frames", 0); ed_marker_move_apply(op); @@ -657,6 +726,8 @@ static void ed_marker_move_cancel(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL); WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL); + + return OPERATOR_CANCELLED; } @@ -675,18 +746,24 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt) ed_marker_move_cancel(C, op); return OPERATOR_CANCELLED; + case RIGHTMOUSE: + /* press = user manually demands transform to be cancelled */ + if (evt->val == KM_PRESS) { + ed_marker_move_cancel(C, op); + return OPERATOR_CANCELLED; + } + /* else continue; <--- see if release event should be caught for tweak-end */ + case RETKEY: case PADENTER: case LEFTMOUSE: case MIDDLEMOUSE: - case RIGHTMOUSE: if (WM_modal_tweak_exit(evt, mm->event_type)) { ed_marker_move_exit(C, op); WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL); WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL); return OPERATOR_FINISHED; } - break; case MOUSEMOVE: if (hasNumInput(&mm->num)) @@ -724,19 +801,19 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt) if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) { SpaceTime *stime= (SpaceTime *)mm->slink; if (stime->flag & TIME_DRAWFRAMES) - sprintf(str, "Marker %d offset %d", selmarker->frame, offs); + BLI_snprintf(str, sizeof(str), "Marker %d offset %d", selmarker->frame, offs); else - sprintf(str, "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs)); + BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs)); } else if (mm->slink->spacetype == SPACE_ACTION) { SpaceAction *saction= (SpaceAction *)mm->slink; if (saction->flag & SACTION_DRAWTIME) - sprintf(str, "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs)); + BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs)); else - sprintf(str, "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs)); + BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs)); } else { - sprintf(str, "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs)); + BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs)); } } else { @@ -744,19 +821,19 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt) if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) { SpaceTime *stime= (SpaceTime *)mm->slink; if (stime->flag & TIME_DRAWFRAMES) - sprintf(str, "Marker offset %d ", offs); + BLI_snprintf(str, sizeof(str), "Marker offset %d ", offs); else - sprintf(str, "Marker offset %.2f ", FRA2TIME(offs)); + BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs)); } else if (mm->slink->spacetype == SPACE_ACTION) { SpaceAction *saction= (SpaceAction *)mm->slink; if (saction->flag & SACTION_DRAWTIME) - sprintf(str, "Marker offset %.2f ", FRA2TIME(offs)); + BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs)); else - sprintf(str, "Marker offset %.2f ", (double)(offs)); + BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs)); } else { - sprintf(str, "Marker offset %.2f ", (double)(offs)); + BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs)); } } @@ -779,7 +856,7 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt) ed_marker_move_apply(op); // ed_marker_header_update(C, op, str, (int)vec[0]); // strcat(str, str_tx); - sprintf(str, "Marker offset %s", str_tx); + BLI_snprintf(str, sizeof(str), "Marker offset %s", str_tx); ED_area_headerprint(CTX_wm_area(C), str); WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL); @@ -812,6 +889,7 @@ static void MARKER_OT_move(wmOperatorType *ot) ot->invoke= ed_marker_move_invoke_wrapper; ot->modal= ed_marker_move_modal; ot->poll= ed_markers_poll_selected_markers; + ot->cancel= ed_marker_move_cancel; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER; @@ -868,6 +946,7 @@ static void ed_marker_duplicate_apply(bContext *C) #endif /* new marker is added to the begining of list */ + // FIXME: bad ordering! BLI_addhead(markers, newmarker); } } @@ -905,6 +984,7 @@ static void MARKER_OT_duplicate(wmOperatorType *ot) ot->invoke= ed_marker_duplicate_invoke_wrapper; ot->modal= ed_marker_move_modal; ot->poll= ed_markers_poll_selected_markers; + ot->cancel= ed_marker_move_cancel; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; @@ -996,8 +1076,8 @@ static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera) WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL); WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL); - /* allowing tweaks */ - return OPERATOR_PASS_THROUGH; + /* allowing tweaks, but needs OPERATOR_FINISHED, otherwise renaming fails... [#25987] */ + return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH; } static int ed_marker_select_invoke(bContext *C, wmOperator *op, wmEvent *evt) @@ -1110,6 +1190,7 @@ static void MARKER_OT_select_border(wmOperatorType *ot) ot->exec= ed_marker_border_select_exec; ot->invoke= ed_marker_select_border_invoke_wrapper; ot->modal= WM_border_select_modal; + ot->cancel= WM_border_select_cancel; ot->poll= ed_markers_poll_markers_exist; @@ -1336,7 +1417,9 @@ static void MARKER_OT_make_links_scene(wmOperatorType *ot) static int ed_marker_camera_bind_exec(bContext *C, wmOperator *UNUSED(op)) { + bScreen *sc= CTX_wm_screen(C); Scene *scene= CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); ListBase *markers= ED_context_get_markers(C); TimeMarker *marker; @@ -1344,10 +1427,15 @@ static int ed_marker_camera_bind_exec(bContext *C, wmOperator *UNUSED(op)) if(marker == NULL) return OPERATOR_CANCELLED; - marker->camera= scene->camera; + marker->camera= ob; + + /* camera may have changes */ + scene_camera_switch_update(scene); + BKE_screen_view3d_scene_sync(sc); WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL); WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL); + WM_event_add_notifier(C, NC_SCENE|NA_EDITED, scene); /* so we get view3d redraws */ return OPERATOR_FINISHED; } @@ -1420,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/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 6b0fa30b096..7a94a21d41e 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -26,6 +26,11 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/editors/animation/anim_ops.c + * \ingroup edanimation + */ + + #include <stdlib.h> #include <math.h> @@ -37,6 +42,7 @@ #include "DNA_scene_types.h" #include "BKE_context.h" +#include "BKE_global.h" #include "BKE_sound.h" #include "UI_view2d.h" @@ -47,6 +53,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "ED_anim_api.h" #include "ED_screen.h" #include "anim_intern.h" @@ -58,6 +65,9 @@ static int change_frame_poll(bContext *C) { ScrArea *curarea= CTX_wm_area(C); + /* XXX temp? prevent changes during render */ + if(G.rendering) return 0; + /* as long as there is an active area, and it isn't a Graph Editor * (since the Graph Editor has its own version which does extra stuff), * we're fine @@ -97,14 +107,9 @@ static int frame_from_event(bContext *C, wmEvent *event) { ARegion *region= CTX_wm_region(C); float viewx; - int x, y; - - /* convert screen coordinates to region coordinates */ - x= event->x - region->winrct.xmin; - y= event->y - region->winrct.ymin; - + /* convert from region coordinates to View2D 'tot' space */ - UI_view2d_region_to_view(®ion->v2d, x, y, &viewx, NULL); + UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &viewx, NULL); /* round result to nearest int (frames are ints!) */ return (int)floor(viewx+0.5f); @@ -153,7 +158,7 @@ static int change_frame_modal(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -void ANIM_OT_change_frame(wmOperatorType *ot) +static void ANIM_OT_change_frame(wmOperatorType *ot) { /* identifiers */ ot->name= "Change frame"; @@ -194,8 +199,8 @@ static int previewrange_define_exec(bContext *C, wmOperator *op) * - must clamp within allowable limits * - end must not be before start (though this won't occur most of the time) */ - if (sfra < 1) sfra = 1.0f; - if (efra < 1) efra = 1.0f; + FRAMENUMBER_MIN_CLAMP(sfra); + FRAMENUMBER_MIN_CLAMP(efra); if (efra < sfra) efra= sfra; scene->r.flag |= SCER_PRV_RANGE; @@ -208,7 +213,7 @@ static int previewrange_define_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void ANIM_OT_previewrange_set(wmOperatorType *ot) +static void ANIM_OT_previewrange_set(wmOperatorType *ot) { /* identifiers */ ot->name= "Set Preview Range"; @@ -219,6 +224,7 @@ void ANIM_OT_previewrange_set(wmOperatorType *ot) ot->invoke= WM_border_select_invoke; ot->exec= previewrange_define_exec; ot->modal= WM_border_select_modal; + ot->cancel= WM_border_select_cancel; ot->poll= ED_operator_animview_active; @@ -255,7 +261,7 @@ static int previewrange_clear_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -void ANIM_OT_previewrange_clear(wmOperatorType *ot) +static void ANIM_OT_previewrange_clear(wmOperatorType *ot) { /* identifiers */ ot->name= "Clear Preview Range"; @@ -323,7 +329,7 @@ static int toggle_time_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -void ANIM_OT_time_toggle(wmOperatorType *ot) +static void ANIM_OT_time_toggle(wmOperatorType *ot) { /* identifiers */ ot->name= "Toggle Frames/Seconds"; diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 8d74e7b1b59..c9e422baa3e 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -26,6 +26,11 @@ * * ***** END GPL LICENSE BLOCK ***** */ + +/** \file blender/editors/animation/drivers.c + * \ingroup edanimation + */ + #include <stdio.h> #include <string.h> @@ -60,6 +65,11 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "anim_intern.h" + +/* called by WM */ +void free_anim_drivers_copybuf (void); + /* ************************************************** */ /* Animation Data Validation */ @@ -475,7 +485,7 @@ static char *get_driver_path_hack (bContext *C, PointerRNA *ptr, PropertyRNA *pr static int add_driver_button_exec (bContext *C, wmOperator *op) { - PointerRNA ptr= {{0}}; + PointerRNA ptr= {{NULL}}; PropertyRNA *prop= NULL; short success= 0; int index, all= RNA_boolean_get(op->ptr, "all"); @@ -531,7 +541,7 @@ void ANIM_OT_driver_button_add (wmOperatorType *ot) static int remove_driver_button_exec (bContext *C, wmOperator *op) { - PointerRNA ptr= {{0}}; + PointerRNA ptr= {{NULL}}; PropertyRNA *prop= NULL; short success= 0; int index, all= RNA_boolean_get(op->ptr, "all"); @@ -583,7 +593,7 @@ void ANIM_OT_driver_button_remove (wmOperatorType *ot) static int copy_driver_button_exec (bContext *C, wmOperator *op) { - PointerRNA ptr= {{0}}; + PointerRNA ptr= {{NULL}}; PropertyRNA *prop= NULL; short success= 0; int index; @@ -627,7 +637,7 @@ void ANIM_OT_copy_driver_button (wmOperatorType *ot) static int paste_driver_button_exec (bContext *C, wmOperator *op) { - PointerRNA ptr= {{0}}; + PointerRNA ptr= {{NULL}}; PropertyRNA *prop= NULL; short success= 0; int index; diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c index b47fea58633..8197d6b25dd 100644 --- a/source/blender/editors/animation/fmodifier_ui.c +++ b/source/blender/editors/animation/fmodifier_ui.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -26,6 +26,11 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/editors/animation/fmodifier_ui.c + * \ingroup edanimation + */ + + /* User-Interface Stuff for F-Modifiers: * This file defines the (C-Coded) templates + editing callbacks needed * by the interface stuff or F-Modifiers, as used by F-Curves in the Graph Editor, @@ -53,10 +58,12 @@ #include "RNA_access.h" - #include "UI_interface.h" #include "UI_resources.h" +#include "ED_anim_api.h" +#include "ED_util.h" + /* ********************************************** */ /* UI STUFF */ @@ -93,6 +100,8 @@ static void delete_fmodifier_cb (bContext *C, void *fmods_v, void *fcm_v) /* remove the given F-Modifier from the active modifier-stack */ remove_fmodifier(modifiers, fcm); + + ED_undo_push(C, "Delete F-Curve Modifier"); /* send notifiers */ // XXX for now, this is the only way to get updates in all the right places... but would be nice to have a special one in this case @@ -226,14 +235,14 @@ static void draw_modifier__fn_generator(uiLayout *layout, ID *id, FModifier *fcm /* add the settings */ col= uiLayoutColumn(layout, 1); - uiItemR(col, &ptr, "function_type", 0, "", ICON_NULL); - uiItemR(col, &ptr, "use_additive", UI_ITEM_R_TOGGLE, NULL, ICON_NULL); + uiItemR(col, &ptr, "function_type", 0, "", ICON_NONE); + uiItemR(col, &ptr, "use_additive", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); col= uiLayoutColumn(layout, 0); // no grouping for now - uiItemR(col, &ptr, "amplitude", 0, NULL, ICON_NULL); - uiItemR(col, &ptr, "phase_multiplier", 0, NULL, ICON_NULL); - uiItemR(col, &ptr, "phase_offset", 0, NULL, ICON_NULL); - uiItemR(col, &ptr, "value_offset", 0, NULL, ICON_NULL); + uiItemR(col, &ptr, "amplitude", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "phase_multiplier", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "phase_offset", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "value_offset", 0, NULL, ICON_NONE); } /* --------------- */ @@ -254,15 +263,15 @@ static void draw_modifier__cycles(uiLayout *layout, ID *id, FModifier *fcm, shor /* before range */ col= uiLayoutColumn(split, 1); - uiItemL(col, "Before:", ICON_NULL); - uiItemR(col, &ptr, "mode_before", 0, "", ICON_NULL); - uiItemR(col, &ptr, "cycles_before", 0, NULL, ICON_NULL); + uiItemL(col, "Before:", ICON_NONE); + uiItemR(col, &ptr, "mode_before", 0, "", ICON_NONE); + uiItemR(col, &ptr, "cycles_before", 0, NULL, ICON_NONE); /* after range */ col= uiLayoutColumn(split, 1); - uiItemL(col, "After:", ICON_NULL); - uiItemR(col, &ptr, "mode_after", 0, "", ICON_NULL); - uiItemR(col, &ptr, "cycles_after", 0, NULL, ICON_NULL); + uiItemL(col, "After:", ICON_NONE); + uiItemR(col, &ptr, "mode_after", 0, "", ICON_NONE); + uiItemR(col, &ptr, "cycles_after", 0, NULL, ICON_NONE); } /* --------------- */ @@ -277,25 +286,25 @@ static void draw_modifier__noise(uiLayout *layout, ID *id, FModifier *fcm, short RNA_pointer_create(id, &RNA_FModifierNoise, fcm, &ptr); /* blending mode */ - uiItemR(layout, &ptr, "blend_type", 0, NULL, ICON_NULL); + uiItemR(layout, &ptr, "blend_type", 0, NULL, ICON_NONE); /* split into 2 columns */ split= uiLayoutSplit(layout, 0.5f, 0); /* col 1 */ col= uiLayoutColumn(split, 0); - uiItemR(col, &ptr, "scale", 0, NULL, ICON_NULL); - uiItemR(col, &ptr, "strength", 0, NULL, ICON_NULL); + uiItemR(col, &ptr, "scale", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "strength", 0, NULL, ICON_NONE); /* col 2 */ col= uiLayoutColumn(split, 0); - uiItemR(col, &ptr, "phase", 0, NULL, ICON_NULL); - uiItemR(col, &ptr, "depth", 0, NULL, ICON_NULL); + uiItemR(col, &ptr, "phase", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "depth", 0, NULL, ICON_NONE); } /* --------------- */ -#define BINARYSEARCH_FRAMEEQ_THRESH 0.0001 +#define BINARYSEARCH_FRAMEEQ_THRESH 0.0001f /* Binary search algorithm for finding where to insert Envelope Data Point. * Returns the index to insert at (data already at that index will be offset if replace is 0) @@ -437,9 +446,9 @@ static void fmod_envelope_deletepoint_cb (bContext *UNUSED(C), void *fcm_dv, voi if (env->totvert > 1) { /* allocate a new smaller array */ fedn= MEM_callocN(sizeof(FCM_EnvelopeData)*(env->totvert-1), "FCM_EnvelopeData"); - - memcpy(fedn, &env->data, sizeof(FCM_EnvelopeData)*(index)); - memcpy(&fedn[index], &env->data[index+1], sizeof(FCM_EnvelopeData)*(env->totvert-index-1)); + + memcpy(fedn, env->data, sizeof(FCM_EnvelopeData)*(index)); + memcpy(fedn + index, env->data + (index + 1), sizeof(FCM_EnvelopeData)*((env->totvert - index)-1)); /* free old array, and set the new */ MEM_freeN(env->data); @@ -448,8 +457,10 @@ static void fmod_envelope_deletepoint_cb (bContext *UNUSED(C), void *fcm_dv, voi } else { /* just free array, since the only vert was deleted */ - if (env->data) + if (env->data) { MEM_freeN(env->data); + env->data= NULL; + } env->totvert= 0; } } @@ -470,12 +481,12 @@ static void draw_modifier__envelope(uiLayout *layout, ID *id, FModifier *fcm, sh /* general settings */ col= uiLayoutColumn(layout, 1); - uiItemL(col, "Envelope:", ICON_NULL); - uiItemR(col, &ptr, "reference_value", 0, NULL, ICON_NULL); + uiItemL(col, "Envelope:", ICON_NONE); + uiItemR(col, &ptr, "reference_value", 0, NULL, ICON_NONE); row= uiLayoutRow(col, 1); - uiItemR(row, &ptr, "default_min", 0, "Min", ICON_NULL); - uiItemR(row, &ptr, "default_max", 0, "Max", ICON_NULL); + uiItemR(row, &ptr, "default_min", 0, "Min", ICON_NONE); + uiItemR(row, &ptr, "default_max", 0, "Max", ICON_NONE); /* control points header */ // TODO: move this control-point control stuff to using the new special widgets for lists @@ -527,13 +538,13 @@ static void draw_modifier__limits(uiLayout *layout, ID *id, FModifier *fcm, shor /* x-minimum */ col= uiLayoutColumn(split, 1); - uiItemR(col, &ptr, "use_min_x", 0, NULL, ICON_NULL); - uiItemR(col, &ptr, "min_x", 0, NULL, ICON_NULL); + uiItemR(col, &ptr, "use_min_x", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "min_x", 0, NULL, ICON_NONE); /* y-minimum*/ col= uiLayoutColumn(split, 1); - uiItemR(col, &ptr, "use_min_y", 0, NULL, ICON_NULL); - uiItemR(col, &ptr, "min_y", 0, NULL, ICON_NULL); + uiItemR(col, &ptr, "use_min_y", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "min_y", 0, NULL, ICON_NONE); } /* row 2: maximum */ @@ -545,13 +556,13 @@ static void draw_modifier__limits(uiLayout *layout, ID *id, FModifier *fcm, shor /* x-minimum */ col= uiLayoutColumn(split, 1); - uiItemR(col, &ptr, "use_max_x", 0, NULL, ICON_NULL); - uiItemR(col, &ptr, "max_x", 0, NULL, ICON_NULL); + uiItemR(col, &ptr, "use_max_x", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "max_x", 0, NULL, ICON_NONE); /* y-minimum*/ col= uiLayoutColumn(split, 1); - uiItemR(col, &ptr, "use_max_y", 0, NULL, ICON_NULL); - uiItemR(col, &ptr, "max_y", 0, NULL, ICON_NULL); + uiItemR(col, &ptr, "use_max_y", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "max_y", 0, NULL, ICON_NONE); } } @@ -568,24 +579,24 @@ static void draw_modifier__stepped(uiLayout *layout, ID *id, FModifier *fcm, sho /* block 1: "stepping" settings */ col= uiLayoutColumn(layout, 0); - uiItemR(col, &ptr, "frame_step", 0, NULL, ICON_NULL); - uiItemR(col, &ptr, "frame_offset", 0, NULL, ICON_NULL); + uiItemR(col, &ptr, "frame_step", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "frame_offset", 0, NULL, ICON_NONE); /* block 2: start range settings */ col= uiLayoutColumn(layout, 1); - uiItemR(col, &ptr, "use_frame_start", 0, NULL, ICON_NULL); + uiItemR(col, &ptr, "use_frame_start", 0, NULL, ICON_NONE); subcol = uiLayoutColumn(col, 1); uiLayoutSetActive(subcol, RNA_boolean_get(&ptr, "use_frame_start")); - uiItemR(subcol, &ptr, "frame_start", 0, NULL, ICON_NULL); + uiItemR(subcol, &ptr, "frame_start", 0, NULL, ICON_NONE); /* block 3: end range settings */ col= uiLayoutColumn(layout, 1); - uiItemR(col, &ptr, "use_frame_end", 0, NULL, ICON_NULL); + uiItemR(col, &ptr, "use_frame_end", 0, NULL, ICON_NONE); subcol = uiLayoutColumn(col, 1); uiLayoutSetActive(subcol, RNA_boolean_get(&ptr, "use_frame_end")); - uiItemR(subcol, &ptr, "frame_end", 0, NULL, ICON_NULL); + uiItemR(subcol, &ptr, "frame_end", 0, NULL, ICON_NONE); } /* --------------- */ @@ -593,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; @@ -611,30 +622,30 @@ 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); /* expand */ - uiItemR(subrow, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NULL); + uiItemR(subrow, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); /* checkbox for 'active' status (for now) */ - uiItemR(subrow, &ptr, "active", UI_ITEM_R_ICON_ONLY, "", ICON_NULL); + uiItemR(subrow, &ptr, "active", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); /* name */ if (fmi) - uiItemL(subrow, fmi->name, ICON_NULL); + uiItemL(subrow, fmi->name, ICON_NONE); else - uiItemL(subrow, "<Unknown Modifier>", ICON_NULL); + uiItemL(subrow, "<Unknown Modifier>", ICON_NONE); /* right-align ------------------------------------------- */ - subrow= uiLayoutRow(row, 0); + subrow= uiLayoutRow(row, 1); uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_RIGHT); /* 'mute' button */ - uiItemR(subrow, &ptr, "mute", UI_ITEM_R_ICON_ONLY, "", ICON_NULL); + uiItemR(subrow, &ptr, "mute", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); uiBlockSetEmboss(block, UI_EMBOSSN); @@ -683,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 c1958064431..b774bc947e4 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -27,6 +27,11 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/editors/animation/keyframes_draw.c + * \ingroup edanimation + */ + + /* System includes ----------------------------------------------------- */ #include <math.h> @@ -75,7 +80,7 @@ /* ActKeyColumns (Keyframe Columns) ------------------------------------------ */ /* Comparator callback used for ActKeyColumns and cframe float-value pointer */ -// NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes +/* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */ short compare_ak_cfraPtr (void *node, void *data) { ActKeyColumn *ak= (ActKeyColumn *)node; @@ -306,6 +311,23 @@ static BezTriple *abk_get_bezt_with_value (ActBeztColumn *abk, float value) /* ActKeyBlocks (Long Keyframes) ------------------------------------------ */ +/* Comparator callback used for ActKeyBlock and cframe float-value pointer */ +/* NOTE: this is exported to other modules that use the ActKeyBlocks for finding long-keyframes */ +short compare_ab_cfraPtr (void *node, void *data) +{ + ActKeyBlock *ab= (ActKeyBlock *)node; + float *cframe= data; + + if (*cframe < ab->start) + return -1; + else if (*cframe > ab->start) + return 1; + else + return 0; +} + +/* --------------- */ + /* Create a ActKeyColumn for a pair of BezTriples */ static ActKeyBlock *bezts_to_new_actkeyblock(BezTriple *prev, BezTriple *beztn) { @@ -338,9 +360,9 @@ static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, DLRBT_Tree *beztTree, * -> secondly, handles which control that section of the curve must be constant */ if ((!prev) || (!beztn)) return; - if (IS_EQ(beztn->vec[1][1], prev->vec[1][1])==0) return; - if (IS_EQ(beztn->vec[1][1], beztn->vec[0][1])==0) return; - if (IS_EQ(prev->vec[1][1], prev->vec[2][1])==0) return; + if (IS_EQF(beztn->vec[1][1], prev->vec[1][1])==0) return; + if (IS_EQF(beztn->vec[1][1], beztn->vec[0][1])==0) return; + if (IS_EQF(prev->vec[1][1], prev->vec[2][1])==0) return; /* if there are no blocks already, just add as root */ @@ -350,7 +372,7 @@ static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, DLRBT_Tree *beztTree, blocks->root= (DLRBT_Node *)new_ab; } else { - ActKeyBlock *ab, *abp=NULL, *abn=NULL; + ActKeyBlock *ab, *abn=NULL; /* try to find a keyblock that starts on the previous beztriple, and add a new one if none start there * Note: we can't search from end to try to optimise this as it causes errors there's @@ -360,7 +382,7 @@ static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, DLRBT_Tree *beztTree, // A|--------------|A ______________ B|--------------|B // A|------------------------------------------------|A // A|----|A|---|A|-----------------------------------|A - for (ab= blocks->root; ab; abp= ab, ab= abn) { + for (ab= blocks->root; ab; ab= abn) { /* check if this is a match, or whether we go left or right */ if (ab->start == prev->vec[1][0]) { /* set selection status and 'touched' status */ @@ -435,6 +457,33 @@ static void set_touched_actkeyblock (ActKeyBlock *ab) set_touched_actkeyblock(ab->right); } +/* --------- */ + +/* Checks if ActKeyBlock should exist... */ +short actkeyblock_is_valid (ActKeyBlock *ab, DLRBT_Tree *keys) +{ + ActKeyColumn *ak; + short startCurves, endCurves, totCurves; + + /* check that block is valid */ + if (ab == NULL) + return 0; + + /* find out how many curves occur at each keyframe */ + ak= (ActKeyColumn *)BLI_dlrbTree_search_exact(keys, compare_ak_cfraPtr, &ab->start); + startCurves = (ak)? ak->totcurve: 0; + + ak= (ActKeyColumn *)BLI_dlrbTree_search_exact(keys, compare_ak_cfraPtr, &ab->end); + endCurves = (ak)? ak->totcurve: 0; + + /* only draw keyblock if it appears in at all of the keyframes at lowest end */ + if (!startCurves && !endCurves) + return 0; + + totCurves = (startCurves>endCurves)? endCurves: startCurves; + return (ab->totcurve >= totCurves); +} + /* *************************** Keyframe Drawing *************************** */ /* coordinates for diamond shape */ @@ -554,22 +603,7 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa /* draw keyblocks */ if (blocks) { for (ab= blocks->first; ab; ab= ab->next) { - short startCurves, endCurves, totCurves; - - /* find out how many curves occur at each keyframe */ - ak= (ActKeyColumn *)BLI_dlrbTree_search_exact(keys, compare_ak_cfraPtr, &ab->start); - startCurves = (ak)? ak->totcurve: 0; - - ak= (ActKeyColumn *)BLI_dlrbTree_search_exact(keys, compare_ak_cfraPtr, &ab->end); - endCurves = (ak)? ak->totcurve: 0; - - /* only draw keyblock if it appears in at all of the keyframes at lowest end */ - if (!startCurves && !endCurves) - continue; - else - totCurves = (startCurves>endCurves)? endCurves: startCurves; - - if (ab->totcurve >= totCurves) { + if (actkeyblock_is_valid(ab, keys)) { /* draw block */ if (ab->sel) UI_ThemeColor4(TH_STRIP_SELECT); @@ -739,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 */ @@ -752,158 +786,79 @@ 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) { DLRBT_Tree *beztTree = NULL; BezTriple *bezt; - int v; - + unsigned int v; + if (fcu && fcu->totvert && fcu->bezt) { /* apply NLA-mapping (if applicable) */ if (adt) diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index e9a2c1bdc06..9f3d40a5709 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -24,6 +24,11 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/editors/animation/keyframes_edit.c + * \ingroup edanimation + */ + + #include <stdlib.h> #include <string.h> #include <math.h> @@ -90,7 +95,7 @@ short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEdi { BezTriple *bezt; short ok = 0; - int i; + unsigned int i; /* sanity check */ if (ELEM(NULL, fcu, fcu->bezt)) @@ -192,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; @@ -392,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 */ @@ -411,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) @@ -432,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) @@ -464,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; @@ -486,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 */ @@ -510,7 +414,7 @@ void ANIM_editkeyframes_refresh(bAnimContext *ac) /* run the given check on the 3 handles * - check should be a macro, which takes the handle index as its single arg, which it substitutes later - * - requires that a var, of type short, is named 'ok', and has been initialised ot 0 + * - requires that a var, of type short, is named 'ok', and has been initialized to 0 */ #define KEYFRAME_OK_CHECKS(check) \ { \ @@ -532,7 +436,7 @@ static short ok_bezier_frame(KeyframeEditData *ked, BezTriple *bezt) short ok = 0; /* frame is stored in f1 property (this float accuracy check may need to be dropped?) */ - #define KEY_CHECK_OK(_index) IS_EQ(bezt->vec[_index][0], ked->f1) + #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][0], ked->f1) KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK @@ -572,7 +476,7 @@ static short ok_bezier_value(KeyframeEditData *ked, BezTriple *bezt) * - this float accuracy check may need to be dropped? * - should value be stored in f2 instead so that we won't have conflicts when using f1 for frames too? */ - #define KEY_CHECK_OK(_index) IS_EQ(bezt->vec[_index][1], ked->f1) + #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][1], ked->f1) KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK @@ -692,7 +596,7 @@ void bezt_remap_times(KeyframeEditData *ked, BezTriple *bezt) static short snap_bezier_nearest(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { if (bezt->f2 & SELECT) - bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]+0.5)); + bezt->vec[1][0]= (float)(floorf(bezt->vec[1][0]+0.5f)); return 0; } diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index 92fce2a77e5..e2afda04d30 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -25,6 +25,11 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/editors/animation/keyframes_general.c + * \ingroup edanimation + */ + + #include <stdlib.h> #include <string.h> #include <math.h> @@ -48,6 +53,7 @@ #include "BKE_global.h" #include "RNA_access.h" +#include "RNA_enum_types.h" #include "ED_anim_api.h" #include "ED_keyframing.h" @@ -105,9 +111,9 @@ 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 */ for (i=0; i < fcu->totvert; i++) { if (fcu->bezt[i].f2 & SELECT) { @@ -118,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); } @@ -273,28 +279,21 @@ void clean_fcurve(FCurve *fcu, float thresh) /* temp struct used for smooth_fcurve */ typedef struct tSmooth_Bezt { float *h1, *h2, *h3; /* bezt->vec[0,1,2][1] */ + float y1, y2, y3; /* averaged before/new/after y-values */ } tSmooth_Bezt; /* Use a weighted moving-means method to reduce intensity of fluctuations */ +// TODO: introduce scaling factor for weighting falloff void smooth_fcurve (FCurve *fcu) { BezTriple *bezt; int i, x, totSel = 0; - /* first loop through - count how many verts are selected, and fix up handles - * this is done for both modes - */ + /* first loop through - count how many verts are selected */ bezt= fcu->bezt; for (i=0; i < fcu->totvert; i++, bezt++) { - if (BEZSELECTED(bezt)) { - /* line point's handles up with point's vertical position */ - bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1]; - if ((bezt->h1==HD_AUTO) || (bezt->h1==HD_VECT)) bezt->h1= HD_ALIGN; - if ((bezt->h2==HD_AUTO) || (bezt->h2==HD_VECT)) bezt->h2= HD_ALIGN; - - /* add value to total */ + if (BEZSELECTED(bezt)) totSel++; - } } /* if any points were selected, allocate tSmooth_Bezt points to work on */ @@ -314,7 +313,7 @@ void smooth_fcurve (FCurve *fcu) tsb->h3 = &bezt->vec[2][1]; /* advance to the next tsb to populate */ - if (x < totSel- 1) + if (x < totSel-1) tsb++; else break; @@ -322,16 +321,16 @@ void smooth_fcurve (FCurve *fcu) } /* calculate the new smoothed F-Curve's with weighted averages: - * - this is done with two passes + * - this is done with two passes to avoid progressive corruption errors * - uses 5 points for each operation (which stores in the relevant handles) * - previous: w/a ratio = 3:5:2:1:1 * - next: w/a ratio = 1:1:2:5:3 */ - /* round 1: calculate previous and next */ + /* round 1: calculate smoothing deltas and new values */ tsb= tarray; for (i=0; i < totSel; i++, tsb++) { - /* don't touch end points (otherwise, curves slowly explode) */ + /* don't touch end points (otherwise, curves slowly explode, as we don't have enough data there) */ if (ELEM(i, 0, (totSel-1)) == 0) { const tSmooth_Bezt *tP1 = tsb - 1; const tSmooth_Bezt *tP2 = (i-2 > 0) ? (tsb - 2) : (NULL); @@ -344,21 +343,26 @@ void smooth_fcurve (FCurve *fcu) const float n1 = *tN1->h2; const float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2); - /* calculate previous and next */ - *tsb->h1= (3*p2 + 5*p1 + 2*c1 + n1 + n2) / 12; - *tsb->h3= (p2 + p1 + 2*c1 + 5*n1 + 3*n2) / 12; + /* calculate previous and next, then new position by averaging these */ + tsb->y1= (3*p2 + 5*p1 + 2*c1 + n1 + n2) / 12; + tsb->y3= (p2 + p1 + 2*c1 + 5*n1 + 3*n2) / 12; + + tsb->y2 = (tsb->y1 + tsb->y3) / 2; } } - /* round 2: calculate new values and reset handles */ + /* round 2: apply new values */ tsb= tarray; for (i=0; i < totSel; i++, tsb++) { - /* calculate new position by averaging handles */ - *tsb->h2 = (*tsb->h1 + *tsb->h3) / 2; - - /* reset handles now */ - *tsb->h1 = *tsb->h2; - *tsb->h3 = *tsb->h2; + /* don't touch end points, as their values were't touched above */ + if (ELEM(i, 0, (totSel-1)) == 0) { + /* y2 takes the average of the 2 points */ + *tsb->h2 = tsb->y2; + + /* handles are weighted between their original values and the averaged values */ + *tsb->h1 = ((*tsb->h1) * 0.7f) + (tsb->y1 * 0.3f); + *tsb->h3 = ((*tsb->h3) * 0.7f) + (tsb->y3 * 0.3f); + } } /* free memory required for tarray */ @@ -452,7 +456,7 @@ void sample_fcurve (FCurve *fcu) */ /* globals for copy/paste data (like for other copy/paste buffers) */ -ListBase animcopybuf = {NULL, NULL}; +static ListBase animcopybuf = {NULL, NULL}; static float animcopy_firstframe= 999999999.0f; static float animcopy_lastframe= -999999999.0f; static float animcopy_cfra= 0.0; diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 8dc813d940b..109da669ce6 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -26,6 +26,11 @@ * * ***** END GPL LICENSE BLOCK ***** */ + +/** \file blender/editors/animation/keyframing.c + * \ingroup edanimation + */ + #include <stdio.h> #include <stddef.h> @@ -50,6 +55,7 @@ #include "BKE_animsys.h" #include "BKE_action.h" +#include "BKE_armature.h" #include "BKE_constraint.h" #include "BKE_depsgraph.h" #include "BKE_fcurve.h" @@ -294,6 +300,7 @@ int insert_bezt_fcurve (FCurve *fcu, BezTriple *bezt, short flag) int insert_vert_fcurve (FCurve *fcu, float x, float y, short flag) { BezTriple beztr= {{{0}}}; + unsigned int oldTot = fcu->totvert; int a; /* set all three points, for nicer start position @@ -329,10 +336,16 @@ int insert_vert_fcurve (FCurve *fcu, float x, float y, short flag) if ((fcu->totvert > 2) && (flag & INSERTKEY_REPLACE)==0) { BezTriple *bezt= (fcu->bezt + a); - /* set interpolation from previous (if available) */ - // FIXME: this doesn't work if user tweaked the interpolation specifically, and they were just overwriting some existing key in the process... - if (a > 0) bezt->ipo= (bezt-1)->ipo; - else if (a < fcu->totvert-1) bezt->ipo= (bezt+1)->ipo; + /* set interpolation from previous (if available), but only if we didn't just replace some keyframe + * - replacement is indicated by no-change in number of verts + * - when replacing, the user may have specified some interpolation that should be kept + */ + if (fcu->totvert > oldTot) { + if (a > 0) + bezt->ipo= (bezt-1)->ipo; + else if (a < fcu->totvert-1) + bezt->ipo= (bezt+1)->ipo; + } /* don't recalculate handles if fast is set * - this is a hack to make importers faster @@ -353,7 +366,7 @@ enum { KEYNEEDED_JUSTADD, KEYNEEDED_DELPREV, KEYNEEDED_DELNEXT -} eKeyNeededStatus; +} /*eKeyNeededStatus*/; /* This helper function determines whether a new keyframe is needed */ /* Cases where keyframes should not be added: @@ -390,14 +403,14 @@ static short new_key_needed (FCurve *fcu, float cFrame, float nValue) prevVal= prev->vec[1][1]; /* keyframe to be added at point where there are already two similar points? */ - if (IS_EQ(prevPosi, cFrame) && IS_EQ(beztPosi, cFrame) && IS_EQ(beztPosi, prevPosi)) { + if (IS_EQF(prevPosi, cFrame) && IS_EQF(beztPosi, cFrame) && IS_EQF(beztPosi, prevPosi)) { return KEYNEEDED_DONTADD; } /* keyframe between prev+current points ? */ if ((prevPosi <= cFrame) && (cFrame <= beztPosi)) { /* is the value of keyframe to be added the same as keyframes on either side ? */ - if (IS_EQ(prevVal, nValue) && IS_EQ(beztVal, nValue) && IS_EQ(prevVal, beztVal)) { + if (IS_EQF(prevVal, nValue) && IS_EQF(beztVal, nValue) && IS_EQF(prevVal, beztVal)) { return KEYNEEDED_DONTADD; } else { @@ -407,7 +420,7 @@ static short new_key_needed (FCurve *fcu, float cFrame, float nValue) realVal= evaluate_fcurve(fcu, cFrame); /* compare whether it's the same as proposed */ - if (IS_EQ(realVal, nValue)) + if (IS_EQF(realVal, nValue)) return KEYNEEDED_DONTADD; else return KEYNEEDED_JUSTADD; @@ -420,7 +433,7 @@ static short new_key_needed (FCurve *fcu, float cFrame, float nValue) * stays around or not depends on whether the values of previous/current * beztriples and new keyframe are the same. */ - if (IS_EQ(prevVal, nValue) && IS_EQ(beztVal, nValue) && IS_EQ(prevVal, beztVal)) + if (IS_EQF(prevVal, nValue) && IS_EQF(beztVal, nValue) && IS_EQF(prevVal, beztVal)) return KEYNEEDED_DELNEXT; else return KEYNEEDED_JUSTADD; @@ -458,7 +471,7 @@ static short new_key_needed (FCurve *fcu, float cFrame, float nValue) else valB= bezt->vec[1][1] + 1.0f; - if (IS_EQ(valA, nValue) && IS_EQ(valA, valB)) + if (IS_EQF(valA, nValue) && IS_EQF(valA, valB)) return KEYNEEDED_DELPREV; else return KEYNEEDED_JUSTADD; @@ -648,41 +661,72 @@ static float visualkey_get_value (PointerRNA *ptr, PropertyRNA *prop, int array_ mat4_to_eulO(eul, ob->rotmode, ob->obmat); return eul[array_index]; } + else if (strstr(identifier, "rotation_quaternion")) { + float trimat[3][3], quat[4]; + + copy_m3_m4(trimat, ob->obmat); + mat3_to_quat_is_ok(quat, trimat); + + return quat[array_index]; + } + else if (strstr(identifier, "rotation_axis_angle")) { + float axis[3], angle; + + mat4_to_axis_angle(axis, &angle, ob->obmat); + + /* w = 0, x,y,z = 1,2,3 */ + if (array_index == 0) + return angle; + else + return axis[array_index - 1]; + } } } else if (ptr->type == &RNA_PoseBone) { - Object *ob= (Object *)ptr->id.data; /* we assume that this is always set, and is an object */ + Object *ob = (Object *)ptr->id.data; /* we assume that this is always set, and is an object */ bPoseChannel *pchan= (bPoseChannel *)ptr->data; - bPoseChannel tchan; + float tmat[4][4]; - /* make a copy of pchan so that we can apply and decompose its chan_mat, thus getting the - * rest-pose to pose-mode transform that got stored there at the end of posing calculations - * for B-Bone deforms to use - * - it should be safe to just make a local copy like this, since we're not doing anything with the copied pointers + /* Although it is not strictly required for this particular space conversion, + * arg1 must not be null, as there is a null check for the other conversions to + * be safe. Therefore, the active object is passed here, and in many cases, this + * will be what owns the pose-channel that is getting this anyway. */ - memcpy(&tchan, pchan, sizeof(bPoseChannel)); - pchan_apply_mat4(&tchan, pchan->chan_mat); + copy_m4_m4(tmat, pchan->pose_mat); + constraint_mat_convertspace(ob, pchan, tmat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); /* Loc, Rot/Quat keyframes are supported... */ if (strstr(identifier, "location")) { /* only use for non-connected bones */ if ((pchan->bone->parent) && !(pchan->bone->flag & BONE_CONNECTED)) - return tchan.loc[array_index]; + return tmat[3][array_index]; else if (pchan->bone->parent == NULL) - return tchan.loc[array_index]; + return tmat[3][array_index]; } else if (strstr(identifier, "rotation_euler")) { - return tchan.eul[array_index]; + float eul[3]; + + mat4_to_eulO(eul, pchan->rotmode, tmat); + return eul[array_index]; } else if (strstr(identifier, "rotation_quaternion")) { - return tchan.quat[array_index]; + float trimat[3][3], quat[4]; + + copy_m3_m4(trimat, tmat); + mat3_to_quat_is_ok(quat, trimat); + + return quat[array_index]; } - else if (strstr(identifier, "rotation_axisangle")) { + else if (strstr(identifier, "rotation_axis_angle")) { + float axis[3], angle; + + mat4_to_axis_angle(axis, &angle, tmat); + /* w = 0, x,y,z = 1,2,3 */ if (array_index == 0) - return tchan.rotAngle; + return angle; else - return tchan.rotAxis[array_index - 1]; + return axis[array_index - 1]; } } @@ -903,7 +947,7 @@ short insert_keyframe (ReportList *reports, ID *id, bAction *act, const char gro /* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor, * is determined by the array index for the F-Curve */ - if (ELEM4(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR)) { + if (ELEM5(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { fcu->color_mode= FCURVE_COLOR_AUTO_RGB; } } @@ -1036,7 +1080,7 @@ short delete_keyframe (ReportList *reports, ID *id, bAction *act, const char gro enum { COMMONKEY_MODE_INSERT = 0, COMMONKEY_MODE_DELETE, -} eCommonModifyKey_Modes; +} /*eCommonModifyKey_Modes*/; /* Polling callback for use with ANIM_*_keyframe() operators * This is based on the standard ED_operator_areaactive callback, @@ -1274,7 +1318,7 @@ void ANIM_OT_keyframe_delete (wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name= "Delete Keyframe"; + ot->name= "Delete Keying-Set Keyframe"; ot->idname= "ANIM_OT_keyframe_delete"; ot->description= "Delete keyframes on the current frame for all properties in the specified Keying Set"; @@ -1319,7 +1363,7 @@ static int delete_key_v3d_exec (bContext *C, wmOperator *op) short success= 0; /* loop through all curves in animdata and delete keys on this frame */ - if (ob->adt) { + if ((ob->adt) && (ob->adt->action)) { AnimData *adt= ob->adt; bAction *act= adt->action; @@ -1329,7 +1373,7 @@ static int delete_key_v3d_exec (bContext *C, wmOperator *op) } } - BKE_reportf(op->reports, RPT_INFO, "Ob '%s' - Successfully removed %d keyframes \n", id->name+2, success); + BKE_reportf(op->reports, RPT_INFO, "Ob '%s' - Successfully had %d keyframes removed", id->name+2, success); ob->recalc |= OB_RECALC_OB; } @@ -1347,6 +1391,7 @@ void ANIM_OT_keyframe_delete_v3d (wmOperatorType *ot) { /* identifiers */ ot->name= "Delete Keyframe"; + ot->description= "Remove keyframes on current frame for selected object"; ot->idname= "ANIM_OT_keyframe_delete_v3d"; /* callbacks */ @@ -1366,7 +1411,7 @@ static int insert_key_button_exec (bContext *C, wmOperator *op) { Main *bmain= CTX_data_main(C); Scene *scene= CTX_data_scene(C); - PointerRNA ptr= {{0}}; + PointerRNA ptr= {{NULL}}; PropertyRNA *prop= NULL; char *path; float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap @@ -1455,7 +1500,7 @@ static int delete_key_button_exec (bContext *C, wmOperator *op) { Main *bmain= CTX_data_main(C); Scene *scene= CTX_data_scene(C); - PointerRNA ptr= {{0}}; + PointerRNA ptr= {{NULL}}; PropertyRNA *prop= NULL; char *path; float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap @@ -1577,7 +1622,7 @@ short fcurve_frame_has_keyframe (FCurve *fcu, float frame, short filter) /* Checks whether an Action has a keyframe for a given frame * Since we're only concerned whether a keyframe exists, we can simply loop until a match is found... */ -short action_frame_has_keyframe (bAction *act, float frame, short filter) +static short action_frame_has_keyframe (bAction *act, float frame, short filter) { FCurve *fcu; @@ -1605,7 +1650,7 @@ short action_frame_has_keyframe (bAction *act, float frame, short filter) } /* Checks whether an Object has a keyframe for a given frame */ -short object_frame_has_keyframe (Object *ob, float frame, short filter) +static short object_frame_has_keyframe (Object *ob, float frame, short filter) { /* error checking */ if (ob == NULL) diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index 2df7d21e907..69e7c4eb73a 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -1,4 +1,4 @@ -/** +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -26,6 +26,11 @@ * * ***** END GPL LICENSE BLOCK ***** */ + +/** \file blender/editors/animation/keyingsets.c + * \ingroup edanimation + */ + #include <stdio.h> #include <stddef.h> @@ -54,6 +59,7 @@ #include "ED_screen.h" #include "UI_interface.h" +#include "UI_resources.h" #include "WM_api.h" #include "WM_types.h" @@ -218,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; } @@ -288,7 +295,7 @@ static int add_keyingset_button_exec (bContext *C, wmOperator *op) Scene *scene= CTX_data_scene(C); KeyingSet *ks = NULL; PropertyRNA *prop= NULL; - PointerRNA ptr= {{0}}; + PointerRNA ptr= {{NULL}}; char *path = NULL; short success= 0; int index=0, pflag=0; @@ -388,7 +395,7 @@ static int remove_keyingset_button_exec (bContext *C, wmOperator *op) Scene *scene= CTX_data_scene(C); KeyingSet *ks = NULL; PropertyRNA *prop= NULL; - PointerRNA ptr= {{0}}; + PointerRNA ptr= {{NULL}}; char *path = NULL; short success= 0; int index=0; @@ -509,7 +516,7 @@ void ANIM_OT_keying_set_active_set (wmOperatorType *ot) /* REGISTERED KEYING SETS */ /* Keying Set Type Info declarations */ -ListBase keyingset_type_infos = {NULL, NULL}; +static ListBase keyingset_type_infos = {NULL, NULL}; /* Built-In Keying Sets (referencing type infos)*/ ListBase builtin_keyingsets = {NULL, NULL}; @@ -572,9 +579,8 @@ void ANIM_keyingset_info_register (KeyingSetInfo *ksi) } /* Remove the given KeyingSetInfo from the list of type infos, and also remove the builtin set if appropriate */ -void ANIM_keyingset_info_unregister (const bContext *C, KeyingSetInfo *ksi) +void ANIM_keyingset_info_unregister (Main *bmain, KeyingSetInfo *ksi) { - Main *bmain= CTX_data_main(C); KeyingSet *ks, *ksn; /* find relevant builtin KeyingSets which use this, and remove them */ @@ -691,7 +697,7 @@ KeyingSet *ANIM_get_keyingset_for_autokeying(Scene *scene, const char *tranformK /* Menu of All Keying Sets ----------------------------- */ /* Dynamically populate an enum of Keying Sets */ -EnumPropertyItem *ANIM_keying_sets_enum_itemf (bContext *C, PointerRNA *UNUSED(ptr), int *free) +EnumPropertyItem *ANIM_keying_sets_enum_itemf (bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) { Scene *scene = CTX_data_scene(C); KeyingSet *ks; @@ -760,14 +766,14 @@ void ANIM_keying_sets_menu_setup (bContext *C, const char title[], const char op uiLayout *layout; int i = 0; - pup= uiPupMenuBegin(C, title, ICON_NULL); + pup= uiPupMenuBegin(C, title, ICON_NONE); layout= uiPupMenuLayout(pup); /* active Keying Set * - only include entry if it exists */ if (scene->active_keyingset) { - uiItemIntO(layout, "Active Keying Set", ICON_NULL, op_name, "type", i++); + uiItemIntO(layout, "Active Keying Set", ICON_NONE, op_name, "type", i++); uiItemS(layout); } else @@ -777,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_NULL, 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)) - uiItemIntO(layout, ks->name, ICON_NULL, op_name, "type", i--); + uiItemEnumO_value(layout, ks->name, ICON_NONE, op_name, "type", i); } uiPupMenuEnd(C, pup); @@ -937,6 +943,14 @@ int ANIM_apply_keyingset (bContext *C, ListBase *dsources, bAction *act, KeyingS int arraylen, i; short kflag2; + /* skip path if no ID pointer is specified */ + if (ksp->id == NULL) { + BKE_reportf(reports, RPT_WARNING, + "Skipping path in Keying Set, as it has no ID (KS = '%s', Path = '%s'[%d])", + ks->name, ksp->rna_path, ksp->array_index); + continue; + } + /* since keying settings can be defined on the paths too, extend the path before using it */ kflag2 = (kflag | ksp->keyingflag); @@ -980,20 +994,18 @@ int ANIM_apply_keyingset (bContext *C, ListBase *dsources, bAction *act, KeyingS } /* set recalc-flags */ - if (ksp->id) { - switch (GS(ksp->id->name)) { - case ID_OB: /* Object (or Object-Related) Keyframes */ - { - Object *ob= (Object *)ksp->id; - - ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME; // XXX: only object transforms only? - } - break; + switch (GS(ksp->id->name)) { + case ID_OB: /* Object (or Object-Related) Keyframes */ + { + Object *ob= (Object *)ksp->id; + + ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME; // XXX: only object transforms only? } - - /* send notifiers for updates (this doesn't require context to work!) */ - WM_main_add_notifier(NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); + break; } + + /* send notifiers for updates (this doesn't require context to work!) */ + WM_main_add_notifier(NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); } /* return the number of channels successfully affected */ |